mysql2 0.2.18-x86-mswin32-60 → 0.3.9-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,64 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # AR adapter for using a fibered mysql2 connection with EM
4
- # This adapter should be used within Thin or Unicorn with the rack-fiber_pool middleware.
5
- # Just update your database.yml's adapter to be 'em_mysql2'
6
-
7
- module ActiveRecord
8
- class Base
9
- def self.em_mysql2_connection(config)
10
- client = ::Mysql2::Fibered::Client.new(config.symbolize_keys)
11
- options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
12
- ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
13
- end
14
- end
15
- end
16
-
17
- require 'fiber'
18
- require 'eventmachine'
19
- require 'mysql2'
20
- require 'active_record/connection_adapters/mysql2_adapter'
21
- require 'active_record/fiber_patches'
22
-
23
- module Mysql2
24
- module Fibered
25
- class Client < ::Mysql2::Client
26
- module Watcher
27
- def initialize(client, deferable)
28
- @client = client
29
- @deferable = deferable
30
- end
31
-
32
- def notify_readable
33
- begin
34
- detach
35
- results = @client.async_result
36
- @deferable.succeed(results)
37
- rescue Exception => e
38
- @deferable.fail(e)
39
- end
40
- end
41
- end
42
-
43
- def query(sql, opts={})
44
- if ::EM.reactor_running?
45
- super(sql, opts.merge(:async => true))
46
- deferrable = ::EM::DefaultDeferrable.new
47
- ::EM.watch(self.socket, Watcher, self, deferrable).notify_readable = true
48
- fiber = Fiber.current
49
- deferrable.callback do |result|
50
- fiber.resume(result)
51
- end
52
- deferrable.errback do |err|
53
- fiber.resume(err)
54
- end
55
- Fiber.yield.tap do |result|
56
- raise result if result.is_a?(Exception)
57
- end
58
- else
59
- super(sql, opts)
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1,605 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'mysql2'
4
-
5
- module ActiveRecord
6
- class Base
7
- def self.mysql2_connection(config)
8
- config[:username] = 'root' if config[:username].nil?
9
-
10
- if Mysql2::Client.const_defined? :FOUND_ROWS
11
- config[:flags] = Mysql2::Client::FOUND_ROWS
12
- end
13
-
14
- client = Mysql2::Client.new(config.symbolize_keys)
15
- options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
16
- ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
17
- end
18
- end
19
-
20
- module ConnectionAdapters
21
- class Mysql2IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
22
- end
23
-
24
- class Mysql2Column < Column
25
- BOOL = "tinyint(1)"
26
- def extract_default(default)
27
- if sql_type =~ /blob/i || type == :text
28
- if default.blank?
29
- return null ? nil : ''
30
- else
31
- raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
32
- end
33
- elsif missing_default_forged_as_empty_string?(default)
34
- nil
35
- else
36
- super
37
- end
38
- end
39
-
40
- def has_default?
41
- return false if sql_type =~ /blob/i || type == :text # mysql forbids defaults on blob and text columns
42
- super
43
- end
44
-
45
- private
46
- def simplified_type(field_type)
47
- return :boolean if Mysql2Adapter.emulate_booleans && field_type.downcase.index(BOOL)
48
- return :string if field_type =~ /enum/i or field_type =~ /set/i
49
- return :integer if field_type =~ /year/i
50
- return :binary if field_type =~ /bit/i
51
- super
52
- end
53
-
54
- def extract_limit(sql_type)
55
- case sql_type
56
- when /blob|text/i
57
- case sql_type
58
- when /tiny/i
59
- 255
60
- when /medium/i
61
- 16777215
62
- when /long/i
63
- 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases
64
- else
65
- super # we could return 65535 here, but we leave it undecorated by default
66
- end
67
- when /^bigint/i; 8
68
- when /^int/i; 4
69
- when /^mediumint/i; 3
70
- when /^smallint/i; 2
71
- when /^tinyint/i; 1
72
- else
73
- super
74
- end
75
- end
76
-
77
- # MySQL misreports NOT NULL column default when none is given.
78
- # We can't detect this for columns which may have a legitimate ''
79
- # default (string) but we can for others (integer, datetime, boolean,
80
- # and the rest).
81
- #
82
- # Test whether the column has default '', is not null, and is not
83
- # a type allowing default ''.
84
- def missing_default_forged_as_empty_string?(default)
85
- type != :string && !null && default == ''
86
- end
87
- end
88
-
89
- class Mysql2Adapter < AbstractAdapter
90
- cattr_accessor :emulate_booleans
91
- self.emulate_booleans = true
92
-
93
- ADAPTER_NAME = 'Mysql2'
94
- PRIMARY = "PRIMARY"
95
-
96
- LOST_CONNECTION_ERROR_MESSAGES = [
97
- "Server shutdown in progress",
98
- "Broken pipe",
99
- "Lost connection to MySQL server during query",
100
- "MySQL server has gone away" ]
101
-
102
- QUOTED_TRUE, QUOTED_FALSE = '1', '0'
103
-
104
- NATIVE_DATABASE_TYPES = {
105
- :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
106
- :string => { :name => "varchar", :limit => 255 },
107
- :text => { :name => "text" },
108
- :integer => { :name => "int", :limit => 4 },
109
- :float => { :name => "float" },
110
- :decimal => { :name => "decimal" },
111
- :datetime => { :name => "datetime" },
112
- :timestamp => { :name => "datetime" },
113
- :time => { :name => "time" },
114
- :date => { :name => "date" },
115
- :binary => { :name => "blob" },
116
- :boolean => { :name => "tinyint", :limit => 1 }
117
- }
118
-
119
- def initialize(connection, logger, connection_options, config)
120
- super(connection, logger)
121
- @connection_options, @config = connection_options, config
122
- @quoted_column_names, @quoted_table_names = {}, {}
123
- configure_connection
124
- end
125
-
126
- def adapter_name
127
- ADAPTER_NAME
128
- end
129
-
130
- def supports_migrations?
131
- true
132
- end
133
-
134
- def supports_primary_key?
135
- true
136
- end
137
-
138
- def supports_savepoints?
139
- true
140
- end
141
-
142
- def native_database_types
143
- NATIVE_DATABASE_TYPES
144
- end
145
-
146
- # QUOTING ==================================================
147
-
148
- def quote(value, column = nil)
149
- if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
150
- s = column.class.string_to_binary(value).unpack("H*")[0]
151
- "x'#{s}'"
152
- elsif value.kind_of?(BigDecimal)
153
- value.to_s("F")
154
- else
155
- super
156
- end
157
- end
158
-
159
- def quote_column_name(name) #:nodoc:
160
- @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
161
- end
162
-
163
- def quote_table_name(name) #:nodoc:
164
- @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`')
165
- end
166
-
167
- def quote_string(string)
168
- @connection.escape(string)
169
- end
170
-
171
- def quoted_true
172
- QUOTED_TRUE
173
- end
174
-
175
- def quoted_false
176
- QUOTED_FALSE
177
- end
178
-
179
- # REFERENTIAL INTEGRITY ====================================
180
-
181
- def disable_referential_integrity(&block) #:nodoc:
182
- old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
183
-
184
- begin
185
- update("SET FOREIGN_KEY_CHECKS = 0")
186
- yield
187
- ensure
188
- update("SET FOREIGN_KEY_CHECKS = #{old}")
189
- end
190
- end
191
-
192
- # CONNECTION MANAGEMENT ====================================
193
-
194
- def active?
195
- return false unless @connection
196
- @connection.ping
197
- end
198
-
199
- def reconnect!
200
- disconnect!
201
- connect
202
- end
203
-
204
- # this is set to true in 2.3, but we don't want it to be
205
- def requires_reloading?
206
- false
207
- end
208
-
209
- def disconnect!
210
- unless @connection.nil?
211
- @connection.close
212
- @connection = nil
213
- end
214
- end
215
-
216
- def reset!
217
- disconnect!
218
- connect
219
- end
220
-
221
- # DATABASE STATEMENTS ======================================
222
-
223
- # FIXME: re-enable the following once a "better" query_cache solution is in core
224
- #
225
- # The overrides below perform much better than the originals in AbstractAdapter
226
- # because we're able to take advantage of mysql2's lazy-loading capabilities
227
- #
228
- # # Returns a record hash with the column names as keys and column values
229
- # # as values.
230
- # def select_one(sql, name = nil)
231
- # result = execute(sql, name)
232
- # result.each(:as => :hash) do |r|
233
- # return r
234
- # end
235
- # end
236
- #
237
- # # Returns a single value from a record
238
- # def select_value(sql, name = nil)
239
- # result = execute(sql, name)
240
- # if first = result.first
241
- # first.first
242
- # end
243
- # end
244
- #
245
- # # Returns an array of the values of the first column in a select:
246
- # # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
247
- # def select_values(sql, name = nil)
248
- # execute(sql, name).map { |row| row.first }
249
- # end
250
-
251
- # Returns an array of arrays containing the field values.
252
- # Order is the same as that returned by +columns+.
253
- def select_rows(sql, name = nil)
254
- execute(sql, name).to_a
255
- end
256
-
257
- # Executes the SQL statement in the context of this connection.
258
- def execute(sql, name = nil)
259
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
260
- # made since we established the connection
261
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
262
- if name == :skip_logging
263
- @connection.query(sql)
264
- else
265
- log(sql, name) { @connection.query(sql) }
266
- end
267
- rescue ActiveRecord::StatementInvalid => exception
268
- if exception.message.split(":").first =~ /Packets out of order/
269
- raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
270
- else
271
- raise
272
- end
273
- end
274
-
275
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
276
- super
277
- id_value || @connection.last_id
278
- end
279
- alias :create :insert_sql
280
-
281
- def update_sql(sql, name = nil)
282
- super
283
- @connection.affected_rows
284
- end
285
-
286
- def begin_db_transaction
287
- execute "BEGIN"
288
- rescue Exception
289
- # Transactions aren't supported
290
- end
291
-
292
- def commit_db_transaction
293
- execute "COMMIT"
294
- rescue Exception
295
- # Transactions aren't supported
296
- end
297
-
298
- def rollback_db_transaction
299
- execute "ROLLBACK"
300
- rescue Exception
301
- # Transactions aren't supported
302
- end
303
-
304
- def create_savepoint
305
- execute("SAVEPOINT #{current_savepoint_name}")
306
- end
307
-
308
- def rollback_to_savepoint
309
- execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
310
- end
311
-
312
- def release_savepoint
313
- execute("RELEASE SAVEPOINT #{current_savepoint_name}")
314
- end
315
-
316
- def add_limit_offset!(sql, options)
317
- limit, offset = options[:limit], options[:offset]
318
- if limit && offset
319
- sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}"
320
- elsif limit
321
- sql << " LIMIT #{sanitize_limit(limit)}"
322
- elsif offset
323
- sql << " OFFSET #{offset.to_i}"
324
- end
325
- sql
326
- end
327
-
328
- # SCHEMA STATEMENTS ========================================
329
-
330
- def structure_dump
331
- if supports_views?
332
- sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
333
- else
334
- sql = "SHOW TABLES"
335
- end
336
-
337
- select_all(sql).inject("") do |structure, table|
338
- table.delete('Table_type')
339
- structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n"
340
- end
341
- end
342
-
343
- def recreate_database(name, options = {})
344
- drop_database(name)
345
- create_database(name, options)
346
- end
347
-
348
- # Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
349
- # Charset defaults to utf8.
350
- #
351
- # Example:
352
- # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin'
353
- # create_database 'matt_development'
354
- # create_database 'matt_development', :charset => :big5
355
- def create_database(name, options = {})
356
- if options[:collation]
357
- execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
358
- else
359
- execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
360
- end
361
- end
362
-
363
- def drop_database(name) #:nodoc:
364
- execute "DROP DATABASE IF EXISTS `#{name}`"
365
- end
366
-
367
- def current_database
368
- select_value 'SELECT DATABASE() as db'
369
- end
370
-
371
- # Returns the database character set.
372
- def charset
373
- show_variable 'character_set_database'
374
- end
375
-
376
- # Returns the database collation strategy.
377
- def collation
378
- show_variable 'collation_database'
379
- end
380
-
381
- def tables(name = nil)
382
- tables = []
383
- execute("SHOW TABLES", name).each do |field|
384
- tables << field.first
385
- end
386
- tables
387
- end
388
-
389
- def drop_table(table_name, options = {})
390
- super(table_name, options)
391
- end
392
-
393
- def indexes(table_name, name = nil)
394
- indexes = []
395
- current_index = nil
396
- result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
397
- result.each(:symbolize_keys => true, :as => :hash) do |row|
398
- if current_index != row[:Key_name]
399
- next if row[:Key_name] == PRIMARY # skip the primary key
400
- current_index = row[:Key_name]
401
- indexes << Mysql2IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], [])
402
- end
403
-
404
- indexes.last.columns << row[:Column_name]
405
- indexes.last.lengths << row[:Sub_part]
406
- end
407
- indexes
408
- end
409
-
410
- def columns(table_name, name = nil)
411
- sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
412
- columns = []
413
- result = execute(sql, :skip_logging)
414
- result.each(:symbolize_keys => true, :as => :hash) { |field|
415
- columns << Mysql2Column.new(field[:Field], field[:Default], field[:Type], field[:Null] == "YES")
416
- }
417
- columns
418
- end
419
-
420
- def create_table(table_name, options = {})
421
- super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB"))
422
- end
423
-
424
- def rename_table(table_name, new_name)
425
- execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
426
- end
427
-
428
- def add_column(table_name, column_name, type, options = {})
429
- add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
430
- add_column_options!(add_column_sql, options)
431
- add_column_position!(add_column_sql, options)
432
- execute(add_column_sql)
433
- end
434
-
435
- def change_column_default(table_name, column_name, default)
436
- column = column_for(table_name, column_name)
437
- change_column table_name, column_name, column.sql_type, :default => default
438
- end
439
-
440
- def change_column_null(table_name, column_name, null, default = nil)
441
- column = column_for(table_name, column_name)
442
-
443
- unless null || default.nil?
444
- execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
445
- end
446
-
447
- change_column table_name, column_name, column.sql_type, :null => null
448
- end
449
-
450
- def change_column(table_name, column_name, type, options = {})
451
- column = column_for(table_name, column_name)
452
-
453
- unless options_include_default?(options)
454
- options[:default] = column.default
455
- end
456
-
457
- unless options.has_key?(:null)
458
- options[:null] = column.null
459
- end
460
-
461
- change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
462
- add_column_options!(change_column_sql, options)
463
- add_column_position!(change_column_sql, options)
464
- execute(change_column_sql)
465
- end
466
-
467
- def rename_column(table_name, column_name, new_column_name)
468
- options = {}
469
- if column = columns(table_name).find { |c| c.name == column_name.to_s }
470
- options[:default] = column.default
471
- options[:null] = column.null
472
- else
473
- raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
474
- end
475
- current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
476
- rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
477
- add_column_options!(rename_column_sql, options)
478
- execute(rename_column_sql)
479
- end
480
-
481
- # Maps logical Rails types to MySQL-specific data types.
482
- def type_to_sql(type, limit = nil, precision = nil, scale = nil)
483
- return super unless type.to_s == 'integer'
484
-
485
- case limit
486
- when 1; 'tinyint'
487
- when 2; 'smallint'
488
- when 3; 'mediumint'
489
- when nil, 4, 11; 'int(11)' # compatibility with MySQL default
490
- when 5..8; 'bigint'
491
- else raise(ActiveRecordError, "No integer type has byte size #{limit}")
492
- end
493
- end
494
-
495
- def add_column_position!(sql, options)
496
- if options[:first]
497
- sql << " FIRST"
498
- elsif options[:after]
499
- sql << " AFTER #{quote_column_name(options[:after])}"
500
- end
501
- end
502
-
503
- def show_variable(name)
504
- variables = select_all("SHOW VARIABLES LIKE '#{name}'")
505
- variables.first['Value'] unless variables.empty?
506
- end
507
-
508
- def pk_and_sequence_for(table)
509
- keys = []
510
- result = execute("describe #{quote_table_name(table)}")
511
- result.each(:symbolize_keys => true, :as => :hash) do |row|
512
- keys << row[:Field] if row[:Key] == "PRI"
513
- end
514
- keys.length == 1 ? [keys.first, nil] : nil
515
- end
516
-
517
- # Returns just a table's primary key
518
- def primary_key(table)
519
- pk_and_sequence = pk_and_sequence_for(table)
520
- pk_and_sequence && pk_and_sequence.first
521
- end
522
-
523
- def case_sensitive_equality_operator
524
- "= BINARY"
525
- end
526
-
527
- def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
528
- where_sql
529
- end
530
-
531
- protected
532
- def quoted_columns_for_index(column_names, options = {})
533
- length = options[:length] if options.is_a?(Hash)
534
-
535
- quoted_column_names = case length
536
- when Hash
537
- column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) }
538
- when Fixnum
539
- column_names.map {|name| "#{quote_column_name(name)}(#{length})"}
540
- else
541
- column_names.map {|name| quote_column_name(name) }
542
- end
543
- end
544
-
545
- def translate_exception(exception, message)
546
- return super unless exception.respond_to?(:error_number)
547
-
548
- case exception.error_number
549
- when 1062
550
- RecordNotUnique.new(message, exception)
551
- when 1452
552
- InvalidForeignKey.new(message, exception)
553
- else
554
- super
555
- end
556
- end
557
-
558
- private
559
- def connect
560
- @connection = Mysql2::Client.new(@config)
561
- configure_connection
562
- end
563
-
564
- def configure_connection
565
- @connection.query_options.merge!(:as => :array)
566
-
567
- # By default, MySQL 'where id is null' selects the last inserted id.
568
- # Turn this off. http://dev.rubyonrails.org/ticket/6778
569
- variable_assignments = ['SQL_AUTO_IS_NULL=0']
570
- encoding = @config[:encoding]
571
-
572
- # make sure we set the encoding
573
- variable_assignments << "NAMES '#{encoding}'" if encoding
574
-
575
- # increase timeout so mysql server doesn't disconnect us
576
- wait_timeout = @config[:wait_timeout]
577
- wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
578
- variable_assignments << "@@wait_timeout = #{wait_timeout}"
579
-
580
- execute("SET #{variable_assignments.join(', ')}", :skip_logging)
581
- end
582
-
583
- # Returns an array of record hashes with the column names as keys and
584
- # column values as values.
585
- def select(sql, name = nil)
586
- execute(sql, name).each(:as => :hash)
587
- end
588
-
589
- def supports_views?
590
- version[0] >= 5
591
- end
592
-
593
- def version
594
- @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
595
- end
596
-
597
- def column_for(table_name, column_name)
598
- unless column = columns(table_name).find { |c| c.name == column_name.to_s }
599
- raise "No such column: #{table_name}.#{column_name}"
600
- end
601
- column
602
- end
603
- end
604
- end
605
- end