@@ -4,6 +4,9 @@ VALUE cMysql2Statement;
4
4
extern VALUE mMysql2 , cMysql2Error , cBigDecimal , cDateTime , cDate ;
5
5
static VALUE sym_stream , intern_new_with_args , intern_each ;
6
6
static VALUE intern_usec , intern_sec , intern_min , intern_hour , intern_day , intern_month , intern_year , intern_to_s ;
7
+ #ifndef HAVE_RB_BIG_CMP
8
+ static ID id_cmp ;
9
+ #endif
7
10
8
11
#define GET_STATEMENT (self ) \
9
12
mysql_stmt_wrapper *stmt_wrapper; \
@@ -203,6 +206,50 @@ static void set_buffer_for_string(MYSQL_BIND* bind_buffer, unsigned long *length
203
206
xfree(length_buffers); \
204
207
}
205
208
209
+ /* return 0 if the given bignum can cast as LONG_LONG, otherwise 1 */
210
+ static int my_big2ll (VALUE bignum , LONG_LONG * ptr )
211
+ {
212
+ unsigned LONG_LONG num ;
213
+ size_t len ;
214
+ #ifdef HAVE_RB_ABSINT_SIZE
215
+ int nlz_bits = 0 ;
216
+ len = rb_absint_size (bignum , & nlz_bits );
217
+ #else
218
+ len = RBIGNUM_LEN (bignum ) * SIZEOF_BDIGITS ;
219
+ #endif
220
+ if (len > sizeof (LONG_LONG )) goto overflow ;
221
+ if (RBIGNUM_POSITIVE_P (bignum )) {
222
+ num = rb_big2ull (bignum );
223
+ if (num > LLONG_MAX )
224
+ goto overflow ;
225
+ * ptr = num ;
226
+ }
227
+ else {
228
+ if (len == 8 &&
229
+ #ifdef HAVE_RB_ABSINT_SIZE
230
+ nlz_bits == 0 &&
231
+ #endif
232
+ #if defined(HAVE_RB_ABSINT_SIZE ) && defined(HAVE_RB_ABSINT_SINGLEBIT_P )
233
+ /* Optimized to avoid object allocation for Ruby 2.1+
234
+ * only -0x8000000000000000 is safe if `len == 8 && nlz_bits == 0`
235
+ */
236
+ !rb_absint_singlebit_p (bignum )
237
+ #elif defined(HAVE_RB_BIG_CMP )
238
+ rb_big_cmp (bignum , LL2NUM (LLONG_MIN )) == INT2FIX (-1 )
239
+ #else
240
+ /* Ruby 1.8.7 and REE doesn't have rb_big_cmp */
241
+ rb_funcall (bignum , id_cmp , 1 , LL2NUM (LLONG_MIN )) == INT2FIX (-1 )
242
+ #endif
243
+ ) {
244
+ goto overflow ;
245
+ }
246
+ * ptr = rb_big2ll (bignum );
247
+ }
248
+ return 0 ;
249
+ overflow :
250
+ return 1 ;
251
+ }
252
+
206
253
/* call-seq: stmt.execute
207
254
*
208
255
* Executes the current prepared statement, returns +result+.
@@ -264,9 +311,23 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
264
311
#endif
265
312
break ;
266
313
case T_BIGNUM :
267
- bind_buffers [i ].buffer_type = MYSQL_TYPE_LONGLONG ;
268
- bind_buffers [i ].buffer = xmalloc (sizeof (long long int ));
269
- * (LONG_LONG * )(bind_buffers [i ].buffer ) = rb_big2ll (argv [i ]);
314
+ {
315
+ LONG_LONG num ;
316
+ if (my_big2ll (argv [i ], & num ) == 0 ) {
317
+ bind_buffers [i ].buffer_type = MYSQL_TYPE_LONGLONG ;
318
+ bind_buffers [i ].buffer = xmalloc (sizeof (long long int ));
319
+ * (LONG_LONG * )(bind_buffers [i ].buffer ) = num ;
320
+ } else {
321
+ /* The bignum was larger than we can fit in LONG_LONG, send it as a string */
322
+ VALUE rb_val_as_string = rb_big2str (argv [i ], 10 );
323
+ bind_buffers [i ].buffer_type = MYSQL_TYPE_NEWDECIMAL ;
324
+ params_enc [i ] = rb_val_as_string ;
325
+ #ifdef HAVE_RUBY_ENCODING_H
326
+ params_enc [i ] = rb_str_export_to_enc (params_enc [i ], conn_enc );
327
+ #endif
328
+ set_buffer_for_string (& bind_buffers [i ], & length_buffers [i ], params_enc [i ]);
329
+ }
330
+ }
270
331
break ;
271
332
case T_FLOAT :
272
333
bind_buffers [i ].buffer_type = MYSQL_TYPE_DOUBLE ;
@@ -500,4 +561,7 @@ void init_mysql2_statement() {
500
561
intern_year = rb_intern ("year" );
501
562
502
563
intern_to_s = rb_intern ("to_s" );
564
+ #ifndef HAVE_RB_BIG_CMP
565
+ id_cmp = rb_intern ("<=>" );
566
+ #endif
503
567
}
0 commit comments