Skip to content

Commit 1af1061

Browse files
committed
Merge branch 'master' into 0.2.x
2 parents 30b2592 + 773c568 commit 1af1061

File tree

12 files changed

+240
-64
lines changed

12 files changed

+240
-64
lines changed

.travis.yml

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,55 @@ language: ruby
22
bundler_args: --without benchmarks
33
script:
44
- bundle exec rake spec
5-
# Temporary workaround for broken Rubygems on Travis
65
before_install:
7-
- gem update --system 2.1.11
86
- gem --version
7+
- |
8+
bash -c " # Install MySQL 5.7 if DB=mysql57
9+
if [[ x$DB =~ mysql57 ]]; then
10+
sudo bash .travis_mysql57.sh
11+
fi
12+
"
913
- |
1014
bash -c " # Install MariaDB if DB=mariadb
1115
if [[ x$DB =~ xmariadb ]]; then
12-
sudo service mysql stop
13-
sudo apt-get purge '^mysql*' 'libmysql*'
14-
sudo apt-get install python-software-properties
15-
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
16-
if [[ x$DB = xmariadb55 ]]; then
17-
sudo add-apt-repository 'deb http://ftp.osuosl.org/pub/mariadb/repo/5.5/ubuntu precise main'
18-
elif [[ x$DB = xmariadb10 ]]; then
19-
sudo add-apt-repository 'deb http://ftp.osuosl.org/pub/mariadb/repo/10.0/ubuntu precise main'
20-
fi
21-
sudo apt-get update
22-
sudo apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -y install mariadb-server libmariadbd-dev
16+
sudo bash .travis_mariadb.sh '$DB'
17+
fi
18+
"
19+
- |
20+
bash -c " # Install MySQL is OS=darwin
21+
if [[ x$OSTYPE =~ ^xdarwin ]]; then
22+
brew install mysql
23+
mysql.server start
2324
fi
2425
"
26+
- |
27+
bash -c " # Configure SSL support
28+
sudo bash .travis_ssl.sh
29+
"
2530
- mysqld --version
31+
- mysql -u root -e "CREATE DATABASE IF NOT EXISTS test"
32+
- mysql -u root -e "CREATE USER '$USER'@'localhost'" || true
33+
os:
34+
- linux
2635
rvm:
2736
- 1.8.7
2837
- 1.9.2
2938
- 1.9.3
3039
- 2.0.0
31-
- 2.1.1
40+
- 2.1.4
3241
- ree
3342
matrix:
3443
allow_failures:
35-
- rvm: rbx
44+
- env: DB=mysql57
45+
- rvm: rbx-2
3646
include:
3747
- rvm: 2.0.0
3848
env: DB=mariadb55
3949
- rvm: 2.0.0
4050
env: DB=mariadb10
41-
- rvm: rbx
51+
- rvm: 2.0.0
52+
env: DB=mysql57
53+
- rvm: rbx-2
4254
env: RBXOPT=-Xgc.honor_start=true
55+
- rvm: 2.0.0
56+
os: osx

.travis_mariadb.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
3+
service mysql stop
4+
apt-get purge '^mysql*' 'libmysql*'
5+
apt-get install python-software-properties
6+
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
7+
8+
if [[ x$1 = xmariadb55 ]]; then
9+
add-apt-repository 'deb http://ftp.osuosl.org/pub/mariadb/repo/5.5/ubuntu precise main'
10+
elif [[ x$1 = xmariadb10 ]]; then
11+
add-apt-repository 'deb http://ftp.osuosl.org/pub/mariadb/repo/10.0/ubuntu precise main'
12+
fi
13+
14+
apt-get update
15+
apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -y install mariadb-server libmariadbd-dev

.travis_mysql57.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/sh
2+
3+
service mysql stop
4+
5+
apt-get purge '^mysql*' 'libmysql*'
6+
apt-get autoclean
7+
8+
rm -rf /var/lib/mysql
9+
rm -rf /var/log/mysql
10+
11+
apt-get install python-software-properties
12+
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x8C718D3B5072E1F5
13+
add-apt-repository 'deb http://repo.mysql.com/apt/ubuntu/ precise mysql-5.7-dmr'
14+
15+
apt-get update
16+
apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -y install mysql-server libmysqlclient-dev

.travis_ssl.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/bin/sh
2+
3+
# Halt the tests on error
4+
set -e
5+
6+
# Whever MySQL configs live, go there (this is for cross-platform)
7+
cd $(my_print_defaults --help | grep my.cnf | xargs find 2>/dev/null | xargs dirname)
8+
9+
# Create config files to run openssl in batch mode
10+
# Set the CA startdate to yesterday to avoid "ASN: before date in the future"
11+
# (there can be 90k seconds in a daylight saving change day)
12+
13+
echo "
14+
[ ca ]
15+
default_startdate = $(ruby -e 'print (Time.now - 90000).strftime("%y%m%d000000Z")')
16+
17+
[ req ]
18+
distinguished_name = req_distinguished_name
19+
20+
[ req_distinguished_name ]
21+
# If this isn't set, the error is "error, no objects specified in config file"
22+
commonName = Common Name (hostname, IP, or your name)
23+
24+
countryName_default = US
25+
stateOrProvinceName_default = CA
26+
localityName_default = San Francisco
27+
0.organizationName_default = test_example
28+
organizationalUnitName_default = Testing
29+
emailAddress_default = [email protected]
30+
" | tee ca.cnf cert.cnf
31+
32+
# The client and server certs must have a diferent common name than the CA
33+
# to avoid "SSL connection error: error:00000001:lib(0):func(0):reason(1)"
34+
35+
echo "
36+
commonName_default = ca_name
37+
" >> ca.cnf
38+
39+
echo "
40+
commonName_default = cert_name
41+
" >> cert.cnf
42+
43+
# Generate a set of certificates
44+
openssl genrsa -out ca-key.pem 2048
45+
openssl req -new -x509 -nodes -days 1000 -key ca-key.pem -out ca-cert.pem -batch -config ca.cnf
46+
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout pkcs8-server-key.pem -out server-req.pem -batch -config cert.cnf
47+
openssl x509 -req -in server-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
48+
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout pkcs8-client-key.pem -out client-req.pem -batch -config cert.cnf
49+
openssl x509 -req -in client-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
50+
51+
# Convert format from PKCS#8 to PKCS#1
52+
openssl rsa -in pkcs8-server-key.pem -out server-key.pem
53+
openssl rsa -in pkcs8-client-key.pem -out client-key.pem
54+
55+
# Put the configs into the server
56+
echo "
57+
[mysqld]
58+
ssl-ca=/etc/mysql/ca-cert.pem
59+
ssl-cert=/etc/mysql/server-cert.pem
60+
ssl-key=/etc/mysql/server-key.pem
61+
" >> my.cnf
62+
63+
# FIXME The startdate code above isn't doing the trick, we must wait until the minute moves
64+
ruby -e 'start = Time.now.min; while Time.now.min == start; sleep 2; end'
65+
66+
# Ok, let's see what we got!
67+
service mysql restart || brew services restart mysql

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# Mysql2 - A modern, simple and very fast Mysql library for Ruby - binding to libmysql
1+
# Mysql2 - A modern, simple and very fast MySQL library for Ruby - binding to libmysql
22

33
[![Build Status](https://travis-ci.org/brianmario/mysql2.png)](https://travis-ci.org/brianmario/mysql2)
44

55
The Mysql2 gem is meant to serve the extremely common use-case of connecting, querying and iterating on results.
6-
Some database libraries out there serve as direct 1:1 mappings of the already complex C API's available.
6+
Some database libraries out there serve as direct 1:1 mappings of the already complex C APIs available.
77
This one is not.
88

99
It also forces the use of UTF-8 [or binary] for the connection [and all strings in 1.9, unless Encoding.default_internal is set then it'll convert from UTF-8 to that encoding] and uses encoding-aware MySQL API calls where it can.
1010

1111
The API consists of two classes:
1212

13-
`Mysql2::Client` - your connection to the database
13+
`Mysql2::Client` - your connection to the database.
1414

1515
`Mysql2::Result` - returned from issuing a #query on the connection. It includes Enumerable.
1616

@@ -26,7 +26,7 @@ By default, the mysql2 gem will try to find a copy of MySQL in this order:
2626

2727
* Option `--with-mysql-dir`, if provided (see below).
2828
* Option `--with-mysql-config`, if provided (see below).
29-
* Several typical paths for `msyql_config` (default for the majority of users).
29+
* Several typical paths for `mysql_config` (default for the majority of users).
3030
* The directory `/usr/local`.
3131

3232
### Configuration options
@@ -104,7 +104,10 @@ results.each do |row|
104104
# conveniently, row is a hash
105105
# the keys are the fields, as you'd expect
106106
# the values are pre-built ruby primitives mapped from their corresponding field types in MySQL
107-
# Here's an otter: http://farm1.static.flickr.com/130/398077070_b8795d0ef3_b.jpg
107+
puts row["id"] # row["id"].class == Fixnum
108+
if row["dne"] # non-existant hash entry is nil
109+
puts row["dne"]
110+
end
108111
end
109112
```
110113

@@ -335,7 +338,7 @@ result = client.query("SELECT * FROM table_with_boolean_field", :cast_booleans =
335338

336339
### Skipping casting
337340

338-
Mysql2 casting is fast, but not as fast as not casting data. In rare cases where typecasting is not needed, it will be faster to disable it by providing :cast => false.
341+
Mysql2 casting is fast, but not as fast as not casting data. In rare cases where typecasting is not needed, it will be faster to disable it by providing :cast => false. (Note that :cast => false overrides :cast_booleans => true.)
339342

340343
``` ruby
341344
client = Mysql2::Client.new

ext/mysql2/client.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
#include <sys/types.h>
77
#include <sys/socket.h>
88
#endif
9+
#ifndef _MSC_VER
910
#include <unistd.h>
11+
#endif
1012
#include <fcntl.h>
1113
#include "wait_for_single_fd.h"
1214

@@ -167,26 +169,30 @@ static void *nogvl_connect(void *ptr) {
167169

168170
#ifndef _WIN32
169171
/*
170-
* Redirect clientfd to a dummy socket for mysql_close to
171-
* write, shutdown, and close on as a no-op.
172-
* We do this hack because we want to call mysql_close to release
173-
* memory, but do not want mysql_close to drop connections in the
174-
* parent if the socket got shared in fork.
172+
* Redirect clientfd to /dev/null for mysql_close and SSL_close to write,
173+
* shutdown, and close. The hack is needed to prevent shutdown() from breaking
174+
* a socket that may be in use by the parent or other processes after fork.
175+
*
176+
* /dev/null is used to absorb writes; previously a dummy socket was used, but
177+
* it could not abosrb writes and caused openssl to go into an infinite loop.
178+
*
175179
* Returns Qtrue or Qfalse (success or failure)
180+
*
181+
* Note: if this function is needed on Windows, use "nul" instead of "/dev/null"
176182
*/
177183
static VALUE invalidate_fd(int clientfd)
178184
{
179185
#ifdef SOCK_CLOEXEC
180186
/* Atomically set CLOEXEC on the new FD in case another thread forks */
181-
int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
187+
int sockfd = open("/dev/null", O_RDWR | O_CLOEXEC);
182188
if (sockfd < 0) {
183189
/* Maybe SOCK_CLOEXEC is defined but not available on this kernel */
184-
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
190+
int sockfd = open("/dev/null", O_RDWR);
185191
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
186192
}
187193
#else
188194
/* Well we don't have SOCK_CLOEXEC, so just set FD_CLOEXEC quickly */
189-
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
195+
int sockfd = open("/dev/null", O_RDWR);
190196
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
191197
#endif
192198

@@ -326,10 +332,10 @@ static VALUE rb_mysql_info(VALUE self) {
326332

327333
static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
328334
struct nogvl_connect_args args;
329-
VALUE rv;
330-
GET_CLIENT(self);
331335
time_t start_time, end_time;
332336
unsigned int elapsed_time, connect_timeout;
337+
VALUE rv;
338+
GET_CLIENT(self);
333339

334340
args.host = NIL_P(host) ? NULL : StringValuePtr(host);
335341
args.unix_socket = NIL_P(socket) ? NULL : StringValuePtr(socket);
@@ -349,11 +355,11 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
349355
time(&end_time);
350356
/* avoid long connect timeout from system time changes */
351357
if (end_time < start_time)
352-
start_time = end_time;
358+
start_time = end_time;
353359
elapsed_time = end_time - start_time;
354360
/* avoid an early timeout due to time truncating milliseconds off the start time */
355361
if (elapsed_time > 0)
356-
elapsed_time--;
362+
elapsed_time--;
357363
if (elapsed_time >= wrapper->connect_timeout)
358364
break;
359365
connect_timeout = wrapper->connect_timeout - elapsed_time;
@@ -764,17 +770,17 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
764770

765771
switch(opt) {
766772
case MYSQL_OPT_CONNECT_TIMEOUT:
767-
intval = NUM2INT(value);
773+
intval = NUM2UINT(value);
768774
retval = &intval;
769775
break;
770776

771777
case MYSQL_OPT_READ_TIMEOUT:
772-
intval = NUM2INT(value);
778+
intval = NUM2UINT(value);
773779
retval = &intval;
774780
break;
775781

776782
case MYSQL_OPT_WRITE_TIMEOUT:
777-
intval = NUM2INT(value);
783+
intval = NUM2UINT(value);
778784
retval = &intval;
779785
break;
780786

@@ -1233,6 +1239,13 @@ void init_mysql2_client() {
12331239
}
12341240
}
12351241

1242+
/* Initializing mysql library, so different threads could call Client.new */
1243+
/* without race condition in the library */
1244+
if (mysql_library_init(0, NULL, NULL) != 0) {
1245+
rb_raise(rb_eRuntimeError, "Could not initialize MySQL client library");
1246+
return;
1247+
}
1248+
12361249
#if 0
12371250
mMysql2 = rb_define_module("Mysql2"); Teach RDoc about Mysql2 constant.
12381251
#endif
@@ -1365,6 +1378,10 @@ void init_mysql2_client() {
13651378
#ifdef CLIENT_SECURE_CONNECTION
13661379
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"),
13671380
LONG2NUM(CLIENT_SECURE_CONNECTION));
1381+
#else
1382+
/* HACK because MySQL5.7 no longer defines this constant,
1383+
* but we're using it in our default connection flags. */
1384+
rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), LONG2NUM(0));
13681385
#endif
13691386

13701387
#ifdef CLIENT_MULTI_STATEMENTS

ext/mysql2/client.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ typedef struct {
4141
VALUE active_thread; /* rb_thread_current() or Qnil */
4242
long server_version;
4343
int reconnect_enabled;
44-
int connect_timeout;
44+
unsigned int connect_timeout;
4545
int active;
4646
int connected;
4747
int initialized;

ext/mysql2/infile.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#include <mysql2_ext.h>
22

33
#include <errno.h>
4+
#ifndef _MSC_VER
45
#include <unistd.h>
6+
#endif
57
#include <fcntl.h>
68

79
#define ERROR_LEN 1024

0 commit comments

Comments
 (0)