@@ -17,6 +17,20 @@ static rb_encoding *binaryEncoding;
17
17
*/
18
18
#define MYSQL2_MIN_TIME 2678400ULL
19
19
20
+ #define MYSQL2_MAX_BYTES_PER_CHAR 3
21
+
22
+ /* From Mysql documentations:
23
+ * To distinguish between binary and nonbinary data for string data types,
24
+ * check whether the charsetnr value is 63. If so, the character set is binary,
25
+ * which indicates binary rather than nonbinary data. This enables you to distinguish BINARY
26
+ * from CHAR, VARBINARY from VARCHAR, and the BLOB types from the TEXT types.
27
+ */
28
+ #define MYSQL2_BINARY_CHARSET 63
29
+
30
+ #ifndef MYSQL_TYPE_JSON
31
+ #define MYSQL_TYPE_JSON 245
32
+ #endif
33
+
20
34
#define GET_RESULT (self ) \
21
35
mysql2_result_wrapper *wrapper; \
22
36
Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
@@ -169,9 +183,171 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
169
183
return rb_field ;
170
184
}
171
185
186
+ static VALUE rb_mysql_result_fetch_field_type (VALUE self , unsigned int idx ) {
187
+ VALUE rb_field_type ;
188
+ GET_RESULT (self );
189
+
190
+ if (wrapper -> fieldTypes == Qnil ) {
191
+ wrapper -> numberOfFields = mysql_num_fields (wrapper -> result );
192
+ wrapper -> fieldTypes = rb_ary_new2 (wrapper -> numberOfFields );
193
+ }
194
+
195
+ rb_field_type = rb_ary_entry (wrapper -> fieldTypes , idx );
196
+ if (rb_field_type == Qnil ) {
197
+ MYSQL_FIELD * field = NULL ;
198
+ rb_encoding * default_internal_enc = rb_default_internal_encoding ();
199
+ rb_encoding * conn_enc = rb_to_encoding (wrapper -> encoding );
200
+ int precision ;
201
+
202
+ field = mysql_fetch_field_direct (wrapper -> result , idx );
203
+
204
+ switch (field -> type ) {
205
+ case MYSQL_TYPE_NULL : // NULL
206
+ rb_field_type = rb_str_new_cstr ("null" );
207
+ break ;
208
+ case MYSQL_TYPE_TINY : // signed char
209
+ rb_field_type = rb_sprintf ("tinyint(%ld)" , field -> length );
210
+ break ;
211
+ case MYSQL_TYPE_SHORT : // short int
212
+ rb_field_type = rb_sprintf ("smallint(%ld)" , field -> length );
213
+ break ;
214
+ case MYSQL_TYPE_YEAR : // short int
215
+ rb_field_type = rb_sprintf ("year(%ld)" , field -> length );
216
+ break ;
217
+ case MYSQL_TYPE_INT24 : // int
218
+ rb_field_type = rb_sprintf ("mediumint(%ld)" , field -> length );
219
+ break ;
220
+ case MYSQL_TYPE_LONG : // int
221
+ rb_field_type = rb_sprintf ("int(%ld)" , field -> length );
222
+ break ;
223
+ case MYSQL_TYPE_LONGLONG : // long long int
224
+ rb_field_type = rb_sprintf ("bigint(%ld)" , field -> length );
225
+ break ;
226
+ case MYSQL_TYPE_FLOAT : // float
227
+ rb_field_type = rb_sprintf ("float(%ld,%d)" , field -> length , field -> decimals );
228
+ break ;
229
+ case MYSQL_TYPE_DOUBLE : // double
230
+ rb_field_type = rb_sprintf ("double(%ld,%d)" , field -> length , field -> decimals );
231
+ break ;
232
+ case MYSQL_TYPE_TIME : // MYSQL_TIME
233
+ rb_field_type = rb_str_new_cstr ("time" );
234
+ break ;
235
+ case MYSQL_TYPE_DATE : // MYSQL_TIME
236
+ case MYSQL_TYPE_NEWDATE : // MYSQL_TIME
237
+ rb_field_type = rb_str_new_cstr ("date" );
238
+ break ;
239
+ case MYSQL_TYPE_DATETIME : // MYSQL_TIME
240
+ rb_field_type = rb_str_new_cstr ("datetime" );
241
+ break ;
242
+ case MYSQL_TYPE_TIMESTAMP : // MYSQL_TIME
243
+ rb_field_type = rb_str_new_cstr ("timestamp" );
244
+ break ;
245
+ case MYSQL_TYPE_DECIMAL : // char[]
246
+ case MYSQL_TYPE_NEWDECIMAL : // char[]
247
+ /*
248
+ Handle precision similar to this line from mysql's code:
249
+ https://github.com/mysql/mysql-server/blob/ea7d2e2d16ac03afdd9cb72a972a95981107bf51/sql/field.cc#L2246
250
+ */
251
+ precision = field -> length - (field -> decimals > 0 ? 2 : 1 );
252
+ rb_field_type = rb_sprintf ("decimal(%ld,%d)" , precision , field -> decimals );
253
+ break ;
254
+ case MYSQL_TYPE_STRING : // char[]
255
+ if (field -> flags & ENUM_FLAG ) {
256
+ rb_field_type = rb_str_new_cstr ("enum" );
257
+ } else if (field -> flags & SET_FLAG ) {
258
+ rb_field_type = rb_str_new_cstr ("set" );
259
+ } else {
260
+ if (field -> charsetnr == MYSQL2_BINARY_CHARSET ) {
261
+ rb_field_type = rb_sprintf ("binary(%ld)" , field -> length );
262
+ } else {
263
+ rb_field_type = rb_sprintf ("char(%ld)" , field -> length / MYSQL2_MAX_BYTES_PER_CHAR );
264
+ }
265
+ }
266
+ break ;
267
+ case MYSQL_TYPE_VAR_STRING : // char[]
268
+ if (field -> charsetnr == MYSQL2_BINARY_CHARSET ) {
269
+ rb_field_type = rb_sprintf ("varbinary(%ld)" , field -> length );
270
+ } else {
271
+ rb_field_type = rb_sprintf ("varchar(%ld)" , field -> length / MYSQL2_MAX_BYTES_PER_CHAR );
272
+ }
273
+ break ;
274
+ case MYSQL_TYPE_VARCHAR : // char[]
275
+ rb_field_type = rb_sprintf ("varchar(%ld)" , field -> length / MYSQL2_MAX_BYTES_PER_CHAR );
276
+ break ;
277
+ case MYSQL_TYPE_TINY_BLOB : // char[]
278
+ rb_field_type = rb_str_new_cstr ("tinyblob" );
279
+ break ;
280
+ case MYSQL_TYPE_BLOB : // char[]
281
+ if (field -> charsetnr == MYSQL2_BINARY_CHARSET ) {
282
+ switch (field -> length ) {
283
+ case 255 :
284
+ rb_field_type = rb_str_new_cstr ("tinyblob" );
285
+ break ;
286
+ case 65535 :
287
+ rb_field_type = rb_str_new_cstr ("blob" );
288
+ break ;
289
+ case 16777215 :
290
+ rb_field_type = rb_str_new_cstr ("mediumblob" );
291
+ break ;
292
+ case 4294967295 :
293
+ rb_field_type = rb_str_new_cstr ("longblob" );
294
+ default :
295
+ break ;
296
+ }
297
+ } else {
298
+ if (field -> length == (255 * MYSQL2_MAX_BYTES_PER_CHAR )) {
299
+ rb_field_type = rb_str_new_cstr ("tinytext" );
300
+ } else if (field -> length == (65535 * MYSQL2_MAX_BYTES_PER_CHAR )) {
301
+ rb_field_type = rb_str_new_cstr ("text" );
302
+ } else if (field -> length == (16777215 * MYSQL2_MAX_BYTES_PER_CHAR )) {
303
+ rb_field_type = rb_str_new_cstr ("mediumtext" );
304
+ } else if (field -> length == 4294967295 ) {
305
+ rb_field_type = rb_str_new_cstr ("longtext" );
306
+ } else {
307
+ rb_field_type = rb_sprintf ("text(%ld)" , field -> length );
308
+ }
309
+ }
310
+ break ;
311
+ case MYSQL_TYPE_MEDIUM_BLOB : // char[]
312
+ rb_field_type = rb_str_new_cstr ("mediumblob" );
313
+ break ;
314
+ case MYSQL_TYPE_LONG_BLOB : // char[]
315
+ rb_field_type = rb_str_new_cstr ("longblob" );
316
+ break ;
317
+ case MYSQL_TYPE_BIT : // char[]
318
+ rb_field_type = rb_sprintf ("bit(%ld)" , field -> length );
319
+ break ;
320
+ case MYSQL_TYPE_SET : // char[]
321
+ rb_field_type = rb_str_new_cstr ("set" );
322
+ break ;
323
+ case MYSQL_TYPE_ENUM : // char[]
324
+ rb_field_type = rb_str_new_cstr ("enum" );
325
+ break ;
326
+ case MYSQL_TYPE_GEOMETRY : // char[]
327
+ rb_field_type = rb_str_new_cstr ("geometry" );
328
+ break ;
329
+ case MYSQL_TYPE_JSON : // json
330
+ rb_field_type = rb_str_new_cstr ("json" );
331
+ break ;
332
+ default :
333
+ rb_field_type = rb_str_new_cstr ("unknown" );
334
+ break ;
335
+ }
336
+
337
+ rb_enc_associate (rb_field_type , conn_enc );
338
+ if (default_internal_enc ) {
339
+ rb_field_type = rb_str_export_to_enc (rb_field_type , default_internal_enc );
340
+ }
341
+
342
+ rb_ary_store (wrapper -> fieldTypes , idx , rb_field_type );
343
+ }
344
+
345
+ return rb_field_type ;
346
+ }
347
+
172
348
static VALUE mysql2_set_field_string_encoding (VALUE val , MYSQL_FIELD field , rb_encoding * default_internal_enc , rb_encoding * conn_enc ) {
173
349
/* if binary flag is set, respect its wishes */
174
- if (field .flags & BINARY_FLAG && field .charsetnr == 63 ) {
350
+ if (field .flags & BINARY_FLAG && field .charsetnr == MYSQL2_BINARY_CHARSET ) {
175
351
rb_enc_associate (val , binaryEncoding );
176
352
} else if (!field .charsetnr ) {
177
353
/* MySQL 4.x may not provide an encoding, binary will get the bytes through */
@@ -716,6 +892,25 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
716
892
return wrapper -> fields ;
717
893
}
718
894
895
+ static VALUE rb_mysql_result_fetch_field_types (VALUE self ) {
896
+ unsigned int i = 0 ;
897
+
898
+ GET_RESULT (self );
899
+
900
+ if (wrapper -> fieldTypes == Qnil ) {
901
+ wrapper -> numberOfFields = mysql_num_fields (wrapper -> result );
902
+ wrapper -> fieldTypes = rb_ary_new2 (wrapper -> numberOfFields );
903
+ }
904
+
905
+ if ((my_ulonglong )RARRAY_LEN (wrapper -> fieldTypes ) != wrapper -> numberOfFields ) {
906
+ for (i = 0 ; i < wrapper -> numberOfFields ; i ++ ) {
907
+ rb_mysql_result_fetch_field_type (self , i );
908
+ }
909
+ }
910
+
911
+ return wrapper -> fieldTypes ;
912
+ }
913
+
719
914
static VALUE rb_mysql_result_each_ (VALUE self ,
720
915
VALUE (* fetch_row_func )(VALUE , MYSQL_FIELD * fields , const result_each_args * args ),
721
916
const result_each_args * args )
@@ -934,6 +1129,7 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
934
1129
wrapper -> resultFreed = 0 ;
935
1130
wrapper -> result = r ;
936
1131
wrapper -> fields = Qnil ;
1132
+ wrapper -> fieldTypes = Qnil ;
937
1133
wrapper -> rows = Qnil ;
938
1134
wrapper -> encoding = encoding ;
939
1135
wrapper -> streamingComplete = 0 ;
@@ -971,6 +1167,7 @@ void init_mysql2_result() {
971
1167
cMysql2Result = rb_define_class_under (mMysql2 , "Result" , rb_cObject );
972
1168
rb_define_method (cMysql2Result , "each" , rb_mysql_result_each , -1 );
973
1169
rb_define_method (cMysql2Result , "fields" , rb_mysql_result_fetch_fields , 0 );
1170
+ rb_define_method (cMysql2Result , "field_types" , rb_mysql_result_fetch_field_types , 0 );
974
1171
rb_define_method (cMysql2Result , "free" , rb_mysql_result_free_ , 0 );
975
1172
rb_define_method (cMysql2Result , "count" , rb_mysql_result_count , 0 );
976
1173
rb_define_alias (cMysql2Result , "size" , "count" );
0 commit comments