Out of range value for column in MySQL float column

156 views Asked by At

I have a MySQL database with a table containing many columns declared as float type, e.g.TgPhi_L1_Min FLOAT DEFAULT NULL,. The table is filled by a program written in C++Builder 10.3 using FireDAC (TFDQuery) that collects data from a measuring device. The code responsible for that looks like this:

FDQuery_InsertData->Open("SELECT * FROM {id measurements_general} WHERE 1=2");
FDQuery_InsertData->Insert();
FDQuery_InsertData->FieldByName("meter_id")->AsInteger = MeterId;
FDQuery_InsertData->FieldByName("cfg_id")->AsInteger = ConfigId;
FDQuery_InsertData->FieldByName("date_time")->AsDateTime = DateTime;
FDQuery_InsertData->FieldByName("insert_date_time")->AsDateTime = Now();
for (auto i = 0; i < DescriptorsGeneral.List->Count; i++)
{
    if (IsNan(Data[DescriptorsGeneral.Indexes[i]]) || IsInfinite(Data[DescriptorsGeneral.Indexes[i]]))
            continue;
    FDQuery_InsertData->FieldByName(DescriptorsGeneral.List->Strings[i])->AsSingle = Data[DescriptorsGeneral.Indexes[i]]; //Data is passed as a parameter to this function, float *Data;
}
FDQuery_InsertData->Post();

Everything goes fine, until someday a measuring device sent a value which is the maximum float value of 0x7F7FFFFF. It shouldn't be a problem, but I got an exception

First chance exception at $772A3642. Exception class EMySQLNativeException with message '[FireDAC][Phys][MySQL] Out of range value for column 'TgPhi_L1_Min' at row 1'. Process Meter_Server.exe (12796).

Trying to understand what happened, I turned on FireDAC's monitor, and it turns out that the value inserted into the INSERT statement indeed exceeds the float range i.e. 3.4028235E38. What I find more surprising is that numbers passed to the INSERT statement differ in precision, although all are declared the same way (MySQL float, FireDAC single), eg 0.98364758, 0, 3.4028235E38, -3.4028235E38, 0, 3.4028235E38, -3.4028235E38, 29.885546.

The parameters of fetching columns by TFDQuery are: Col add [Index=86, SrcName="TgPhi_L1", SrcType=Single, SrcSize=0, SrcPrec=12, SrcScale=31, Type=Single, Size=0, Prec=12, Scale=31].

I tried with FormatOptions: CheckPrecision and Round2Scale, I added my own mapping rules setting ScaleMin and PrecMin, but none of it affected values in the INSERT statement sent to the database by FireDAC.

Can anyone help me solve this problem? what I am doing wrong?

EDITED:

I'm confused, of course when I prepare a proper string manually, as @GarrGodfrey suggested, it works, but it doesn't work with TFDQuery in the way I did it. TFDQuery knows that the field is the single type, and finally always converts and rounds the values to single precision. The problem is, the single type fields have a Precision property set to 7, which complies with the float standard. But in MySQL I'm not sure, this is where I'm lost.

In C++, the following two numbers are treated as equal:

float x = 3.4028235E38; 
float y = 3.402823466385288E38;

I think, this is because y has much more precision and is rounded. In MySQL, these are two different numbers: x is out of range and y is not, why?

CREATE PROCEDURE `test_float`()
begin
    declare x float;
    declare y float;
    set x = 3.4028235E38;
    set y = 3.402823466385288E38;
    select x, y;
end
0

There are 0 answers