@@ -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; \
@@ -204,6 +207,47 @@ static void set_buffer_for_string(MYSQL_BIND* bind_buffer, unsigned long *length
204207 xfree(length_buffers); \
205208 }
206209
210+ /* return 0 if the given bignum can cast as LONG_LONG, otherwise 1 */
211+ static int my_big2ll (VALUE bignum , LONG_LONG * ptr )
212+ {
213+ unsigned LONG_LONG num ;
214+ size_t len ;
215+ #ifdef HAVE_RB_ABSINT_SIZE
216+ int nlz_bits = 0 ;
217+ len = rb_absint_size (bignum , & nlz_bits );
218+ #else
219+ len = RBIGNUM_LEN (bignum ) * SIZEOF_BDIGITS ;
220+ #endif
221+ if (len > 8 ) goto overflow ;
222+ if (RBIGNUM_POSITIVE_P (bignum )) {
223+ num = rb_big2ull (bignum );
224+ if (num > LLONG_MAX )
225+ goto overflow ;
226+ * ptr = num ;
227+ }
228+ else {
229+ if (len == 8 &&
230+ #ifdef HAVE_RB_ABSINT_SIZE
231+ nlz_bits == 0 &&
232+ #endif
233+ #if defined(HAVE_RB_ABSINT_SIZE ) && defined(HAVE_RB_ABSINT_SINGLEBIT_P )
234+ /* only -0x8000000000000000 is safe if `len == 8 && nlz_bits == 0` */
235+ !rb_absint_singlebit_p (bignum )
236+ #elif defined(HAVE_RB_BIG_CMP )
237+ rb_big_cmp (bignum , LL2NUM (LLONG_MIN )) == INT2FIX (-1 )
238+ #else
239+ rb_funcall (bignum , intern_cmp , 1 , LL2NUM (LLONG_MIN )) == INT2FIX (-1 )
240+ #endif
241+ ) {
242+ goto overflow ;
243+ }
244+ * ptr = rb_big2ll (bignum );
245+ }
246+ return 0 ;
247+ overflow :
248+ return 1 ;
249+ }
250+
207251/* call-seq: stmt.execute
208252 *
209253 * Executes the current prepared statement, returns +result+.
@@ -265,9 +309,23 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
265309#endif
266310 break ;
267311 case T_BIGNUM :
268- bind_buffers [i ].buffer_type = MYSQL_TYPE_LONGLONG ;
269- bind_buffers [i ].buffer = xmalloc (sizeof (long long int ));
270- * (LONG_LONG * )(bind_buffers [i ].buffer ) = rb_big2ll (argv [i ]);
312+ {
313+ LONG_LONG num ;
314+ if (my_big2ll (argv [i ], & num ) == 0 ) {
315+ bind_buffers [i ].buffer_type = MYSQL_TYPE_LONGLONG ;
316+ bind_buffers [i ].buffer = xmalloc (sizeof (long long int ));
317+ * (LONG_LONG * )(bind_buffers [i ].buffer ) = num ;
318+ } else {
319+ /* The bignum was larger than we can fit in LONG_LONG, send it as a string */
320+ VALUE rb_val_as_string = rb_big2str (argv [i ], 10 );
321+ bind_buffers [i ].buffer_type = MYSQL_TYPE_NEWDECIMAL ;
322+ params_enc [i ] = rb_val_as_string ;
323+ #ifdef HAVE_RUBY_ENCODING_H
324+ params_enc [i ] = rb_str_export_to_enc (params_enc [i ], conn_enc );
325+ #endif
326+ set_buffer_for_string (& bind_buffers [i ], & length_buffers [i ], params_enc [i ]);
327+ }
328+ }
271329 break ;
272330 case T_FLOAT :
273331 bind_buffers [i ].buffer_type = MYSQL_TYPE_DOUBLE ;
@@ -501,4 +559,7 @@ void init_mysql2_statement() {
501559 intern_year = rb_intern ("year" );
502560
503561 intern_to_s = rb_intern ("to_s" );
562+ #ifndef HAVE_RB_BIG_CMP
563+ id_cmp = rb_intern ("cmp" );
564+ #endif
504565}
0 commit comments