Skip to content

Commit 569de36

Browse files
committed
Use rb_big_and instead of rb_big_cmp
This logic has the following merits. * rb_big_and is exported from Ruby 1.8.7. * it can avoid to generate a bignum object on LP64 environment because `LL2NUM(LLONG_MAX>>1)` is Fixnum on LP64.
1 parent a3f5500 commit 569de36

File tree

3 files changed

+15
-21
lines changed

3 files changed

+15
-21
lines changed

ext/mysql2/extconf.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ def asplode(lib)
2323
have_func('rb_wait_for_single_fd')
2424
have_func('rb_hash_dup')
2525
have_func('rb_intern3')
26-
have_func('rb_big_cmp')
2726

2827
# borrowed from mysqlplus
2928
# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb

ext/mysql2/statement.c

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -204,39 +204,27 @@ static void set_buffer_for_string(MYSQL_BIND* bind_buffer, unsigned long *length
204204
xfree(length_buffers); \
205205
}
206206

207-
#ifndef HAVE_RB_BIG_CMP
208-
/* both x and y must be Bignum though MRI's rb_big_cmp support more types */
209-
static VALUE rb_big_cmp(VALUE x, VALUE y)
210-
{
211-
/* Ruby 1.8.7 has rb_big_minus */
212-
VALUE r = rb_big_minus(x, y);
213-
if (FIXNUM_P(r)) {
214-
long l = FIX2LONG(r);
215-
return l < 0 ? -1 : l == 0 ? 0 : 1;
216-
}
217-
else { /* must be normalized Bignum */
218-
return RBIGNUM_POSITIVE_P(r) ? 1 : -1;
219-
}
220-
}
221-
#endif
222-
223207
/* return 0 if the given bignum can cast as LONG_LONG, otherwise 1 */
224208
static int my_big2ll(VALUE bignum, LONG_LONG *ptr)
225209
{
226210
unsigned LONG_LONG num;
211+
size_t len;
212+
int nlz_bits = 0;
227213
#ifdef HAVE_RB_ABSINT_SIZE
228-
if (rb_absint_size(bignum, NULL) > 8) goto overflow;
214+
len = rb_absint_size(bignum, &nlz_bits);
229215
#else
230-
if (RBIGNUM_LEN(bignum)*SIZEOF_BDIGITS > 8) goto overflow;
216+
len = RBIGNUM_LEN(bignum) * SIZEOF_BDIGITS;
231217
#endif
218+
if (len > 8) goto overflow;
232219
if (RBIGNUM_POSITIVE_P(bignum)) {
233220
num = rb_big2ull(bignum);
234221
if (num > LLONG_MAX)
235222
goto overflow;
236223
*ptr = num;
237224
}
238225
else {
239-
if (rb_big_cmp(bignum, LL2NUM(LLONG_MIN)) == INT2FIX(-1))
226+
if (len == 8 && nlz_bits == 0 &&
227+
rb_big_and(bignum, LL2NUM(LLONG_MAX>>1)) != INT2FIX(0))
240228
goto overflow;
241229
*ptr = rb_big2ll(bignum);
242230
}

spec/mysql2/statement_spec.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,16 @@
7272
int64_max1 = (1 << 63)
7373
int64_min1 = -(1 << 63) - 1
7474
result = stmt.execute(int64_max1, int64_min1)
75-
expect(result.to_a).to eq(['max1' => "9223372036854775808", 'min1' => "-9223372036854775809"])
75+
expect(result.to_a).to eq(['max1' => int64_max1.to_s, 'min1' => int64_min1.to_s])
7676
end
7777

78+
it "should handle bignum but beyond uint64_t" do
79+
stmt = @client.prepare('SELECT ? AS max1, ? AS min1')
80+
int65_max1 = (1 << 64) - 1
81+
int65_min1 = -(1 << 64)+1
82+
result = stmt.execute(int65_max1, int65_min1)
83+
expect(result.to_a).to eq(['max1' => int65_max1.to_s, 'min1' => int65_min1.to_s])
84+
end
7885
it "should keep its result after other query" do
7986
@client.query 'USE test'
8087
@client.query 'CREATE TABLE IF NOT EXISTS mysql2_stmt_q(a int)'

0 commit comments

Comments
 (0)