diff --git a/include/s3select_functions.h b/include/s3select_functions.h index f7fb1948..6849de96 100644 --- a/include/s3select_functions.h +++ b/include/s3select_functions.h @@ -599,42 +599,43 @@ struct _fn_to_int : public base_function struct _fn_to_float : public base_function { - value var_result; - value v_from; bool operator()(bs_stmt_vec_t* args, variable* result) override { - char* perr; - double d=0; value v = (*args->begin())->eval(); - if (v.type == value::value_En_t::STRING) + switch (v.type) { + + case value::value_En_t::STRING: { - errno = 0; - d = strtod(v.str(), &perr) ; //TODO check error before constructor - if ((errno == ERANGE && (d == LONG_MAX || d == LONG_MIN)) || (errno != 0 && d == 0)) { + char* pend; + double d = strtod(v.str(), &pend); + if (errno == ERANGE) { throw base_s3select_exception("converted value would fall out of the range of the result type!"); - return false; - } - - if (*perr != '\0') { - throw base_s3select_exception("characters after float!"); - return false; - } - } - else if (v.type == value::value_En_t::FLOAT) - { - d = v.dbl(); + } + if (pend == v.str()) { + // no number found + throw base_s3select_exception("text cannot be converted to a number"); + } + if (*pend) { + throw base_s3select_exception("extra characters after the number"); + } + + var_result = d; } - else - { - d = v.i64(); + break; + + case value::value_En_t::FLOAT: + var_result = v.dbl(); + break; + + default: + var_result = v.i64(); + break; } - var_result = d; *result = var_result; - return true; } diff --git a/test/s3select_test.cpp b/test/s3select_test.cpp index 38d6e435..66f33eb9 100644 --- a/test/s3select_test.cpp +++ b/test/s3select_test.cpp @@ -689,7 +689,7 @@ int count_string(std::string in,std::string substr) } -void test_single_column_single_row(const char* input_query,const char* expected_result) +void test_single_column_single_row(const char* input_query,const char* expected_result,const char * error_description = 0) { s3select s3select_syntax; auto status = s3select_syntax.parse_query(input_query); @@ -704,6 +704,17 @@ void test_single_column_single_row(const char* input_query,const char* expected_ false, // dont skip last line true // aggregate call ); + + if(strcmp(expected_result,"#failure#") == 0) + { + if (status==0 && s3select_result.compare("#failure#")==0) + { + ASSERT_TRUE(0); + } + ASSERT_EQ(s3_csv_object.get_error_description(),error_description); + return; + } + ASSERT_EQ(status, 0); ASSERT_EQ(s3select_result, std::string(expected_result)); } @@ -3426,6 +3437,13 @@ TEST(TestS3selectFunctions, boolcast) test_single_column_single_row("select cast('a' as bool) from s3object;","false,\n"); } +TEST(TestS3selectFunctions, floatcast) +{ + test_single_column_single_row("select cast('1234a' as float) from s3object;","#failure#","extra characters after the number"); + test_single_column_single_row("select cast('a1234' as float) from s3object;","#failure#","text cannot be converted to a number"); + test_single_column_single_row("select cast('999e+999' as float) from s3object;","#failure#","converted value would fall out of the range of the result type!"); +} + TEST(TestS3selectFunctions, predicate_as_projection_column) { std::string input;