ffi-mysql 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +4 -0
- data/README +55 -0
- data/README.rdoc +55 -0
- data/Rakefile +27 -0
- data/lib/ffi-mysql.rb +49 -0
- data/lib/mysql/constants.rb +166 -0
- data/lib/mysql/error.rb +4 -0
- data/lib/mysql/field.rb +89 -0
- data/lib/mysql/mysql.rb +365 -0
- data/lib/mysql/result.rb +168 -0
- data/lib/mysql/stmt.rb +416 -0
- data/lib/mysql/time.rb +33 -0
- data/test/test_mysql.rb +1483 -0
- metadata +103 -0
data/History.rdoc
ADDED
data/README
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
ffi-mysql
|
2
|
+
by Frank Fischer
|
3
|
+
http://bitbucket.org/lyro/ffi-mysql
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Pure Ruby FFI interface to MySQL.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* satisfies almost complete test-suite of MySQL/Ruby
|
12
|
+
* prepared statement does not handle Double fields
|
13
|
+
correctly
|
14
|
+
|
15
|
+
== SYNOPSIS:
|
16
|
+
|
17
|
+
See MySQL/Ruby for examples.
|
18
|
+
|
19
|
+
== REQUIREMENTS:
|
20
|
+
|
21
|
+
* ffi >= 0.6.2
|
22
|
+
|
23
|
+
== INSTALL:
|
24
|
+
|
25
|
+
gem install ffi-ruby
|
26
|
+
|
27
|
+
== ACKNOWLEDGEMENTS:
|
28
|
+
|
29
|
+
Tomita Masahiro for his MySQL/Ruby and Ruby/MySQL gems from which some
|
30
|
+
of the code has been stolen.
|
31
|
+
|
32
|
+
== LICENSE:
|
33
|
+
|
34
|
+
(The MIT License)
|
35
|
+
|
36
|
+
Copyright (c) 2010 Frank Fischer
|
37
|
+
|
38
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
39
|
+
a copy of this software and associated documentation files (the
|
40
|
+
'Software'), to deal in the Software without restriction, including
|
41
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
42
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
43
|
+
permit persons to whom the Software is furnished to do so, subject to
|
44
|
+
the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be
|
47
|
+
included in all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
52
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
53
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
54
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
55
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
ffi-mysql
|
2
|
+
by Frank Fischer
|
3
|
+
http://bitbucket.org/lyro/ffi-mysql
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Pure Ruby FFI interface to MySQL.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* satisfies almost complete test-suite of MySQL/Ruby
|
12
|
+
* prepared statement does not handle Double fields
|
13
|
+
correctly
|
14
|
+
|
15
|
+
== SYNOPSIS:
|
16
|
+
|
17
|
+
See MySQL/Ruby for examples.
|
18
|
+
|
19
|
+
== REQUIREMENTS:
|
20
|
+
|
21
|
+
* ffi >= 0.6.2
|
22
|
+
|
23
|
+
== INSTALL:
|
24
|
+
|
25
|
+
gem install ffi-ruby
|
26
|
+
|
27
|
+
== ACKNOWLEDGEMENTS:
|
28
|
+
|
29
|
+
Tomita Masahiro for his MySQL/Ruby and Ruby/MySQL gems from which some
|
30
|
+
of the code has been stolen.
|
31
|
+
|
32
|
+
== LICENSE:
|
33
|
+
|
34
|
+
(The MIT License)
|
35
|
+
|
36
|
+
Copyright (c) 2010 Frank Fischer
|
37
|
+
|
38
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
39
|
+
a copy of this software and associated documentation files (the
|
40
|
+
'Software'), to deal in the Software without restriction, including
|
41
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
42
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
43
|
+
permit persons to whom the Software is furnished to do so, subject to
|
44
|
+
the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be
|
47
|
+
included in all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
52
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
53
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
54
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
55
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'bones'
|
4
|
+
rescue LoadError
|
5
|
+
abort '### Please install the "bones" gem ###'
|
6
|
+
end
|
7
|
+
|
8
|
+
ensure_in_path 'lib'
|
9
|
+
require 'ffi-mysql'
|
10
|
+
|
11
|
+
task :default => 'test:run'
|
12
|
+
task 'gem:release' => 'test:run'
|
13
|
+
|
14
|
+
Bones {
|
15
|
+
name 'ffi-mysql'
|
16
|
+
authors 'Frank Fischer'
|
17
|
+
email 'frank.fischer@mathematik.tu-chemnitz.de'
|
18
|
+
url 'http://bitbucket.org/lyro/ffi-mysql/wiki'
|
19
|
+
ignore_file '.hgignore'
|
20
|
+
readme_file 'README.rdoc'
|
21
|
+
history_file 'History.rdoc'
|
22
|
+
version Mysql::VERSION
|
23
|
+
gem.extras = { :has_rdoc => 'yard' }
|
24
|
+
depend_on 'ffi', '>= 0.6.2'
|
25
|
+
}
|
26
|
+
|
27
|
+
# EOF
|
data/lib/ffi-mysql.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
class Mysql
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
VERSION = '0.0.1'
|
6
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
7
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
8
|
+
# :startdoc:
|
9
|
+
|
10
|
+
# Returns the version string for the library.
|
11
|
+
#
|
12
|
+
def self.version
|
13
|
+
VERSION
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the library path for the module. If any arguments are given,
|
17
|
+
# they will be joined to the end of the libray path using
|
18
|
+
# <tt>File.join</tt>.
|
19
|
+
#
|
20
|
+
def self.libpath( *args )
|
21
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the lpath for the module. If any arguments are given,
|
25
|
+
# they will be joined to the end of the path using
|
26
|
+
# <tt>File.join</tt>.
|
27
|
+
#
|
28
|
+
def self.path( *args )
|
29
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Utility method used to require all files ending in .rb that lie in the
|
33
|
+
# directory below this file that has the same name as the filename passed
|
34
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
35
|
+
# the _filename_ does not have to be equivalent to the directory.
|
36
|
+
#
|
37
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
38
|
+
dir ||= ::File.basename(fname, '.*')
|
39
|
+
search_me = ::File.expand_path(
|
40
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
41
|
+
|
42
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
43
|
+
end
|
44
|
+
|
45
|
+
end # class Mysql
|
46
|
+
|
47
|
+
Mysql.require_all_libs_relative_to(__FILE__, "mysql")
|
48
|
+
|
49
|
+
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# Copyright (C) 2003-2008 TOMITA Masahiro
|
2
|
+
# mailto:tommy@tmtm.org
|
3
|
+
|
4
|
+
class Mysql
|
5
|
+
# Command
|
6
|
+
COM_SLEEP = 0
|
7
|
+
COM_QUIT = 1
|
8
|
+
COM_INIT_DB = 2
|
9
|
+
COM_QUERY = 3
|
10
|
+
COM_FIELD_LIST = 4
|
11
|
+
COM_CREATE_DB = 5
|
12
|
+
COM_DROP_DB = 6
|
13
|
+
COM_REFRESH = 7
|
14
|
+
COM_SHUTDOWN = 8
|
15
|
+
COM_STATISTICS = 9
|
16
|
+
COM_PROCESS_INFO = 10
|
17
|
+
COM_CONNECT = 11
|
18
|
+
COM_PROCESS_KILL = 12
|
19
|
+
COM_DEBUG = 13
|
20
|
+
COM_PING = 14
|
21
|
+
COM_TIME = 15
|
22
|
+
COM_DELAYED_INSERT = 16
|
23
|
+
COM_CHANGE_USER = 17
|
24
|
+
COM_BINLOG_DUMP = 18
|
25
|
+
COM_TABLE_DUMP = 19
|
26
|
+
COM_CONNECT_OUT = 20
|
27
|
+
COM_REGISTER_SLAVE = 21
|
28
|
+
COM_STMT_PREPARE = 22
|
29
|
+
COM_STMT_EXECUTE = 23
|
30
|
+
COM_STMT_SEND_LONG_DATA = 24
|
31
|
+
COM_STMT_CLOSE = 25
|
32
|
+
COM_STMT_RESET = 26
|
33
|
+
COM_SET_OPTION = 27
|
34
|
+
COM_STMT_FETCH = 28
|
35
|
+
|
36
|
+
# Client flag
|
37
|
+
CLIENT_LONG_PASSWORD = 1 # new more secure passwords
|
38
|
+
CLIENT_FOUND_ROWS = 1 << 1 # Found instead of affected rows
|
39
|
+
CLIENT_LONG_FLAG = 1 << 2 # Get all column flags
|
40
|
+
CLIENT_CONNECT_WITH_DB = 1 << 3 # One can specify db on connect
|
41
|
+
CLIENT_NO_SCHEMA = 1 << 4 # Don't allow database.table.column
|
42
|
+
CLIENT_COMPRESS = 1 << 5 # Can use compression protocol
|
43
|
+
CLIENT_ODBC = 1 << 6 # Odbc client
|
44
|
+
CLIENT_LOCAL_FILES = 1 << 7 # Can use LOAD DATA LOCAL
|
45
|
+
CLIENT_IGNORE_SPACE = 1 << 8 # Ignore spaces before '('
|
46
|
+
CLIENT_PROTOCOL_41 = 1 << 9 # New 4.1 protocol
|
47
|
+
CLIENT_INTERACTIVE = 1 << 10 # This is an interactive client
|
48
|
+
CLIENT_SSL = 1 << 11 # Switch to SSL after handshake
|
49
|
+
CLIENT_IGNORE_SIGPIPE = 1 << 12 # IGNORE sigpipes
|
50
|
+
CLIENT_TRANSACTIONS = 1 << 13 # Client knows about transactions
|
51
|
+
CLIENT_RESERVED = 1 << 14 # Old flag for 4.1 protocol
|
52
|
+
CLIENT_SECURE_CONNECTION = 1 << 15 # New 4.1 authentication
|
53
|
+
CLIENT_MULTI_STATEMENTS = 1 << 16 # Enable/disable multi-stmt support
|
54
|
+
CLIENT_MULTI_RESULTS = 1 << 17 # Enable/disable multi-results
|
55
|
+
|
56
|
+
# Connection Option
|
57
|
+
OPT_CONNECT_TIMEOUT = 0
|
58
|
+
OPT_COMPRESS = 1
|
59
|
+
OPT_NAMED_PIPE = 2
|
60
|
+
INIT_COMMAND = 3
|
61
|
+
READ_DEFAULT_FILE = 4
|
62
|
+
READ_DEFAULT_GROUP = 5
|
63
|
+
SET_CHARSET_DIR = 6
|
64
|
+
SET_CHARSET_NAME = 7
|
65
|
+
OPT_LOCAL_INFILE = 8
|
66
|
+
OPT_PROTOCOL = 9
|
67
|
+
SHARED_MEMORY_BASE_NAME = 10
|
68
|
+
OPT_READ_TIMEOUT = 11
|
69
|
+
OPT_WRITE_TIMEOUT = 12
|
70
|
+
OPT_USE_RESULT = 13
|
71
|
+
OPT_USE_REMOTE_CONNECTION = 14
|
72
|
+
OPT_USE_EMBEDDED_CONNECTION = 15
|
73
|
+
OPT_GUESS_CONNECTION = 16
|
74
|
+
SET_CLIENT_IP = 17
|
75
|
+
SECURE_AUTH = 18
|
76
|
+
REPORT_DATA_TRUNCATION = 19
|
77
|
+
OPT_RECONNECT = 20
|
78
|
+
OPT_SSL_VERIFY_SERVER_CERT = 21
|
79
|
+
|
80
|
+
# Server Option
|
81
|
+
OPTION_MULTI_STATEMENTS_ON = 0
|
82
|
+
OPTION_MULTI_STATEMENTS_OFF = 1
|
83
|
+
|
84
|
+
# Server Status
|
85
|
+
SERVER_STATUS_IN_TRANS = 1
|
86
|
+
SERVER_STATUS_AUTOCOMMIT = 1 << 1
|
87
|
+
SERVER_MORE_RESULTS_EXISTS = 1 << 3
|
88
|
+
SERVER_QUERY_NO_GOOD_INDEX_USED = 1 << 4
|
89
|
+
SERVER_QUERY_NO_INDEX_USED = 1 << 5
|
90
|
+
SERVER_STATUS_CURSOR_EXISTS = 1 << 6
|
91
|
+
SERVER_STATUS_LAST_ROW_SENT = 1 << 7
|
92
|
+
SERVER_STATUS_DB_DROPPED = 1 << 8
|
93
|
+
SERVER_STATUS_NO_BACKSLASH_ESCAPES = 1 << 9
|
94
|
+
|
95
|
+
# Refresh parameter
|
96
|
+
REFRESH_GRANT = 1
|
97
|
+
REFRESH_LOG = 1 << 1
|
98
|
+
REFRESH_TABLES = 1 << 2
|
99
|
+
REFRESH_HOSTS = 1 << 3
|
100
|
+
REFRESH_STATUS = 1 << 4
|
101
|
+
REFRESH_THREADS = 1 << 5
|
102
|
+
REFRESH_SLAVE = 1 << 6
|
103
|
+
REFRESH_MASTER = 1 << 7
|
104
|
+
REFRESH_READ_LOCK = 1 << 14
|
105
|
+
REFRESH_FAST = 1 << 15
|
106
|
+
|
107
|
+
class Field
|
108
|
+
# Field type
|
109
|
+
TYPE_DECIMAL = 0
|
110
|
+
TYPE_TINY = 1
|
111
|
+
TYPE_SHORT = 2
|
112
|
+
TYPE_LONG = 3
|
113
|
+
TYPE_FLOAT = 4
|
114
|
+
TYPE_DOUBLE = 5
|
115
|
+
TYPE_NULL = 6
|
116
|
+
TYPE_TIMESTAMP = 7
|
117
|
+
TYPE_LONGLONG = 8
|
118
|
+
TYPE_INT24 = 9
|
119
|
+
TYPE_DATE = 10
|
120
|
+
TYPE_TIME = 11
|
121
|
+
TYPE_DATETIME = 12
|
122
|
+
TYPE_YEAR = 13
|
123
|
+
TYPE_NEWDATE = 14
|
124
|
+
TYPE_VARCHAR = 15
|
125
|
+
TYPE_BIT = 16
|
126
|
+
TYPE_NEWDECIMAL = 246
|
127
|
+
TYPE_ENUM = 247
|
128
|
+
TYPE_SET = 248
|
129
|
+
TYPE_TINY_BLOB = 249
|
130
|
+
TYPE_MEDIUM_BLOB = 250
|
131
|
+
TYPE_LONG_BLOB = 251
|
132
|
+
TYPE_BLOB = 252
|
133
|
+
TYPE_VAR_STRING = 253
|
134
|
+
TYPE_STRING = 254
|
135
|
+
TYPE_GEOMETRY = 255
|
136
|
+
TYPE_CHAR = TYPE_TINY
|
137
|
+
TYPE_INTERVAL = TYPE_ENUM
|
138
|
+
|
139
|
+
# Flag
|
140
|
+
NOT_NULL_FLAG = 1
|
141
|
+
PRI_KEY_FLAG = 2
|
142
|
+
UNIQUE_KEY_FLAG = 4
|
143
|
+
MULTIPLE_KEY_FLAG = 8
|
144
|
+
BLOB_FLAG = 16
|
145
|
+
UNSIGNED_FLAG = 32
|
146
|
+
ZEROFILL_FLAG = 64
|
147
|
+
BINARY_FLAG = 128
|
148
|
+
ENUM_FLAG = 256
|
149
|
+
AUTO_INCREMENT_FLAG = 512
|
150
|
+
TIMESTAMP_FLAG = 1024
|
151
|
+
SET_FLAG = 2048
|
152
|
+
NUM_FLAG = 32768
|
153
|
+
PART_KEY_FLAG = 16384
|
154
|
+
GROUP_FLAG = 32768
|
155
|
+
UNIQUE_FLAG = 65536
|
156
|
+
BINCMP_FLAG = 131072
|
157
|
+
end
|
158
|
+
|
159
|
+
class Stmt
|
160
|
+
# Cursor type
|
161
|
+
CURSOR_TYPE_NO_CURSOR = 0
|
162
|
+
CURSOR_TYPE_READ_ONLY = 1
|
163
|
+
NO_DATA = 100
|
164
|
+
DATA_TRUNCATED = 101
|
165
|
+
end
|
166
|
+
end
|
data/lib/mysql/error.rb
ADDED
data/lib/mysql/field.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
class Mysql
|
2
|
+
# Information about one column.
|
3
|
+
class Field
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :org_name
|
6
|
+
attr_reader :table
|
7
|
+
attr_reader :org_table
|
8
|
+
attr_reader :db
|
9
|
+
attr_reader :catalog
|
10
|
+
attr_reader :def
|
11
|
+
attr_reader :length
|
12
|
+
attr_reader :max_length
|
13
|
+
attr_reader :name_length
|
14
|
+
attr_reader :org_name_length
|
15
|
+
attr_reader :table_length
|
16
|
+
attr_reader :org_table_length
|
17
|
+
attr_reader :db_length
|
18
|
+
attr_reader :catalog_length
|
19
|
+
attr_reader :def_length
|
20
|
+
attr_reader :flags
|
21
|
+
attr_reader :decimals
|
22
|
+
attr_reader :charsetnr
|
23
|
+
attr_reader :type
|
24
|
+
|
25
|
+
def initialize(c_field)
|
26
|
+
@name = c_field[:name]
|
27
|
+
@org_name = c_field[:org_name]
|
28
|
+
@table = c_field[:table]
|
29
|
+
@org_table = c_field[:org_table]
|
30
|
+
@db = c_field[:db]
|
31
|
+
@catalog = c_field[:catalog]
|
32
|
+
@def = c_field[:def]
|
33
|
+
@length = c_field[:length]
|
34
|
+
@max_length = c_field[:max_length]
|
35
|
+
@name_length = c_field[:name_length]
|
36
|
+
@org_name_length = c_field[:org_name_length]
|
37
|
+
@table_length = c_field[:table_length]
|
38
|
+
@org_table_length = c_field[:org_table_length]
|
39
|
+
@db_length = c_field[:db_length]
|
40
|
+
@catalog_length = c_field[:catalog_length]
|
41
|
+
@def_length = c_field[:def_length]
|
42
|
+
@flags = c_field[:flags]
|
43
|
+
@decimals = c_field[:decimals]
|
44
|
+
@charsetnr = c_field[:charsetnr]
|
45
|
+
# @type = C::FieldType[c_field[:type]]
|
46
|
+
@type = c_field[:type]
|
47
|
+
@flags |= NUM_FLAG if is_num_type?
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Boolean] true if this field is not null
|
51
|
+
def is_not_null?
|
52
|
+
@flags & NOT_NULL_FLAG != 0
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Boolean] true if this is a numeric field
|
56
|
+
def is_num?
|
57
|
+
@flags & NUM_FLAG != 0
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Boolean] true if this field is a primary key
|
61
|
+
def is_pri_key?
|
62
|
+
@flags & PRI_KEY_FLAG != 0
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Hash] this field as a hash
|
66
|
+
def hash
|
67
|
+
h = {}
|
68
|
+
h['name'] = @name
|
69
|
+
h['table'] = @table
|
70
|
+
h['def'] = @def
|
71
|
+
h['length'] = @length
|
72
|
+
h['max_length'] = @max_length
|
73
|
+
h['flags'] = @flags
|
74
|
+
h['decimals'] = @decimals
|
75
|
+
h['type'] = @type
|
76
|
+
h
|
77
|
+
end
|
78
|
+
|
79
|
+
def inspect
|
80
|
+
"#<Mysql::Field:#{@name}>"
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
# @return [Boolean] true if this field's type is a numeric type
|
85
|
+
def is_num_type?
|
86
|
+
[TYPE_DECIMAL, TYPE_TINY, TYPE_SHORT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_LONGLONG, TYPE_INT24].include?(@type) || (@type == TYPE_TIMESTAMP && (@length == 14 || @length == 8))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|