@@ -4,6 +4,9 @@ VALUE cMysql2Statement;
44extern VALUE mMysql2 , cMysql2Error , cBigDecimal , cDateTime , cDate ;
55static VALUE sym_stream , intern_new_with_args , intern_each ;
66static 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
710
811#define GET_STATEMENT (self ) \
912 mysql_stmt_wrapper *stmt_wrapper; \
@@ -203,6 +206,50 @@ static void set_buffer_for_string(MYSQL_BIND* bind_buffer, unsigned long *length
203206 xfree(length_buffers); \
204207 }
205208
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+
206253/* call-seq: stmt.execute
207254 *
208255 * Executes the current prepared statement, returns +result+.
@@ -264,9 +311,23 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
264311#endif
265312 break ;
266313 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+ }
270331 break ;
271332 case T_FLOAT :
272333 bind_buffers [i ].buffer_type = MYSQL_TYPE_DOUBLE ;
@@ -500,4 +561,7 @@ void init_mysql2_statement() {
500561 intern_year = rb_intern ("year" );
501562
502563 intern_to_s = rb_intern ("to_s" );
564+ #ifndef HAVE_RB_BIG_CMP
565+ id_cmp = rb_intern ("<=>" );
566+ #endif
503567}
0 commit comments