mysql2 0.1.9 → 0.2.0

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.
@@ -1,237 +0,0 @@
1
- require 'mysql2' unless defined? Mysql2
2
-
3
- Sequel.require %w'shared/mysql utils/stored_procedures', 'adapters'
4
-
5
- module Sequel
6
- # Module for holding all MySQL-related classes and modules for Sequel.
7
- module Mysql2
8
- # Mapping of type numbers to conversion procs
9
- MYSQL_TYPES = {}
10
-
11
- MYSQL2_LITERAL_PROC = lambda{|v| v}
12
-
13
- # Use only a single proc for each type to save on memory
14
- MYSQL_TYPE_PROCS = {
15
- [0, 246] => MYSQL2_LITERAL_PROC, # decimal
16
- [1] => lambda{|v| convert_tinyint_to_bool ? v != 0 : v}, # tinyint
17
- [2, 3, 8, 9, 13, 247, 248] => MYSQL2_LITERAL_PROC, # integer
18
- [4, 5] => MYSQL2_LITERAL_PROC, # float
19
- [10, 14] => MYSQL2_LITERAL_PROC, # date
20
- [7, 12] => MYSQL2_LITERAL_PROC, # datetime
21
- [11] => MYSQL2_LITERAL_PROC, # time
22
- [249, 250, 251, 252] => lambda{|v| Sequel::SQL::Blob.new(v)} # blob
23
- }
24
- MYSQL_TYPE_PROCS.each do |k,v|
25
- k.each{|n| MYSQL_TYPES[n] = v}
26
- end
27
-
28
- @convert_invalid_date_time = false
29
- @convert_tinyint_to_bool = true
30
-
31
- class << self
32
- # By default, Sequel raises an exception if in invalid date or time is used.
33
- # However, if this is set to nil or :nil, the adapter treats dates
34
- # like 0000-00-00 and times like 838:00:00 as nil values. If set to :string,
35
- # it returns the strings as is.
36
- attr_accessor :convert_invalid_date_time
37
-
38
- # Sequel converts the column type tinyint(1) to a boolean by default when
39
- # using the native MySQL adapter. You can turn off the conversion by setting
40
- # this to false.
41
- attr_accessor :convert_tinyint_to_bool
42
- end
43
-
44
- # Database class for MySQL databases used with Sequel.
45
- class Database < Sequel::Database
46
- include Sequel::MySQL::DatabaseMethods
47
-
48
- # Mysql::Error messages that indicate the current connection should be disconnected
49
- MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away)/
50
-
51
- set_adapter_scheme :mysql2
52
-
53
- # Support stored procedures on MySQL
54
- def call_sproc(name, opts={}, &block)
55
- args = opts[:args] || []
56
- execute("CALL #{name}#{args.empty? ? '()' : literal(args)}", opts.merge(:sproc=>false), &block)
57
- end
58
-
59
- # Connect to the database. In addition to the usual database options,
60
- # the following options have effect:
61
- #
62
- # * :auto_is_null - Set to true to use MySQL default behavior of having
63
- # a filter for an autoincrement column equals NULL to return the last
64
- # inserted row.
65
- # * :charset - Same as :encoding (:encoding takes precendence)
66
- # * :compress - Set to false to not compress results from the server
67
- # * :config_default_group - The default group to read from the in
68
- # the MySQL config file.
69
- # * :config_local_infile - If provided, sets the Mysql::OPT_LOCAL_INFILE
70
- # option on the connection with the given value.
71
- # * :encoding - Set all the related character sets for this
72
- # connection (connection, client, database, server, and results).
73
- # * :socket - Use a unix socket file instead of connecting via TCP/IP.
74
- # * :timeout - Set the timeout in seconds before the server will
75
- # disconnect this connection.
76
- def connect(server)
77
- opts = server_opts(server)
78
- conn = ::Mysql2::Client.new({
79
- :host => opts[:host] || 'localhost',
80
- :username => opts[:user],
81
- :password => opts[:password],
82
- :database => opts[:database],
83
- :port => opts[:port],
84
- :socket => opts[:socket]
85
- })
86
-
87
- # increase timeout so mysql server doesn't disconnect us
88
- conn.query("set @@wait_timeout = #{opts[:timeout] || 2592000}")
89
-
90
- # By default, MySQL 'where id is null' selects the last inserted id
91
- conn.query("set SQL_AUTO_IS_NULL=0") unless opts[:auto_is_null]
92
-
93
- conn
94
- end
95
-
96
- # Returns instance of Sequel::MySQL::Dataset with the given options.
97
- def dataset(opts = nil)
98
- Mysql2::Dataset.new(self, opts)
99
- end
100
-
101
- # Executes the given SQL using an available connection, yielding the
102
- # connection if the block is given.
103
- def execute(sql, opts={}, &block)
104
- if opts[:sproc]
105
- call_sproc(sql, opts, &block)
106
- else
107
- synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
108
- end
109
- end
110
-
111
- # Return the version of the MySQL server two which we are connecting.
112
- def server_version(server=nil)
113
- @server_version ||= (synchronize(server){|conn| conn.info[:id]})
114
- end
115
-
116
- private
117
-
118
- # Execute the given SQL on the given connection. If the :type
119
- # option is :select, yield the result of the query, otherwise
120
- # yield the connection if a block is given.
121
- def _execute(conn, sql, opts)
122
- begin
123
- r = log_yield(sql){conn.query(sql)}
124
- if opts[:type] == :select
125
- yield r if r
126
- elsif block_given?
127
- yield conn
128
- end
129
- rescue ::Mysql2::Error => e
130
- raise_error(e, :disconnect=>MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
131
- end
132
- end
133
-
134
- # MySQL connections use the query method to execute SQL without a result
135
- def connection_execute_method
136
- :query
137
- end
138
-
139
- # The MySQL adapter main error class is Mysql::Error
140
- def database_error_classes
141
- [::Mysql2::Error]
142
- end
143
-
144
- # The database name when using the native adapter is always stored in
145
- # the :database option.
146
- def database_name
147
- @opts[:database]
148
- end
149
-
150
- # Closes given database connection.
151
- def disconnect_connection(c)
152
- c.close
153
- end
154
-
155
- # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
156
- def schema_column_type(db_type)
157
- Sequel::Mysql2.convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
158
- end
159
- end
160
-
161
- # Dataset class for MySQL datasets accessed via the native driver.
162
- class Dataset < Sequel::Dataset
163
- include Sequel::MySQL::DatasetMethods
164
- include StoredProcedures
165
-
166
- # Methods for MySQL stored procedures using the native driver.
167
- module StoredProcedureMethods
168
- include Sequel::Dataset::StoredProcedureMethods
169
-
170
- private
171
-
172
- # Execute the database stored procedure with the stored arguments.
173
- def execute(sql, opts={}, &block)
174
- super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
175
- end
176
-
177
- # Same as execute, explicit due to intricacies of alias and super.
178
- def execute_dui(sql, opts={}, &block)
179
- super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
180
- end
181
- end
182
-
183
- # Delete rows matching this dataset
184
- def delete
185
- execute_dui(delete_sql){|c| return c.affected_rows}
186
- end
187
-
188
- # Yield all rows matching this dataset. If the dataset is set to
189
- # split multiple statements, yield arrays of hashes one per statement
190
- # instead of yielding results for all statements as hashes.
191
- def fetch_rows(sql, &block)
192
- execute(sql) do |r|
193
- r.each(:symbolize_keys => true, &block)
194
- end
195
- self
196
- end
197
-
198
- # Don't allow graphing a dataset that splits multiple statements
199
- def graph(*)
200
- raise(Error, "Can't graph a dataset that splits multiple result sets") if opts[:split_multiple_result_sets]
201
- super
202
- end
203
-
204
- # Insert a new value into this dataset
205
- def insert(*values)
206
- execute_dui(insert_sql(*values)){|c| return c.last_id}
207
- end
208
-
209
- # Replace (update or insert) the matching row.
210
- def replace(*args)
211
- execute_dui(replace_sql(*args)){|c| return c.last_id}
212
- end
213
-
214
- # Update the matching rows.
215
- def update(values={})
216
- execute_dui(update_sql(values)){|c| return c.affected_rows}
217
- end
218
-
219
- private
220
-
221
- # Set the :type option to :select if it hasn't been set.
222
- def execute(sql, opts={}, &block)
223
- super(sql, {:type=>:select}.merge(opts), &block)
224
- end
225
-
226
- # Set the :type option to :dui if it hasn't been set.
227
- def execute_dui(sql, opts={}, &block)
228
- super(sql, {:type=>:dui}.merge(opts), &block)
229
- end
230
-
231
- # Handle correct quoting of strings using ::Mysql2#escape.
232
- def literal_string(v)
233
- db.synchronize{|c| "'#{c.escape(v)}'"}
234
- end
235
- end
236
- end
237
- end
@@ -1,149 +0,0 @@
1
- # encoding: UTF-8
2
- require 'spec_helper'
3
- require 'rubygems'
4
- require 'active_record'
5
- require 'active_record/connection_adapters/mysql2_adapter'
6
-
7
- class Mysql2Test2 < ActiveRecord::Base
8
- set_table_name "mysql2_test2"
9
- end
10
-
11
- describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
12
- it "should be able to connect" do
13
- lambda {
14
- ActiveRecord::Base.establish_connection(:adapter => 'mysql2')
15
- }.should_not raise_error(Mysql2::Error)
16
- end
17
-
18
- context "once connected" do
19
- before(:each) do
20
- @connection = ActiveRecord::Base.connection
21
- end
22
-
23
- it "should be able to execute a raw query" do
24
- @connection.execute("SELECT 1 as one").first['one'].should eql(1)
25
- @connection.execute("SELECT NOW() as n").first['n'].class.should eql(Time)
26
- end
27
- end
28
-
29
- context "columns" do
30
- before(:all) do
31
- ActiveRecord::Base.default_timezone = 'Pacific Time (US & Canada)'
32
- ActiveRecord::Base.time_zone_aware_attributes = true
33
- ActiveRecord::Base.establish_connection(:adapter => 'mysql2', :database => 'test')
34
- Mysql2Test2.connection.execute %[
35
- CREATE TABLE IF NOT EXISTS mysql2_test2 (
36
- `id` mediumint(9) NOT NULL AUTO_INCREMENT,
37
- `null_test` varchar(10) DEFAULT NULL,
38
- `bit_test` bit(64) NOT NULL DEFAULT b'1',
39
- `boolean_test` tinyint(1) DEFAULT 0,
40
- `tiny_int_test` tinyint(4) NOT NULL DEFAULT '1',
41
- `small_int_test` smallint(6) NOT NULL DEFAULT '1',
42
- `medium_int_test` mediumint(9) NOT NULL DEFAULT '1',
43
- `int_test` int(11) NOT NULL DEFAULT '1',
44
- `big_int_test` bigint(20) NOT NULL DEFAULT '1',
45
- `float_test` float(10,3) NOT NULL DEFAULT '1.000',
46
- `double_test` double(10,3) NOT NULL DEFAULT '1.000',
47
- `decimal_test` decimal(10,3) NOT NULL DEFAULT '1.000',
48
- `date_test` date NOT NULL DEFAULT '2010-01-01',
49
- `date_time_test` datetime NOT NULL DEFAULT '2010-01-01 00:00:00',
50
- `timestamp_test` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
51
- `time_test` time NOT NULL DEFAULT '00:00:00',
52
- `year_test` year(4) NOT NULL DEFAULT '2010',
53
- `char_test` char(10) NOT NULL DEFAULT 'abcdefghij',
54
- `varchar_test` varchar(10) NOT NULL DEFAULT 'abcdefghij',
55
- `binary_test` binary(10) NOT NULL DEFAULT 'abcdefghij',
56
- `varbinary_test` varbinary(10) NOT NULL DEFAULT 'abcdefghij',
57
- `tiny_blob_test` tinyblob NOT NULL,
58
- `tiny_text_test` tinytext,
59
- `blob_test` blob,
60
- `text_test` text,
61
- `medium_blob_test` mediumblob,
62
- `medium_text_test` mediumtext,
63
- `long_blob_test` longblob,
64
- `long_text_test` longtext,
65
- `enum_test` enum('val1','val2') NOT NULL DEFAULT 'val1',
66
- `set_test` set('val1','val2') NOT NULL DEFAULT 'val1,val2',
67
- PRIMARY KEY (`id`)
68
- )
69
- ]
70
- Mysql2Test2.connection.execute "INSERT INTO mysql2_test2 (null_test) VALUES (NULL)"
71
- @test_result = Mysql2Test2.connection.execute("SELECT * FROM mysql2_test2 ORDER BY id DESC LIMIT 1").first
72
- end
73
-
74
- after(:all) do
75
- Mysql2Test2.connection.execute("DELETE FROM mysql2_test WHERE id=#{@test_result['id']}")
76
- end
77
-
78
- it "default value should be cast to the expected type of the field" do
79
- test = Mysql2Test2.new
80
- test.null_test.should be_nil
81
- test.bit_test.should eql("b'1'")
82
- test.boolean_test.should eql(false)
83
- test.tiny_int_test.should eql(1)
84
- test.small_int_test.should eql(1)
85
- test.medium_int_test.should eql(1)
86
- test.int_test.should eql(1)
87
- test.big_int_test.should eql(1)
88
- test.float_test.should eql('1.0000'.to_f)
89
- test.double_test.should eql('1.0000'.to_f)
90
- test.decimal_test.should eql(BigDecimal.new('1.0000'))
91
- test.date_test.should eql(Date.parse('2010-01-01'))
92
- test.date_time_test.should eql(DateTime.parse('2010-01-01 00:00:00'))
93
- test.timestamp_test.should be_nil
94
- test.time_test.class.should eql(DateTime)
95
- test.year_test.should eql(2010)
96
- test.char_test.should eql('abcdefghij')
97
- test.varchar_test.should eql('abcdefghij')
98
- test.binary_test.should eql('abcdefghij')
99
- test.varbinary_test.should eql('abcdefghij')
100
- test.tiny_blob_test.should eql("")
101
- test.tiny_text_test.should be_nil
102
- test.blob_test.should be_nil
103
- test.text_test.should be_nil
104
- test.medium_blob_test.should be_nil
105
- test.medium_text_test.should be_nil
106
- test.long_blob_test.should be_nil
107
- test.long_text_test.should be_nil
108
- test.long_blob_test.should be_nil
109
- test.enum_test.should eql('val1')
110
- test.set_test.should eql('val1,val2')
111
- test.save
112
- end
113
-
114
- it "should have correct values when pulled from a db record" do
115
- test = Mysql2Test2.last
116
- test.null_test.should be_nil
117
- test.bit_test.class.should eql(String)
118
- test.boolean_test.should eql(false)
119
- test.tiny_int_test.should eql(1)
120
- test.small_int_test.should eql(1)
121
- test.medium_int_test.should eql(1)
122
- test.int_test.should eql(1)
123
- test.big_int_test.should eql(1)
124
- test.float_test.should eql('1.0000'.to_f)
125
- test.double_test.should eql('1.0000'.to_f)
126
- test.decimal_test.should eql(BigDecimal.new('1.0000'))
127
- test.date_test.should eql(Date.parse('2010-01-01'))
128
- test.date_time_test.should eql(Time.utc(2010,1,1,0,0,0))
129
- test.timestamp_test.class.should eql(ActiveSupport::TimeWithZone)
130
- test.time_test.class.should eql(Time)
131
- test.year_test.should eql(2010)
132
- test.char_test.should eql('abcdefghij')
133
- test.varchar_test.should eql('abcdefghij')
134
- test.binary_test.should eql('abcdefghij')
135
- test.varbinary_test.should eql('abcdefghij')
136
- test.tiny_blob_test.should eql("")
137
- test.tiny_text_test.should be_nil
138
- test.blob_test.should be_nil
139
- test.text_test.should be_nil
140
- test.medium_blob_test.should be_nil
141
- test.medium_text_test.should be_nil
142
- test.long_blob_test.should be_nil
143
- test.long_text_test.should be_nil
144
- test.long_blob_test.should be_nil
145
- test.enum_test.should eql('val1')
146
- test.set_test.should eql('val1,val2')
147
- end
148
- end
149
- end