mysql2 0.4.6-x64-mingw32 → 0.4.7-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +57 -42
- data/ext/mysql2/client.c +55 -23
- data/ext/mysql2/client.h +1 -2
- data/ext/mysql2/extconf.rb +5 -2
- data/ext/mysql2/mysql2_ext.h +2 -0
- data/ext/mysql2/statement.c +13 -2
- data/lib/mysql2/2.0/mysql2.so +0 -0
- data/lib/mysql2/2.1/mysql2.so +0 -0
- data/lib/mysql2/2.2/mysql2.so +0 -0
- data/lib/mysql2/2.3/mysql2.so +0 -0
- data/lib/mysql2/client.rb +3 -3
- data/lib/mysql2/version.rb +1 -1
- data/spec/em/em_spec.rb +1 -0
- data/spec/mysql2/client_spec.rb +119 -72
- data/spec/mysql2/error_spec.rb +3 -5
- data/spec/mysql2/result_spec.rb +7 -12
- data/spec/mysql2/statement_spec.rb +13 -15
- data/spec/spec_helper.rb +73 -59
- data/vendor/libmysql.dll +0 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 453a3e20e7f3dbb02c72c486e02415d905720f93
|
4
|
+
data.tar.gz: dd0f4dc57756cbcccc72517b5c87d538eb5f3318
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9cc3d554e47ab6f68cae1bbc58501a444058f0e2b97f0c3995fbc3a24568417045d0ad53097d600968bcfbf4a7e5c67bf754e3f303cb35ae8041385e3aea8e1
|
7
|
+
data.tar.gz: a54f879bc8a39fdc1be5148e7ff0ed02093931ca55e44f30140b921d3f6c6900168f87a39ccff1134232afe9c7f0386a2c77286a5ccc835d02cc6f81dd9ad38f
|
data/README.md
CHANGED
@@ -112,7 +112,7 @@ Connect to a database:
|
|
112
112
|
``` ruby
|
113
113
|
# this takes a hash of options, almost all of which map directly
|
114
114
|
# to the familiar database.yml in rails
|
115
|
-
# See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/
|
115
|
+
# See http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html
|
116
116
|
client = Mysql2::Client.new(:host => "localhost", :username => "root")
|
117
117
|
```
|
118
118
|
|
@@ -213,6 +213,21 @@ Mysql2::Client.new(
|
|
213
213
|
)
|
214
214
|
```
|
215
215
|
|
216
|
+
### Connecting to localhost
|
217
|
+
|
218
|
+
The underlying MySQL client library has a special interpretation of the "localhost" default connection host name:
|
219
|
+
|
220
|
+
1. Attempt to connect via local socket (as specified in your distribution's my.cnf or `default_file` config file).
|
221
|
+
2. But if the socket is not available, look up "localhost" to find an IP address...
|
222
|
+
* The file "/etc/hosts" is generally the source of truth for "localhost", and can override its value.
|
223
|
+
* Systems with IPv4 use "127.0.0.1"
|
224
|
+
* Systems with IPv6 use "::1"
|
225
|
+
* Systems with both IPv4 and IPv6 can be configured to prefer one or the other.
|
226
|
+
3. If an address is found for "localhost", connect to it over TCP/IP.
|
227
|
+
|
228
|
+
You can be explicit about using either a local socket or a TCP/IP connection,
|
229
|
+
and whether to use IPv4 or IPv6, by specifying a value other than "localhost"
|
230
|
+
for the `host` or `socket` connection options.
|
216
231
|
|
217
232
|
### SSL options
|
218
233
|
|
@@ -235,47 +250,6 @@ Mysql2::Client.new(
|
|
235
250
|
)
|
236
251
|
```
|
237
252
|
|
238
|
-
### Multiple result sets
|
239
|
-
|
240
|
-
You can also retrieve multiple result sets. For this to work you need to
|
241
|
-
connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
|
242
|
-
be used with stored procedures that return more than one result set, and for
|
243
|
-
bundling several SQL statements into a single call to `client.query`.
|
244
|
-
|
245
|
-
``` ruby
|
246
|
-
client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
|
247
|
-
result = client.query('CALL sp_customer_list( 25, 10 )')
|
248
|
-
# result now contains the first result set
|
249
|
-
while client.next_result
|
250
|
-
result = client.store_result
|
251
|
-
# result now contains the next result set
|
252
|
-
end
|
253
|
-
```
|
254
|
-
|
255
|
-
Repeated calls to `client.next_result` will return true, false, or raise an
|
256
|
-
exception if the respective query erred. When `client.next_result` returns true,
|
257
|
-
call `client.store_result` to retrieve a result object. Exceptions are not
|
258
|
-
raised until `client.next_result` is called to find the status of the respective
|
259
|
-
query. Subsequent queries are not executed if an earlier query raised an
|
260
|
-
exception. Subsequent calls to `client.next_result` will return false.
|
261
|
-
|
262
|
-
``` ruby
|
263
|
-
result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
|
264
|
-
p result.first
|
265
|
-
|
266
|
-
while client.next_result
|
267
|
-
result = client.store_result
|
268
|
-
p result.first
|
269
|
-
end
|
270
|
-
```
|
271
|
-
|
272
|
-
Yields:
|
273
|
-
```
|
274
|
-
{"1"=>1}
|
275
|
-
{"2"=>2}
|
276
|
-
next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
|
277
|
-
```
|
278
|
-
|
279
253
|
### Secure auth
|
280
254
|
|
281
255
|
Starting wih MySQL 5.6.5, secure_auth is enabled by default on servers (it was disabled by default prior to this).
|
@@ -332,6 +306,47 @@ It is useful if you want to provide session options which survive reconnection.
|
|
332
306
|
Mysql2::Client.new(:init_command => "SET @@SESSION.sql_mode = 'STRICT_ALL_TABLES'")
|
333
307
|
```
|
334
308
|
|
309
|
+
### Multiple result sets
|
310
|
+
|
311
|
+
You can also retrieve multiple result sets. For this to work you need to
|
312
|
+
connect with flags `Mysql2::Client::MULTI_STATEMENTS`. Multiple result sets can
|
313
|
+
be used with stored procedures that return more than one result set, and for
|
314
|
+
bundling several SQL statements into a single call to `client.query`.
|
315
|
+
|
316
|
+
``` ruby
|
317
|
+
client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS)
|
318
|
+
result = client.query('CALL sp_customer_list( 25, 10 )')
|
319
|
+
# result now contains the first result set
|
320
|
+
while client.next_result
|
321
|
+
result = client.store_result
|
322
|
+
# result now contains the next result set
|
323
|
+
end
|
324
|
+
```
|
325
|
+
|
326
|
+
Repeated calls to `client.next_result` will return true, false, or raise an
|
327
|
+
exception if the respective query erred. When `client.next_result` returns true,
|
328
|
+
call `client.store_result` to retrieve a result object. Exceptions are not
|
329
|
+
raised until `client.next_result` is called to find the status of the respective
|
330
|
+
query. Subsequent queries are not executed if an earlier query raised an
|
331
|
+
exception. Subsequent calls to `client.next_result` will return false.
|
332
|
+
|
333
|
+
``` ruby
|
334
|
+
result = client.query('SELECT 1; SELECT 2; SELECT A; SELECT 3')
|
335
|
+
p result.first
|
336
|
+
|
337
|
+
while client.next_result
|
338
|
+
result = client.store_result
|
339
|
+
p result.first
|
340
|
+
end
|
341
|
+
```
|
342
|
+
|
343
|
+
Yields:
|
344
|
+
```
|
345
|
+
{"1"=>1}
|
346
|
+
{"2"=>2}
|
347
|
+
next_result: Unknown column 'A' in 'field list' (Mysql2::Error)
|
348
|
+
```
|
349
|
+
|
335
350
|
## Cascading config
|
336
351
|
|
337
352
|
The default config hash is at:
|
data/ext/mysql2/client.c
CHANGED
@@ -30,15 +30,21 @@ VALUE rb_hash_dup(VALUE other) {
|
|
30
30
|
rb_raise(cMysql2Error, "MySQL client is not initialized"); \
|
31
31
|
}
|
32
32
|
|
33
|
+
#if defined(HAVE_MYSQL_NET_VIO) || defined(HAVE_ST_NET_VIO)
|
34
|
+
#define CONNECTED(wrapper) (wrapper->client->net.vio != NULL && wrapper->client->net.fd != -1)
|
35
|
+
#elif defined(HAVE_MYSQL_NET_PVIO) || defined(HAVE_ST_NET_PVIO)
|
36
|
+
#define CONNECTED(wrapper) (wrapper->client->net.pvio != NULL && wrapper->client->net.fd != -1)
|
37
|
+
#endif
|
38
|
+
|
33
39
|
#define REQUIRE_CONNECTED(wrapper) \
|
34
40
|
REQUIRE_INITIALIZED(wrapper) \
|
35
|
-
if (!wrapper
|
41
|
+
if (!CONNECTED(wrapper) && !wrapper->reconnect_enabled) { \
|
36
42
|
rb_raise(cMysql2Error, "MySQL client is not connected"); \
|
37
43
|
}
|
38
44
|
|
39
45
|
#define REQUIRE_NOT_CONNECTED(wrapper) \
|
40
46
|
REQUIRE_INITIALIZED(wrapper) \
|
41
|
-
if (wrapper
|
47
|
+
if (CONNECTED(wrapper)) { \
|
42
48
|
rb_raise(cMysql2Error, "MySQL connection is already open"); \
|
43
49
|
}
|
44
50
|
|
@@ -107,14 +113,13 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
107
113
|
return Qnil;
|
108
114
|
}
|
109
115
|
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
|
110
|
-
GET_CLIENT(self);
|
116
|
+
GET_CLIENT(self);
|
111
117
|
int val = NUM2INT( setting );
|
112
118
|
if (version >= 50703 && version < 50711) {
|
113
119
|
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
|
114
120
|
bool b = ( val == SSL_MODE_REQUIRED );
|
115
121
|
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
|
116
122
|
return INT2NUM(result);
|
117
|
-
|
118
123
|
} else {
|
119
124
|
rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
|
120
125
|
return Qnil;
|
@@ -122,7 +127,7 @@ static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
|
|
122
127
|
}
|
123
128
|
#endif
|
124
129
|
#ifdef FULL_SSL_MODE_SUPPORT
|
125
|
-
GET_CLIENT(self);
|
130
|
+
GET_CLIENT(self);
|
126
131
|
int val = NUM2INT( setting );
|
127
132
|
|
128
133
|
if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
|
@@ -264,11 +269,10 @@ static VALUE invalidate_fd(int clientfd)
|
|
264
269
|
static void *nogvl_close(void *ptr) {
|
265
270
|
mysql_client_wrapper *wrapper = ptr;
|
266
271
|
|
267
|
-
if (wrapper->
|
272
|
+
if (!wrapper->closed) {
|
268
273
|
mysql_close(wrapper->client);
|
269
|
-
|
270
|
-
wrapper->
|
271
|
-
wrapper->connected = 0;
|
274
|
+
wrapper->closed = 1;
|
275
|
+
wrapper->reconnect_enabled = 0;
|
272
276
|
wrapper->active_thread = Qnil;
|
273
277
|
}
|
274
278
|
|
@@ -287,7 +291,7 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
|
287
291
|
|
288
292
|
if (wrapper->refcount == 0) {
|
289
293
|
#ifndef _WIN32
|
290
|
-
if (wrapper
|
294
|
+
if (CONNECTED(wrapper) && !wrapper->automatic_close) {
|
291
295
|
/* The client is being garbage collected while connected. Prevent
|
292
296
|
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
|
293
297
|
* the socket by invalidating it. invalidate_fd() will drop this
|
@@ -299,10 +303,12 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
|
|
299
303
|
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely\n");
|
300
304
|
close(wrapper->client->net.fd);
|
301
305
|
}
|
306
|
+
wrapper->client->net.fd = -1;
|
302
307
|
}
|
303
308
|
#endif
|
304
309
|
|
305
310
|
nogvl_close(wrapper);
|
311
|
+
xfree(wrapper->client);
|
306
312
|
xfree(wrapper);
|
307
313
|
}
|
308
314
|
}
|
@@ -317,9 +323,9 @@ static VALUE allocate(VALUE klass) {
|
|
317
323
|
wrapper->server_version = 0;
|
318
324
|
wrapper->reconnect_enabled = 0;
|
319
325
|
wrapper->connect_timeout = 0;
|
320
|
-
wrapper->connected = 0; /* means that a database connection is open */
|
321
326
|
wrapper->initialized = 0; /* means that that the wrapper is initialized */
|
322
327
|
wrapper->refcount = 1;
|
328
|
+
wrapper->closed = 0;
|
323
329
|
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
|
324
330
|
|
325
331
|
return obj;
|
@@ -450,7 +456,6 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
450
456
|
}
|
451
457
|
|
452
458
|
wrapper->server_version = mysql_get_server_version(wrapper->client);
|
453
|
-
wrapper->connected = 1;
|
454
459
|
return self;
|
455
460
|
}
|
456
461
|
|
@@ -465,13 +470,23 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
465
470
|
static VALUE rb_mysql_client_close(VALUE self) {
|
466
471
|
GET_CLIENT(self);
|
467
472
|
|
468
|
-
if (wrapper->
|
473
|
+
if (wrapper->client) {
|
469
474
|
rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
470
475
|
}
|
471
476
|
|
472
477
|
return Qnil;
|
473
478
|
}
|
474
479
|
|
480
|
+
/* call-seq:
|
481
|
+
* client.closed?
|
482
|
+
*
|
483
|
+
* @return [Boolean]
|
484
|
+
*/
|
485
|
+
static VALUE rb_mysql_client_closed(VALUE self) {
|
486
|
+
GET_CLIENT(self);
|
487
|
+
return CONNECTED(wrapper) ? Qfalse : Qtrue;
|
488
|
+
}
|
489
|
+
|
475
490
|
/*
|
476
491
|
* mysql_send_query is unlikely to block since most queries are small
|
477
492
|
* enough to fit in a socket buffer, but sometimes large UPDATE and
|
@@ -591,16 +606,16 @@ static VALUE disconnect_and_raise(VALUE self, VALUE error) {
|
|
591
606
|
GET_CLIENT(self);
|
592
607
|
|
593
608
|
wrapper->active_thread = Qnil;
|
594
|
-
wrapper->connected = 0;
|
595
609
|
|
596
610
|
/* Invalidate the MySQL socket to prevent further communication.
|
597
611
|
* The GC will come along later and call mysql_close to free it.
|
598
612
|
*/
|
599
|
-
if (wrapper
|
613
|
+
if (CONNECTED(wrapper)) {
|
600
614
|
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
601
615
|
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, closing unsafely\n");
|
602
616
|
close(wrapper->client->net.fd);
|
603
617
|
}
|
618
|
+
wrapper->client->net.fd = -1;
|
604
619
|
}
|
605
620
|
|
606
621
|
rb_exc_raise(error);
|
@@ -656,19 +671,21 @@ static VALUE disconnect_and_mark_inactive(VALUE self) {
|
|
656
671
|
|
657
672
|
/* Check if execution terminated while result was still being read. */
|
658
673
|
if (!NIL_P(wrapper->active_thread)) {
|
659
|
-
|
674
|
+
if (CONNECTED(wrapper)) {
|
675
|
+
/* Invalidate the MySQL socket to prevent further communication. */
|
660
676
|
#ifndef _WIN32
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
677
|
+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
|
678
|
+
rb_warn("mysql2 failed to invalidate FD safely, closing unsafely\n");
|
679
|
+
close(wrapper->client->net.fd);
|
680
|
+
}
|
665
681
|
#else
|
666
|
-
|
682
|
+
close(wrapper->client->net.fd);
|
667
683
|
#endif
|
684
|
+
wrapper->client->net.fd = -1;
|
685
|
+
}
|
668
686
|
/* Skip mysql client check performed before command execution. */
|
669
687
|
wrapper->client->status = MYSQL_STATUS_READY;
|
670
688
|
wrapper->active_thread = Qnil;
|
671
|
-
wrapper->connected = 0;
|
672
689
|
}
|
673
690
|
|
674
691
|
return Qnil;
|
@@ -886,6 +903,11 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
|
|
886
903
|
retval = charval;
|
887
904
|
break;
|
888
905
|
|
906
|
+
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
|
907
|
+
boolval = (value == Qfalse ? 0 : 1);
|
908
|
+
retval = &boolval;
|
909
|
+
break;
|
910
|
+
|
889
911
|
default:
|
890
912
|
return Qfalse;
|
891
913
|
}
|
@@ -1075,7 +1097,7 @@ static void *nogvl_ping(void *ptr) {
|
|
1075
1097
|
static VALUE rb_mysql_client_ping(VALUE self) {
|
1076
1098
|
GET_CLIENT(self);
|
1077
1099
|
|
1078
|
-
if (!wrapper
|
1100
|
+
if (!CONNECTED(wrapper)) {
|
1079
1101
|
return Qfalse;
|
1080
1102
|
} else {
|
1081
1103
|
return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
|
@@ -1303,6 +1325,10 @@ static VALUE set_init_command(VALUE self, VALUE value) {
|
|
1303
1325
|
return _mysql_client_options(self, MYSQL_INIT_COMMAND, value);
|
1304
1326
|
}
|
1305
1327
|
|
1328
|
+
static VALUE set_enable_cleartext_plugin(VALUE self, VALUE value) {
|
1329
|
+
return _mysql_client_options(self, MYSQL_ENABLE_CLEARTEXT_PLUGIN, value);
|
1330
|
+
}
|
1331
|
+
|
1306
1332
|
static VALUE initialize_ext(VALUE self) {
|
1307
1333
|
GET_CLIENT(self);
|
1308
1334
|
|
@@ -1363,6 +1389,7 @@ void init_mysql2_client() {
|
|
1363
1389
|
rb_define_singleton_method(cMysql2Client, "info", rb_mysql_client_info, 0);
|
1364
1390
|
|
1365
1391
|
rb_define_method(cMysql2Client, "close", rb_mysql_client_close, 0);
|
1392
|
+
rb_define_method(cMysql2Client, "closed?", rb_mysql_client_closed, 0);
|
1366
1393
|
rb_define_method(cMysql2Client, "abandon_results!", rb_mysql_client_abandon_results, 0);
|
1367
1394
|
rb_define_method(cMysql2Client, "escape", rb_mysql_client_real_escape, 1);
|
1368
1395
|
rb_define_method(cMysql2Client, "server_info", rb_mysql_client_server_info, 0);
|
@@ -1398,6 +1425,7 @@ void init_mysql2_client() {
|
|
1398
1425
|
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
|
1399
1426
|
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
|
1400
1427
|
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
|
1428
|
+
rb_define_private_method(cMysql2Client, "enable_cleartext_plugin=", set_enable_cleartext_plugin, 1);
|
1401
1429
|
rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
|
1402
1430
|
rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
|
1403
1431
|
rb_define_private_method(cMysql2Client, "_query", rb_query, 2);
|
@@ -1419,6 +1447,10 @@ void init_mysql2_client() {
|
|
1419
1447
|
#ifdef CLIENT_LONG_PASSWORD
|
1420
1448
|
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"),
|
1421
1449
|
LONG2NUM(CLIENT_LONG_PASSWORD));
|
1450
|
+
#else
|
1451
|
+
/* HACK because MariaDB 10.2 no longer defines this constant,
|
1452
|
+
* but we're using it in our default connection flags. */
|
1453
|
+
rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0));
|
1422
1454
|
#endif
|
1423
1455
|
|
1424
1456
|
#ifdef CLIENT_FOUND_ROWS
|
data/ext/mysql2/client.h
CHANGED
data/ext/mysql2/extconf.rb
CHANGED
@@ -105,13 +105,16 @@ else
|
|
105
105
|
asplode 'mysql.h'
|
106
106
|
end
|
107
107
|
|
108
|
-
add_ssl_defines([prefix, 'mysql.h'].compact.join('/'))
|
109
|
-
|
110
108
|
%w(errmsg.h mysqld_error.h).each do |h|
|
111
109
|
header = [prefix, h].compact.join '/'
|
112
110
|
asplode h unless have_header header
|
113
111
|
end
|
114
112
|
|
113
|
+
mysql_h = [prefix, 'mysql.h'].compact.join('/')
|
114
|
+
add_ssl_defines(mysql_h)
|
115
|
+
have_struct_member('MYSQL', 'net.vio', mysql_h)
|
116
|
+
have_struct_member('MYSQL', 'net.pvio', mysql_h)
|
117
|
+
|
115
118
|
# This is our wishlist. We use whichever flags work on the host.
|
116
119
|
# -Wall and -Wextra are included by default.
|
117
120
|
wishlist = [
|
data/ext/mysql2/mysql2_ext.h
CHANGED
@@ -14,11 +14,13 @@ void Init_mysql2(void);
|
|
14
14
|
#include <mysql_com.h>
|
15
15
|
#include <errmsg.h>
|
16
16
|
#include <mysqld_error.h>
|
17
|
+
#include <mysql_version.h>
|
17
18
|
#else
|
18
19
|
#include <mysql/mysql.h>
|
19
20
|
#include <mysql/mysql_com.h>
|
20
21
|
#include <mysql/errmsg.h>
|
21
22
|
#include <mysql/mysqld_error.h>
|
23
|
+
#include <mysql/mysql_version.h>
|
22
24
|
#endif
|
23
25
|
|
24
26
|
#ifdef HAVE_RUBY_ENCODING_H
|
data/ext/mysql2/statement.c
CHANGED
@@ -468,6 +468,7 @@ static VALUE fields(VALUE self) {
|
|
468
468
|
rb_encoding *default_internal_enc, *conn_enc;
|
469
469
|
#endif
|
470
470
|
GET_STATEMENT(self);
|
471
|
+
GET_CLIENT(stmt_wrapper->client);
|
471
472
|
stmt = stmt_wrapper->stmt;
|
472
473
|
|
473
474
|
#ifdef HAVE_RUBY_ENCODING_H
|
@@ -478,12 +479,22 @@ static VALUE fields(VALUE self) {
|
|
478
479
|
}
|
479
480
|
#endif
|
480
481
|
|
481
|
-
metadata
|
482
|
+
metadata = mysql_stmt_result_metadata(stmt);
|
483
|
+
if (metadata == NULL) {
|
484
|
+
if (mysql_stmt_errno(stmt) != 0) {
|
485
|
+
// either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
|
486
|
+
wrapper->active_thread = Qnil;
|
487
|
+
rb_raise_mysql2_stmt_error(stmt_wrapper);
|
488
|
+
}
|
489
|
+
// no data and no error, so query was not a SELECT
|
490
|
+
return Qnil;
|
491
|
+
}
|
492
|
+
|
482
493
|
fields = mysql_fetch_fields(metadata);
|
483
494
|
field_count = mysql_stmt_field_count(stmt);
|
484
495
|
field_list = rb_ary_new2((long)field_count);
|
485
496
|
|
486
|
-
for(i = 0; i < field_count; i++) {
|
497
|
+
for (i = 0; i < field_count; i++) {
|
487
498
|
VALUE rb_field;
|
488
499
|
|
489
500
|
rb_field = rb_str_new(fields[i].name, fields[i].name_length);
|