From 198139075386338b28007c75225f26b86f48f327 Mon Sep 17 00:00:00 2001
From: Tristan Partin <tristan@partin.io>
Date: Thu, 30 Jul 2026 08:33:28 +0000
Subject: [PATCH v2 3/3] Fix strto* usage in ecpg

strto*() can set two different values for errno: EINVAL and ERANGE.
Quoting the man page for EINVAL:

> The value of base is not supported or no conversion could be performed
> (the last feature is not portable across all platforms).

Emphasis on the portion in parentheses.

Take the following example:

    strtoul("", &endptr, 10);

On glibc, the output value is 0, errno *is not* set, and endptr points
to the empty string.

On Apple libc, the output value is 0, errno *is* set to EINVAL, and
endptr points to the empty string.

Because of this discrepancy, ECPG was silently converting empty strings
to 0 on glibc, while Apple libc was correctly rejecting them as invalid
integers.

# ------------------------ >8 ------------------------ Do not modify or
# remove the line above. Everything below it will be ignored.
#
# On branch strtoul Changes to be committed: modified:
# src/interfaces/ecpg/ecpglib/data.c modified:
# src/interfaces/ecpg/pgtypeslib/dt_common.c modified:
# src/interfaces/ecpg/test/expected/sql-indicators.c modified:
# src/interfaces/ecpg/test/expected/sql-indicators.stderr modified:
# src/interfaces/ecpg/test/expected/sql-indicators.stdout modified:
# src/interfaces/ecpg/test/sql/indicators.pgc
#
# Changes not staged for commit: modified:
# src/bin/pg_verifybackup/pg_verifybackup.c
#
diff --git c/src/interfaces/ecpg/ecpglib/data.c
i/src/interfaces/ecpg/ecpglib/data.c index d5d40f7b654..932cb568a2d
100644 --- c/src/interfaces/ecpg/ecpglib/data.c +++
i/src/interfaces/ecpg/ecpglib/data.c @@ -373,7 +373,7 @@
ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int
lineno, case ECPGt_int: case ECPGt_long: res = strtol(pval,
&scan_length, 10);
-					if (garbage_left(isarray, &scan_length, compat))
+					if (scan_length == pval || garbage_left(isarray,
&scan_length, compat)) { ecpg_raise(lineno, ECPG_INT_FORMAT,
ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); @@ -402,7 +402,7 @@
ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int
lineno, case ECPGt_unsigned_int: case ECPGt_unsigned_long: ures
= strtoul(pval, &scan_length, 10);
-					if (garbage_left(isarray, &scan_length, compat))
+					if (scan_length == pval || garbage_left(isarray,
&scan_length, compat)) { ecpg_raise(lineno, ECPG_UINT_FORMAT,
ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); @@ -429,7 +429,7 @@
ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int
lineno,

 				case ECPGt_long_long:
 					*((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10);
-					if (garbage_left(isarray, &scan_length, compat))
+					if (scan_length == pval || garbage_left(isarray, &scan_length, compat))
 					{
 						ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
 						return false;
@@ -440,7 +440,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,

 				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))
+					if (scan_length == pval || garbage_left(isarray, &scan_length, compat))
 					{
 						ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
 						return false;
@@ -457,6 +457,13 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 					if (!check_special_value(pval, &dres, &scan_length))
 						dres = strtod(pval, &scan_length);

+					if (scan_length == pval)
+					{
+						ecpg_raise(lineno, ECPG_FLOAT_FORMAT,
+								   ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
+						return false;
+					}
+
 					if (isarray && *scan_length == '"')
 						scan_length++;

diff --git c/src/interfaces/ecpg/pgtypeslib/dt_common.c i/src/interfaces/ecpg/pgtypeslib/dt_common.c
index 3ed5ad06c06..958e220b806 100644
--- c/src/interfaces/ecpg/pgtypeslib/dt_common.c
+++ i/src/interfaces/ecpg/pgtypeslib/dt_common.c
@@ -2505,7 +2505,7 @@ pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char
 				(*pstr)++;
 			errno = 0;
 			scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10);
-			if (errno)
+			if (errno || strtol_end == *pstr)
 				err = 1;
 			break;
 		case PGTYPES_TYPE_UINT_LONG:
@@ -2513,7 +2513,7 @@ pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char
 				(*pstr)++;
 			errno = 0;
 			scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10);
-			if (errno)
+			if (errno || strtol_end == *pstr)
 				err = 1;
 			break;
 		case PGTYPES_TYPE_STRING_MALLOCED:
diff --git c/src/interfaces/ecpg/test/expected/sql-indicators.c i/src/interfaces/ecpg/test/expected/sql-indicators.c
index 796bd906af6..017f6c3ad39 100644
--- c/src/interfaces/ecpg/test/expected/sql-indicators.c
+++ i/src/interfaces/ecpg/test/expected/sql-indicators.c
@@ -8,6 +8,7 @@

 #line 1 "indicators.pgc"
 #include <stdio.h>
+#include <ecpgerrno.h>

 #line 1 "sqlca.h"
@@ -78,7 +79,7 @@ struct sqlca_t *ECPGget_sqlca(void);

 #endif

-#line 3 "indicators.pgc"
+#line 4 "indicators.pgc"

 #line 1 "regression.h"
@@ -88,7 +89,7 @@ struct sqlca_t *ECPGget_sqlca(void);

-#line 4 "indicators.pgc"
+#line 5 "indicators.pgc"

 int main(void)
@@ -96,68 +97,72 @@ int main(void)
 	/* exec sql begin declare section */

+

-#line 9 "indicators.pgc"
+#line 10 "indicators.pgc"
  int intvar = 5 ;

-#line 10 "indicators.pgc"
- int nullind = - 1 ;
-/* exec sql end declare section */
 #line 11 "indicators.pgc"
+ int nullind = - 1 ;
+
+#line 12 "indicators.pgc"
+ float floatvar ;
+/* exec sql end declare section */
+#line 13 "indicators.pgc"

 	ECPGdebug(1,stderr);

 	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); }
-#line 15 "indicators.pgc"
+#line 17 "indicators.pgc"

 	{ ECPGsetcommit(__LINE__, "off", NULL);}
-#line 16 "indicators.pgc"
+#line 18 "indicators.pgc"

 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table indicator_test ( \"id\" int primary key , \"str\" text not null , val int null )", ECPGt_EOIT, ECPGt_EORT);}
-#line 21 "indicators.pgc"
+#line 23 "indicators.pgc"

 	{ ECPGtrans(__LINE__, NULL, "commit work");}
-#line 22 "indicators.pgc"
+#line 24 "indicators.pgc"

 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 1 , 'Hello' , 0 )", ECPGt_EOIT, ECPGt_EORT);}
-#line 24 "indicators.pgc"
+#line 26 "indicators.pgc"

 	/* use indicator in insert */
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 2 , 'Hi there' , $1  )",
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
-#line 27 "indicators.pgc"
+#line 29 "indicators.pgc"

 	nullind = 0;
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 3 , 'Good evening' , $1  )",
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
-#line 29 "indicators.pgc"
+#line 31 "indicators.pgc"

 	{ ECPGtrans(__LINE__, NULL, "commit work");}
-#line 30 "indicators.pgc"
+#line 32 "indicators.pgc"

 	/* use indicators to get information about selects */
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 1", ECPGt_EOIT,
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
-#line 33 "indicators.pgc"
+#line 35 "indicators.pgc"

 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 2", ECPGt_EOIT,
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EORT);}
-#line 34 "indicators.pgc"
+#line 36 "indicators.pgc"

 	printf("intvar: %d, nullind: %d\n", intvar, nullind);
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 3", ECPGt_EOIT,
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EORT);}
-#line 36 "indicators.pgc"
+#line 38 "indicators.pgc"

 	printf("intvar: %d, nullind: %d\n", intvar, nullind);

@@ -166,24 +171,57 @@ int main(void)
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "update indicator_test set val = $1  where id = 1",
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
-#line 41 "indicators.pgc"
+#line 43 "indicators.pgc"

 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 1", ECPGt_EOIT,
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EORT);}
-#line 42 "indicators.pgc"
+#line 44 "indicators.pgc"

 	printf("intvar: %d, nullind: %d\n", intvar, nullind);

-	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table indicator_test", ECPGt_EOIT, ECPGt_EORT);}
-#line 45 "indicators.pgc"
+	/*
+	 * An empty string used to be silently converted to 0 instead of being
+	 * rejected as an invalid integer/float.
+	 */
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 4 , '' , 0 )", ECPGt_EOIT, ECPGt_EORT);}
+#line 51 "indicators.pgc"

 	{ ECPGtrans(__LINE__, NULL, "commit work");}
-#line 46 "indicators.pgc"
+#line 52 "indicators.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select str from indicator_test where id = 4", ECPGt_EOIT,
+	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int),
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 54 "indicators.pgc"
+
+	if (sqlca.sqlcode == ECPG_INT_FORMAT)
+		printf("empty string correctly rejected as integer\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as integer: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select str from indicator_test where id = 4", ECPGt_EOIT,
+	ECPGt_float,&(floatvar),(long)1,(long)1,sizeof(float),
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 61 "indicators.pgc"
+
+	if (sqlca.sqlcode == ECPG_FLOAT_FORMAT)
+		printf("empty string correctly rejected as float\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as float: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table indicator_test", ECPGt_EOIT, ECPGt_EORT);}
+#line 68 "indicators.pgc"
+
+	{ ECPGtrans(__LINE__, NULL, "commit work");}
+#line 69 "indicators.pgc"

 	{ ECPGdisconnect(__LINE__, "CURRENT");}
-#line 48 "indicators.pgc"
+#line 71 "indicators.pgc"

 	return 0;
 }
diff --git c/src/interfaces/ecpg/test/expected/sql-indicators.stderr i/src/interfaces/ecpg/test/expected/sql-indicators.stderr
index 5813ce29603..dec3eec2422 100644
--- c/src/interfaces/ecpg/test/expected/sql-indicators.stderr
+++ i/src/interfaces/ecpg/test/expected/sql-indicators.stderr
@@ -2,87 +2,115 @@
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGsetcommit on line 16: action "off"; connection "ecpg1_regression"
+[NO_PID]: ECPGsetcommit on line 18: action "off"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 18: query: create table indicator_test ( "id" int primary key , "str" text not null , val int null ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 20: query: create table indicator_test ( "id" int primary key , "str" text not null , val int null ); with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 18: using PQexec
+[NO_PID]: ecpg_execute on line 20: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 18: OK: CREATE TABLE
+[NO_PID]: ecpg_process_output on line 20: OK: CREATE TABLE
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGtrans on line 22: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: ECPGtrans on line 24: action "commit work"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: query: insert into indicator_test ( id , str , val ) values ( 1 , 'Hello' , 0 ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 26: query: insert into indicator_test ( id , str , val ) values ( 1 , 'Hello' , 0 ); with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: using PQexec
+[NO_PID]: ecpg_execute on line 26: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 24: OK: INSERT 0 1
+[NO_PID]: ecpg_process_output on line 26: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 27: query: insert into indicator_test ( id , str , val ) values ( 2 , 'Hi there' , $1  ); with 1 parameter(s) on connection ecpg1_regression
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 27: using PQexecParams
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_free_params on line 27: parameter 1 = null
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 27: OK: INSERT 0 1
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 29: query: insert into indicator_test ( id , str , val ) values ( 3 , 'Good evening' , $1  ); with 1 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 29: query: insert into indicator_test ( id , str , val ) values ( 2 , 'Hi there' , $1  ); with 1 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_execute on line 29: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_free_params on line 29: parameter 1 = 5
+[NO_PID]: ecpg_free_params on line 29: parameter 1 = null
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_process_output on line 29: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGtrans on line 30: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: ecpg_execute on line 31: query: insert into indicator_test ( id , str , val ) values ( 3 , 'Good evening' , $1  ); with 1 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 33: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 31: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 33: using PQexec
+[NO_PID]: ecpg_free_params on line 31: parameter 1 = 5
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 33: correctly got 1 tuples with 1 fields
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 33: RESULT: 0 offset: -1; array: no
+[NO_PID]: ECPGtrans on line 32: action "commit work"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 34: query: select val from indicator_test where id = 2; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 35: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 34: using PQexec
+[NO_PID]: ecpg_execute on line 35: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 34: correctly got 1 tuples with 1 fields
+[NO_PID]: ecpg_process_output on line 35: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 34: RESULT:  offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 35: RESULT: 0 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 36: query: select val from indicator_test where id = 3; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 36: query: select val from indicator_test where id = 2; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_execute on line 36: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_process_output on line 36: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 36: RESULT: 5 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 36: RESULT:  offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 41: query: update indicator_test set val = $1  where id = 1; with 1 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 38: query: select val from indicator_test where id = 3; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 41: using PQexecParams
+[NO_PID]: ecpg_execute on line 38: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_free_params on line 41: parameter 1 = null
+[NO_PID]: ecpg_process_output on line 38: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 41: OK: UPDATE 1
+[NO_PID]: ecpg_get_data on line 38: RESULT: 5 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 42: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 43: query: update indicator_test set val = $1  where id = 1; with 1 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 42: using PQexec
+[NO_PID]: ecpg_execute on line 43: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 42: correctly got 1 tuples with 1 fields
+[NO_PID]: ecpg_free_params on line 43: parameter 1 = null
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 42: RESULT:  offset: -1; array: no
+[NO_PID]: ecpg_process_output on line 43: OK: UPDATE 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 45: query: drop table indicator_test; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 44: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 45: using PQexec
+[NO_PID]: ecpg_execute on line 44: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 45: OK: DROP TABLE
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGtrans on line 46: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: query: insert into indicator_test ( id , str , val ) values ( 4 , '' , 0 ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 51: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 52: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 54: query: select str from indicator_test where id = 4; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 54: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 54: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 54: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -204 on line 54: invalid input syntax for type int: "", on line 54
+[NO_PID]: sqlca: code: -204, state: 42804
+[NO_PID]: ecpg_execute on line 61: query: select str from indicator_test where id = 4; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 61: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 61: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 61: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -206 on line 61: invalid input syntax for floating-point type: "", on line 61
+[NO_PID]: sqlca: code: -206, state: 42804
+[NO_PID]: ecpg_execute on line 68: query: drop table indicator_test; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 68: OK: DROP TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 69: action "commit work"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_finish: connection ecpg1_regression closed
 [NO_PID]: sqlca: code: 0, state: 00000
diff --git c/src/interfaces/ecpg/test/expected/sql-indicators.stdout i/src/interfaces/ecpg/test/expected/sql-indicators.stdout
index e9d6fd17c1c..270addb76c3 100644
--- c/src/interfaces/ecpg/test/expected/sql-indicators.stdout
+++ i/src/interfaces/ecpg/test/expected/sql-indicators.stdout
@@ -1,3 +1,5 @@
 intvar: 0, nullind: -1
 intvar: 5, nullind: 0
 intvar: 5, nullind: -1
+empty string correctly rejected as integer
+empty string correctly rejected as float
diff --git c/src/interfaces/ecpg/test/sql/indicators.pgc i/src/interfaces/ecpg/test/sql/indicators.pgc
index d925faf35ce..16e67ce498c 100644
--- c/src/interfaces/ecpg/test/sql/indicators.pgc
+++ i/src/interfaces/ecpg/test/sql/indicators.pgc
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <ecpgerrno.h>

 exec sql include sqlca;
 exec sql include ../regression;
@@ -8,6 +9,7 @@ int main(void)
 	exec sql begin declare section;
 		int intvar = 5;
 		int nullind = -1;
+		float floatvar;
 	exec sql end declare section;

 	ECPGdebug(1,stderr);
@@ -42,6 +44,27 @@ int main(void)
 	exec sql select val into :intvar :nullind from indicator_test where id = 1;
 	printf("intvar: %d, nullind: %d\n", intvar, nullind);

+	/*
+	 * An empty string used to be silently converted to 0 instead of being
+	 * rejected as an invalid integer/float.
+	 */
+	exec sql insert into indicator_test (id, str, val) values ( 4, '', 0);
+	exec sql commit work;
+
+	exec sql select str into :intvar from indicator_test where id = 4;
+	if (sqlca.sqlcode == ECPG_INT_FORMAT)
+		printf("empty string correctly rejected as integer\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as integer: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
+	exec sql select str into :floatvar from indicator_test where id = 4;
+	if (sqlca.sqlcode == ECPG_FLOAT_FORMAT)
+		printf("empty string correctly rejected as float\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as float: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
 	exec sql drop table indicator_test;
 	exec sql commit work;

Signed-off-by: Tristan Partin <tristan@partin.io>
---
 src/interfaces/ecpg/ecpglib/data.c            |  15 ++-
 src/interfaces/ecpg/pgtypeslib/dt_common.c    |   4 +-
 .../ecpg/test/expected/sql-indicators.c       |  84 +++++++++----
 .../ecpg/test/expected/sql-indicators.stderr  | 110 +++++++++++-------
 .../ecpg/test/expected/sql-indicators.stdout  |   2 +
 src/interfaces/ecpg/test/sql/indicators.pgc   |  23 ++++
 6 files changed, 168 insertions(+), 70 deletions(-)

diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c
index d5d40f7b654..932cb568a2d 100644
--- a/src/interfaces/ecpg/ecpglib/data.c
+++ b/src/interfaces/ecpg/ecpglib/data.c
@@ -373,7 +373,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 				case ECPGt_int:
 				case ECPGt_long:
 					res = strtol(pval, &scan_length, 10);
-					if (garbage_left(isarray, &scan_length, compat))
+					if (scan_length == pval || garbage_left(isarray, &scan_length, compat))
 					{
 						ecpg_raise(lineno, ECPG_INT_FORMAT,
 								   ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
@@ -402,7 +402,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 				case ECPGt_unsigned_int:
 				case ECPGt_unsigned_long:
 					ures = strtoul(pval, &scan_length, 10);
-					if (garbage_left(isarray, &scan_length, compat))
+					if (scan_length == pval || garbage_left(isarray, &scan_length, compat))
 					{
 						ecpg_raise(lineno, ECPG_UINT_FORMAT,
 								   ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
@@ -429,7 +429,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 
 				case ECPGt_long_long:
 					*((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10);
-					if (garbage_left(isarray, &scan_length, compat))
+					if (scan_length == pval || garbage_left(isarray, &scan_length, compat))
 					{
 						ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
 						return false;
@@ -440,7 +440,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 
 				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))
+					if (scan_length == pval || garbage_left(isarray, &scan_length, compat))
 					{
 						ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
 						return false;
@@ -457,6 +457,13 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 					if (!check_special_value(pval, &dres, &scan_length))
 						dres = strtod(pval, &scan_length);
 
+					if (scan_length == pval)
+					{
+						ecpg_raise(lineno, ECPG_FLOAT_FORMAT,
+								   ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
+						return false;
+					}
+
 					if (isarray && *scan_length == '"')
 						scan_length++;
 
diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c
index 3ed5ad06c06..958e220b806 100644
--- a/src/interfaces/ecpg/pgtypeslib/dt_common.c
+++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c
@@ -2505,7 +2505,7 @@ pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char
 				(*pstr)++;
 			errno = 0;
 			scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10);
-			if (errno)
+			if (errno || strtol_end == *pstr)
 				err = 1;
 			break;
 		case PGTYPES_TYPE_UINT_LONG:
@@ -2513,7 +2513,7 @@ pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char
 				(*pstr)++;
 			errno = 0;
 			scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10);
-			if (errno)
+			if (errno || strtol_end == *pstr)
 				err = 1;
 			break;
 		case PGTYPES_TYPE_STRING_MALLOCED:
diff --git a/src/interfaces/ecpg/test/expected/sql-indicators.c b/src/interfaces/ecpg/test/expected/sql-indicators.c
index 796bd906af6..017f6c3ad39 100644
--- a/src/interfaces/ecpg/test/expected/sql-indicators.c
+++ b/src/interfaces/ecpg/test/expected/sql-indicators.c
@@ -8,6 +8,7 @@
 
 #line 1 "indicators.pgc"
 #include <stdio.h>
+#include <ecpgerrno.h>
 
 
 #line 1 "sqlca.h"
@@ -78,7 +79,7 @@ struct sqlca_t *ECPGget_sqlca(void);
 
 #endif
 
-#line 3 "indicators.pgc"
+#line 4 "indicators.pgc"
 
 
 #line 1 "regression.h"
@@ -88,7 +89,7 @@ struct sqlca_t *ECPGget_sqlca(void);
 
 
 
-#line 4 "indicators.pgc"
+#line 5 "indicators.pgc"
 
 
 int main(void)
@@ -96,68 +97,72 @@ int main(void)
 	/* exec sql begin declare section */
 		   
 		   
+		 
 	
-#line 9 "indicators.pgc"
+#line 10 "indicators.pgc"
  int intvar = 5 ;
  
-#line 10 "indicators.pgc"
- int nullind = - 1 ;
-/* exec sql end declare section */
 #line 11 "indicators.pgc"
+ int nullind = - 1 ;
+ 
+#line 12 "indicators.pgc"
+ float floatvar ;
+/* exec sql end declare section */
+#line 13 "indicators.pgc"
 
 
 	ECPGdebug(1,stderr);
 
 	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); }
-#line 15 "indicators.pgc"
+#line 17 "indicators.pgc"
 
 	{ ECPGsetcommit(__LINE__, "off", NULL);}
-#line 16 "indicators.pgc"
+#line 18 "indicators.pgc"
 
 
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table indicator_test ( \"id\" int primary key , \"str\" text not null , val int null )", ECPGt_EOIT, ECPGt_EORT);}
-#line 21 "indicators.pgc"
+#line 23 "indicators.pgc"
 
 	{ ECPGtrans(__LINE__, NULL, "commit work");}
-#line 22 "indicators.pgc"
+#line 24 "indicators.pgc"
 
 
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 1 , 'Hello' , 0 )", ECPGt_EOIT, ECPGt_EORT);}
-#line 24 "indicators.pgc"
+#line 26 "indicators.pgc"
 
 
 	/* use indicator in insert */
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 2 , 'Hi there' , $1  )", 
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
-#line 27 "indicators.pgc"
+#line 29 "indicators.pgc"
 
 	nullind = 0;
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 3 , 'Good evening' , $1  )", 
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
-#line 29 "indicators.pgc"
+#line 31 "indicators.pgc"
 
 	{ ECPGtrans(__LINE__, NULL, "commit work");}
-#line 30 "indicators.pgc"
+#line 32 "indicators.pgc"
 
 
 	/* use indicators to get information about selects */
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 1", ECPGt_EOIT, 
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
-#line 33 "indicators.pgc"
+#line 35 "indicators.pgc"
 
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 2", ECPGt_EOIT, 
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EORT);}
-#line 34 "indicators.pgc"
+#line 36 "indicators.pgc"
 
 	printf("intvar: %d, nullind: %d\n", intvar, nullind);
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 3", ECPGt_EOIT, 
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EORT);}
-#line 36 "indicators.pgc"
+#line 38 "indicators.pgc"
 
 	printf("intvar: %d, nullind: %d\n", intvar, nullind);
 
@@ -166,24 +171,57 @@ int main(void)
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "update indicator_test set val = $1  where id = 1", 
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
-#line 41 "indicators.pgc"
+#line 43 "indicators.pgc"
 
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select val from indicator_test where id = 1", ECPGt_EOIT, 
 	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
 	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EORT);}
-#line 42 "indicators.pgc"
+#line 44 "indicators.pgc"
 
 	printf("intvar: %d, nullind: %d\n", intvar, nullind);
 
-	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table indicator_test", ECPGt_EOIT, ECPGt_EORT);}
-#line 45 "indicators.pgc"
+	/*
+	 * An empty string used to be silently converted to 0 instead of being
+	 * rejected as an invalid integer/float.
+	 */
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into indicator_test ( id , str , val ) values ( 4 , '' , 0 )", ECPGt_EOIT, ECPGt_EORT);}
+#line 51 "indicators.pgc"
 
 	{ ECPGtrans(__LINE__, NULL, "commit work");}
-#line 46 "indicators.pgc"
+#line 52 "indicators.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select str from indicator_test where id = 4", ECPGt_EOIT, 
+	ECPGt_int,&(intvar),(long)1,(long)1,sizeof(int), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 54 "indicators.pgc"
+
+	if (sqlca.sqlcode == ECPG_INT_FORMAT)
+		printf("empty string correctly rejected as integer\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as integer: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select str from indicator_test where id = 4", ECPGt_EOIT, 
+	ECPGt_float,&(floatvar),(long)1,(long)1,sizeof(float), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 61 "indicators.pgc"
+
+	if (sqlca.sqlcode == ECPG_FLOAT_FORMAT)
+		printf("empty string correctly rejected as float\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as float: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table indicator_test", ECPGt_EOIT, ECPGt_EORT);}
+#line 68 "indicators.pgc"
+
+	{ ECPGtrans(__LINE__, NULL, "commit work");}
+#line 69 "indicators.pgc"
 
 
 	{ ECPGdisconnect(__LINE__, "CURRENT");}
-#line 48 "indicators.pgc"
+#line 71 "indicators.pgc"
 
 	return 0;
 }
diff --git a/src/interfaces/ecpg/test/expected/sql-indicators.stderr b/src/interfaces/ecpg/test/expected/sql-indicators.stderr
index 5813ce29603..dec3eec2422 100644
--- a/src/interfaces/ecpg/test/expected/sql-indicators.stderr
+++ b/src/interfaces/ecpg/test/expected/sql-indicators.stderr
@@ -2,87 +2,115 @@
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGsetcommit on line 16: action "off"; connection "ecpg1_regression"
+[NO_PID]: ECPGsetcommit on line 18: action "off"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 18: query: create table indicator_test ( "id" int primary key , "str" text not null , val int null ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 20: query: create table indicator_test ( "id" int primary key , "str" text not null , val int null ); with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 18: using PQexec
+[NO_PID]: ecpg_execute on line 20: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 18: OK: CREATE TABLE
+[NO_PID]: ecpg_process_output on line 20: OK: CREATE TABLE
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGtrans on line 22: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: ECPGtrans on line 24: action "commit work"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: query: insert into indicator_test ( id , str , val ) values ( 1 , 'Hello' , 0 ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 26: query: insert into indicator_test ( id , str , val ) values ( 1 , 'Hello' , 0 ); with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: using PQexec
+[NO_PID]: ecpg_execute on line 26: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 24: OK: INSERT 0 1
+[NO_PID]: ecpg_process_output on line 26: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 27: query: insert into indicator_test ( id , str , val ) values ( 2 , 'Hi there' , $1  ); with 1 parameter(s) on connection ecpg1_regression
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 27: using PQexecParams
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_free_params on line 27: parameter 1 = null
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 27: OK: INSERT 0 1
-[NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 29: query: insert into indicator_test ( id , str , val ) values ( 3 , 'Good evening' , $1  ); with 1 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 29: query: insert into indicator_test ( id , str , val ) values ( 2 , 'Hi there' , $1  ); with 1 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_execute on line 29: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_free_params on line 29: parameter 1 = 5
+[NO_PID]: ecpg_free_params on line 29: parameter 1 = null
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_process_output on line 29: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGtrans on line 30: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: ecpg_execute on line 31: query: insert into indicator_test ( id , str , val ) values ( 3 , 'Good evening' , $1  ); with 1 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 33: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 31: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 33: using PQexec
+[NO_PID]: ecpg_free_params on line 31: parameter 1 = 5
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 33: correctly got 1 tuples with 1 fields
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 33: RESULT: 0 offset: -1; array: no
+[NO_PID]: ECPGtrans on line 32: action "commit work"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 34: query: select val from indicator_test where id = 2; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 35: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 34: using PQexec
+[NO_PID]: ecpg_execute on line 35: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 34: correctly got 1 tuples with 1 fields
+[NO_PID]: ecpg_process_output on line 35: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 34: RESULT:  offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 35: RESULT: 0 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 36: query: select val from indicator_test where id = 3; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 36: query: select val from indicator_test where id = 2; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_execute on line 36: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_process_output on line 36: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 36: RESULT: 5 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 36: RESULT:  offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 41: query: update indicator_test set val = $1  where id = 1; with 1 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 38: query: select val from indicator_test where id = 3; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 41: using PQexecParams
+[NO_PID]: ecpg_execute on line 38: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_free_params on line 41: parameter 1 = null
+[NO_PID]: ecpg_process_output on line 38: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 41: OK: UPDATE 1
+[NO_PID]: ecpg_get_data on line 38: RESULT: 5 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 42: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 43: query: update indicator_test set val = $1  where id = 1; with 1 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 42: using PQexec
+[NO_PID]: ecpg_execute on line 43: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 42: correctly got 1 tuples with 1 fields
+[NO_PID]: ecpg_free_params on line 43: parameter 1 = null
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 42: RESULT:  offset: -1; array: no
+[NO_PID]: ecpg_process_output on line 43: OK: UPDATE 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 45: query: drop table indicator_test; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: ecpg_execute on line 44: query: select val from indicator_test where id = 1; with 0 parameter(s) on connection ecpg1_regression
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 45: using PQexec
+[NO_PID]: ecpg_execute on line 44: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_process_output on line 45: OK: DROP TABLE
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 1 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGtrans on line 46: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: query: insert into indicator_test ( id , str , val ) values ( 4 , '' , 0 ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 51: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 52: action "commit work"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 54: query: select str from indicator_test where id = 4; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 54: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 54: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 54: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -204 on line 54: invalid input syntax for type int: "", on line 54
+[NO_PID]: sqlca: code: -204, state: 42804
+[NO_PID]: ecpg_execute on line 61: query: select str from indicator_test where id = 4; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 61: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 61: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 61: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -206 on line 61: invalid input syntax for floating-point type: "", on line 61
+[NO_PID]: sqlca: code: -206, state: 42804
+[NO_PID]: ecpg_execute on line 68: query: drop table indicator_test; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 68: OK: DROP TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 69: action "commit work"; connection "ecpg1_regression"
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_finish: connection ecpg1_regression closed
 [NO_PID]: sqlca: code: 0, state: 00000
diff --git a/src/interfaces/ecpg/test/expected/sql-indicators.stdout b/src/interfaces/ecpg/test/expected/sql-indicators.stdout
index e9d6fd17c1c..270addb76c3 100644
--- a/src/interfaces/ecpg/test/expected/sql-indicators.stdout
+++ b/src/interfaces/ecpg/test/expected/sql-indicators.stdout
@@ -1,3 +1,5 @@
 intvar: 0, nullind: -1
 intvar: 5, nullind: 0
 intvar: 5, nullind: -1
+empty string correctly rejected as integer
+empty string correctly rejected as float
diff --git a/src/interfaces/ecpg/test/sql/indicators.pgc b/src/interfaces/ecpg/test/sql/indicators.pgc
index d925faf35ce..16e67ce498c 100644
--- a/src/interfaces/ecpg/test/sql/indicators.pgc
+++ b/src/interfaces/ecpg/test/sql/indicators.pgc
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <ecpgerrno.h>
 
 exec sql include sqlca;
 exec sql include ../regression;
@@ -8,6 +9,7 @@ int main(void)
 	exec sql begin declare section;
 		int intvar = 5;
 		int nullind = -1;
+		float floatvar;
 	exec sql end declare section;
 
 	ECPGdebug(1,stderr);
@@ -42,6 +44,27 @@ int main(void)
 	exec sql select val into :intvar :nullind from indicator_test where id = 1;
 	printf("intvar: %d, nullind: %d\n", intvar, nullind);
 
+	/*
+	 * An empty string used to be silently converted to 0 instead of being
+	 * rejected as an invalid integer/float.
+	 */
+	exec sql insert into indicator_test (id, str, val) values ( 4, '', 0);
+	exec sql commit work;
+
+	exec sql select str into :intvar from indicator_test where id = 4;
+	if (sqlca.sqlcode == ECPG_INT_FORMAT)
+		printf("empty string correctly rejected as integer\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as integer: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
+	exec sql select str into :floatvar from indicator_test where id = 4;
+	if (sqlca.sqlcode == ECPG_FLOAT_FORMAT)
+		printf("empty string correctly rejected as float\n");
+	else
+		printf("unexpected sqlcode %ld for empty string as float: %s\n",
+			   sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
+
 	exec sql drop table indicator_test;
 	exec sql commit work;
 
-- 
Tristan Partin
https://tristan.partin.io

