From 96da8c2831804a3818ecee0b467f0b7b000efe74 Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Thu, 30 Jul 2026 08:33:28 +0000 Subject: [PATCH v1 4/5] 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 +#include #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 port [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 +#include 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 --- 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 +#include #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 port [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 +#include 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