-
Notifications
You must be signed in to change notification settings - Fork 548
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
Avoid RangeError on integers larger than LONG_LONG #764
Avoid RangeError on integers larger than LONG_LONG #764
Conversation
int64_min = -(1 << 63) | ||
result = stmt.execute(int64_max, int64_min) | ||
expect(result.to_a).to eq(['max' => int64_max, 'min' => int64_min]) | ||
@client.query 'DROP TABLE IF EXISTS mysql2_stmt_q' |
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.
No need to drop the table since these tests aren't creating/querying from it.
Thank you! Will this also work in the future merged Integer / FixNum / BigNum world of Ruby 2.4.0? |
f47cb50
to
1a0703c
Compare
Yeah, |
Ruby 1.8.7 does have You could call Bignum#<=> to get the same effect? /* elsewhere in the file */
static ID id_cmp;
id_cmp = rb_intern("<=>");
/**/
#ifdef HAVE_RB_BIG_CMP
VALUE less_than_llong_min = rb_big_cmp(bignum, LL2NUM(LLONG_MIN));
#else
VALUE less_than_llong_min = rb_funcall(bignum, id_cmp, 1, LL2NUM(LLONG_MIN));
#endif
if (less_than_llong_min == INT2FIX(-1)) {
// code
} else {
// code
} |
I noticed |
#endif | ||
if (len > 8) goto overflow; | ||
if (RBIGNUM_POSITIVE_P(bignum)) { | ||
num = rb_big2ull(bignum); |
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.
Looks like if BIGSIZE(bignum) > SIZEOF_LONG_LONG
, should be goto overflow
.
http://rxr.whitequark.org/mri/source/bignum.c#3587
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.
Oh, enough to if (len > 8) goto overflow;
?
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.
Yes. len > 8
means "Bignum's raw size is larger than 8
byte.
It is the same meaning with BIGSIZE(bignum) > SIZEOF_LONG_LONG
.
Anyway the spec should have int64_max3 = 1 << 64
; I'll add it tomorrow.
#else | ||
len = RBIGNUM_LEN(bignum) * SIZEOF_BDIGITS; | ||
#endif | ||
if (len > 8) goto overflow; |
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.
Length 8 is intended to be the same as sizeof(long long int)
right? Would it make sense for the integer size to be passed in as an argument?
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.
fixed!
37410c4
to
81fb72b
Compare
@sodabrew I reflected your comments. What do you think about current one? |
Sorry for the long delay on this PR, and it's run into a merge conflict since the recent |
CRuby's rb_big2ull raises RangeError if the argument is out of [LONG_MIN, ULONG_MAX]. To avoid that calling to_s and set as decimal with some tricks for edge cases. For Ruby 1.8.7, use rb_funcall() to call Bignum#<=> through Ruby space. For Ruby 1.9.3 and 2.0.0, use rb_big_cmp() to call Bignum#<=> directly. For Ruby 2.1 and above, use rb_absint_size() and I noticed len == 8 && nlz_bits == 0 && rb_absint_singlebit_p(bignum) is the best condition because it doesn't allocate extra object.
c2c67e7
to
f59eb53
Compare
Hmm, rebased but it fails. I'll investigate later... |
Thanks! There's an interaction with #783 that results in the values getting cast as BigDecimal instead of a string on return. The reason is that MySQL defaults to returning numeric values as decimals unless it knows a specific integer size from a column definition or a procedure signature. |
I think #783 actually correctly fixed the big number types, and you can remove the
|
* Use rb_absint_size and rb_absint_singlebit_p on Ruby 2.1 or later. They don't allocate new objects and fast. * Use rb_big_cmp on Ruby 1.9.x and 2.0.0 * Use rb_funcall(bignum, rb_intern("<=>")) on Ruby 1.8 and REE Note that this works on Ruby 2.4.
f59eb53
to
f10a337
Compare
@sodabrew Fixed as you says removed |
CRuby's rb_big2ull raises RangeError if the argument is out of [LONG_MIN, ULONG_MAX].
To avoid that calling to_s and set as decimal with some tricks for edge cases.