-
Notifications
You must be signed in to change notification settings - Fork 2.3k
SELECT FLOAT to float64 #308
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
Conversation
…ut problems from the begining, but just in case let's place it here
You can check build result for each individual commit here: https://github.com/arvenil/mysql/compare/select_float_to_float64 |
} | ||
} | ||
|
||
dsns := []string{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parseTime
is irrelevant here I guess. You don't need to test both versions of the DSN. Just leave out parseTime
altogether.
One more problem: What you are trying to do (returning float32 instead) is illegal according to the specification: http://golang.org/pkg/database/sql/driver/#Value and http://golang.org/pkg/database/sql/driver/#Rows |
Is there really something wrong here at all? http://play.golang.org/p/kY-amQoUG1 |
No, there's nothing wrong. |
@arvenil your test is faulty, the driver does what it should do. EDIT To illustrate: |
Hi, sorry for not responding earlier but I was quite busy (and was thinking about this too). Yes, I got the float32 to float64 conversion and changes related to the precision. The original bug report from me is that this query:
Results with While those queries
Results with So, it's not about which one is correct, but that they return different values. @julienschmidt @arnehormann Is this correct behavior? If so then why? If so then maybe it would be a good idea to write tests for this? I might find the answer but it would be great if you guys could take a look at this too and tell me what you think. |
A preliminary (strong) suspicion: None of these are wrong, just righter and wronger in certain cases. f32str := strconv.FormatFloat(float64(floatFromServer), 'g', -1, 32)
result, _ := strconv.ParseFloat(f32str, 64) Floats are hard. Floating point decimals would improve this so much 😢 I'm still for "working as intended" - or at least "the lesser evil" |
Exactly! I came to the same conclusion. In text protocol we probably get closest value e.g. I'm ok with Also a good thing could be to check how this is handled by other drivers in other languages. Thanks for you time guys, and thanks for looking at this! |
@arvenil I just want to state that this is exactly what I meant when I said your test is wrong. The precision is not "higher", the resulting value just probably matches the user intent better. There's just an empty space between what we receive and the format we have to pass it on in (float64) - and we fill it differently in the text and binary case because we never know what the intended value is. Most of the time, it will be the closest matching decimal. But it does not have to be and using that value would be slower. I don't know how to sensibly lock this down in a test and I'd prefer not to to keep it open when some way of improved handling presents itself upstream. For speed and for correctness. But I can see the value in documenting this. Btw, thanks for your engagement! It's pretty great. |
Yes, my bad, wrongly phrased sentence. With the precision I meant that in case of text protocol, with conversion of string Ok, enough, thanks for help figuring this out! |
You're welcome! |
Hi all,
While I was trying out #297 I discovered some of tests in internal project started to fail when emulated queries were used instead of prepared statements.
I checked query log with
substitutePlaceholder=true
andsubstitutePlaceholder=false
. All queries were identical, didn't matter if they were prepared by MySQL or by driver (tests run 2000+ queries) - so #297 was 100% correct!So I investigated further... Tests were failing at some floats where expected value was e.g.
0.050551000982522964
but withsubstitutePlaceholder=true
I got0.050551
. I checked data, and actually correct value was0.050551
. So actually turningsubstitutePlaceholder=true
on provided correct data.I found out that in some cases switching from MySQL prepared statements to driver prepared statements changed the way how data was parsed by driver. With
substitutePlaceholder=false
data was parsed byfunc (rows *binaryRows) readRow
(https://github.com/go-sql-driver/mysql/blob/master/packets.go#L962) while switching tosubstitutePlaceholder=true
changed the behavior and data got parsed byfunc (rows *textRows) readRow
(https://github.com/go-sql-driver/mysql/blob/master/packets.go#L595). After some investigation I came to conclusion that currently selecting FLOAT to float64 is incorrectly handled. I've attached failing test cases with fixes. With one fix I'm not happy - it's an ugly hack because I couldn't figure out what's going on here: https://github.com/go-sql-driver/mysql/blob/master/packets.go#L619 I couldn't figure out whenrows.columns
is filled with data... I wanted simply to check forrows.columns[i].fieldType
but it looks like it doesn't always have data and so it was throwing panics... I've added dirty hackif i > len(rows.columns)-1 { continue }
and it works but I bet there is a better way to handle that ;)Summary:
"CREATE TABLE test (f FLOAT)"
"INSERT INTO test VALUE (0.050551)"
(rows *binaryRows) readRow
(rows *textRows) readRow
(why this is different than first example?)