@@ -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; \
@@ -204,6 +207,47 @@ static void set_buffer_for_string(MYSQL_BIND* bind_buffer, unsigned long *length
204
207
xfree(length_buffers); \
205
208
}
206
209
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
+
207
251
/* call-seq: stmt.execute
208
252
*
209
253
* Executes the current prepared statement, returns +result+.
@@ -265,9 +309,23 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
265
309
#endif
266
310
break ;
267
311
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
+ }
271
329
break ;
272
330
case T_FLOAT :
273
331
bind_buffers [i ].buffer_type = MYSQL_TYPE_DOUBLE ;
@@ -501,4 +559,7 @@ void init_mysql2_statement() {
501
559
intern_year = rb_intern ("year" );
502
560
503
561
intern_to_s = rb_intern ("to_s" );
562
+ #ifndef HAVE_RB_BIG_CMP
563
+ id_cmp = rb_intern ("cmp" );
564
+ #endif
504
565
}
0 commit comments