Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2022 regression: negative DECIMAL, NUMERIC and DECFLOAT numbers in result sets are truncated to negative integers in fetch_array, fetch_assoc, fetch_object #172

Open
cthorman opened this issue Jul 15, 2024 · 2 comments

Comments

@cthorman
Copy link

All negative DECIMAL, NUMERIC and DECFLOAT numbers in result sets are truncated to negative integers in fetch_array, fetch_assoc, fetch_object. The problem does not happen in fetch_row/result, where they are returned as string types including negative sign, and could be parsed as decimals if desired.

To reproduce:

pp IBM_DB::fetch_assoc(IBM_DB.exec(dbh, "select 12.34 as FOO, -12.34 as BAR from PRCDTEP limit 1"))
==> {"FOO"=>0.1234e2, "BAR"=>-12}

The bug is here in line 9582:

if ((atof(row_data->str_val) - atol(row_data->str_val)) > 0)

The data coming in from the DB2 driver is evidently a string representation of the value (!). The code is trying to determine if it has a decimal component, or not. If it does, it is going to create a BigDecimal. Otherwise, it just going to use a C "long" integer which will become a Ruby Integer. In that line, it is choosing a really odd way of determining if there is a decimal component: as follows: letting the C compiler parse the string as a float, then as a long, and then subtracting. If the result is "greater than zero" (e.g. 23.5 - 23 = 0.5) then of course there must be a floating point component, and so it uses BigDecimal. But that logic only works for positive numbers. If the number is -23.50, then you have -23.50 - -23, which gives you -.05, which is less than zero, so the whole-number (else) path is followed, giving us the integer interpretation (truncating everything after the decimal point). So this logic will never work for negative decimal or float values.

I would also dispute whether this logic should ever be returning integer values for these data types which have all been declared to have a decimal component. It seems it should always be returning BigDecimal, but that is another question. In other words, 12.00 stored in my database as decimal(10,2) is not the same meaning as 12 (integer).

The bug comes from this commit in 2022:

58e48b1

commit 58e48b1
Author: Praveen Narayanappa <pnarayanappa@waldevdbctpyl01.dev.rocketsoftware.com>
Date: Fri Sep 16 11:49:17 2022 -0400
Support for Rails 6.1

I am surprised to be the first person to find this bug. Maybe nobody ever uses negative decimal / currency numbers? In my client’s application, they are common.

P.S. the bug does not happen when using fetch_row/result, where these values are returned as string types including negative sign. I am not using that function myself, but this could also be considered wrong behavior. fetch_row/result should probably use the same internal logic to convert data values, as these other functions. Maybe it's too late to change that at this point.

Hope this helps,

-c

@oeil2lynx
Copy link

I have the same problem

@cthorman
Copy link
Author

cthorman commented Aug 15, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants