activerecord 1.13.0 → 1.13.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (68) hide show
  1. data/CHANGELOG +91 -0
  2. data/lib/active_record.rb +2 -2
  3. data/lib/active_record/acts/list.rb +16 -12
  4. data/lib/active_record/acts/tree.rb +2 -2
  5. data/lib/active_record/aggregations.rb +6 -0
  6. data/lib/active_record/associations.rb +38 -16
  7. data/lib/active_record/associations/has_many_association.rb +2 -1
  8. data/lib/active_record/associations/has_one_association.rb +1 -1
  9. data/lib/active_record/base.rb +46 -33
  10. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +33 -9
  11. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +11 -2
  12. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -0
  13. data/lib/active_record/connection_adapters/abstract_adapter.rb +41 -21
  14. data/lib/active_record/connection_adapters/firebird_adapter.rb +414 -0
  15. data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -29
  16. data/lib/active_record/connection_adapters/oci_adapter.rb +141 -21
  17. data/lib/active_record/connection_adapters/postgresql_adapter.rb +82 -21
  18. data/lib/active_record/connection_adapters/sqlite_adapter.rb +3 -3
  19. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +39 -6
  20. data/lib/active_record/fixtures.rb +1 -0
  21. data/lib/active_record/migration.rb +30 -13
  22. data/lib/active_record/validations.rb +18 -7
  23. data/lib/active_record/vendor/mysql.rb +89 -12
  24. data/lib/active_record/version.rb +2 -2
  25. data/rakefile +38 -3
  26. data/test/abstract_unit.rb +5 -0
  27. data/test/aggregations_test.rb +19 -0
  28. data/test/associations_go_eager_test.rb +26 -2
  29. data/test/associations_test.rb +29 -10
  30. data/test/base_test.rb +57 -6
  31. data/test/binary_test.rb +3 -3
  32. data/test/connections/native_db2/connection.rb +1 -1
  33. data/test/connections/native_firebird/connection.rb +24 -0
  34. data/test/connections/native_mysql/connection.rb +1 -1
  35. data/test/connections/native_oci/connection.rb +1 -1
  36. data/test/connections/native_postgresql/connection.rb +6 -6
  37. data/test/connections/native_sqlite/connection.rb +1 -1
  38. data/test/connections/native_sqlite3/connection.rb +1 -1
  39. data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
  40. data/test/connections/native_sqlserver/connection.rb +1 -1
  41. data/test/connections/native_sqlserver_odbc/connection.rb +1 -1
  42. data/test/default_test_firebird.rb +16 -0
  43. data/test/deprecated_associations_test.rb +1 -1
  44. data/test/finder_test.rb +11 -1
  45. data/test/fixtures/author.rb +30 -30
  46. data/test/fixtures/comment.rb +1 -1
  47. data/test/fixtures/company.rb +3 -1
  48. data/test/fixtures/customer.rb +4 -0
  49. data/test/fixtures/db_definitions/firebird.drop.sql +54 -0
  50. data/test/fixtures/db_definitions/firebird.sql +259 -0
  51. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  52. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  53. data/test/fixtures/db_definitions/oci.sql +8 -0
  54. data/test/fixtures/db_definitions/postgresql.sql +3 -2
  55. data/test/fixtures/developer.rb +10 -0
  56. data/test/fixtures/fixture_database.sqlite +0 -0
  57. data/test/fixtures/fixture_database_2.sqlite +0 -0
  58. data/test/fixtures/mixin.rb +11 -1
  59. data/test/fixtures/mixins.yml +20 -1
  60. data/test/fixtures_test.rb +65 -45
  61. data/test/inheritance_test.rb +1 -1
  62. data/test/migration_test.rb +7 -1
  63. data/test/mixin_test.rb +267 -98
  64. data/test/multiple_db_test.rb +13 -1
  65. data/test/pk_test.rb +1 -0
  66. metadata +11 -5
  67. data/lib/active_record/vendor/mysql411.rb +0 -311
  68. data/test/debug.log +0 -2857
@@ -47,7 +47,7 @@ module ActiveRecord
47
47
  def parse_config!(config)
48
48
  config[:database] ||= config[:dbfile]
49
49
  # Require database.
50
- unless config.has_key?(:database)
50
+ unless config[:database]
51
51
  raise ArgumentError, "No database file specified. Missing argument: database"
52
52
  end
53
53
 
@@ -55,7 +55,7 @@ module ActiveRecord
55
55
  # the database path is not the special path that tells
56
56
  # Sqlite build a database only in memory.
57
57
  if Object.const_defined?(:RAILS_ROOT) && ':memory:' != config[:database]
58
- config[:database] = File.expand_path(config[:database], RAILS_ROOT)
58
+ config[:database] = File.join(RAILS_ROOT, config[:database])
59
59
  end
60
60
  end
61
61
  end
@@ -123,7 +123,7 @@ module ActiveRecord
123
123
  end
124
124
 
125
125
  def quote_column_name(name) #:nodoc:
126
- "'#{name}'"
126
+ %Q("#{name}")
127
127
  end
128
128
 
129
129
 
@@ -30,16 +30,17 @@ module ActiveRecord
30
30
  if mode == "ODBC"
31
31
  raise ArgumentError, "Missing DSN. Argument ':dsn' must be set in order for this adapter to work." unless config.has_key?(:dsn)
32
32
  dsn = config[:dsn]
33
- conn = DBI.connect("DBI:ODBC:#{dsn}", username, password)
33
+ driver_url = "DBI:ODBC:#{dsn}"
34
34
  else
35
35
  raise ArgumentError, "Missing Database. Argument ':database' must be set in order for this adapter to work." unless config.has_key?(:database)
36
36
  database = config[:database]
37
37
  host = config[:host] ? config[:host].to_s : 'localhost'
38
- conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=#{host};Initial Catalog=#{database};User Id=#{username};Password=#{password};")
38
+ driver_url = "DBI:ADO:Provider=SQLOLEDB;Data Source=#{host};Initial Catalog=#{database};User Id=#{username};Password=#{password};"
39
39
  end
40
+ conn = DBI.connect(driver_url, username, password)
40
41
 
41
42
  conn["AutoCommit"] = true
42
- ConnectionAdapters::SQLServerAdapter.new(conn, logger)
43
+ ConnectionAdapters::SQLServerAdapter.new(conn, logger, [driver_url, username, password])
43
44
  end
44
45
  end # class Base
45
46
 
@@ -52,6 +53,8 @@ module ActiveRecord
52
53
  @identity = is_identity
53
54
  @is_special = sql_type =~ /text|ntext|image/i ? true : false
54
55
  @scale = scale_value
56
+ # SQL Server only supports limits on *char and float types
57
+ @limit = nil unless @type == :float or @type == :string
55
58
  end
56
59
 
57
60
  def simplified_type(field_type)
@@ -170,6 +173,12 @@ module ActiveRecord
170
173
  # unixODBC 2.2.11, Ruby ODBC 0.996, Ruby DBI 0.0.23 and Ruby 1.8.2.
171
174
  # [Linux strongmad 2.6.11-1.1369_FC4 #1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux]
172
175
  class SQLServerAdapter < AbstractAdapter
176
+
177
+ def initialize(connection, logger, connection_options=nil)
178
+ super(connection, logger)
179
+ @connection_options = connection_options
180
+ end
181
+
173
182
  def native_database_types
174
183
  {
175
184
  :primary_key => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY",
@@ -194,6 +203,25 @@ module ActiveRecord
194
203
  true
195
204
  end
196
205
 
206
+ # CONNECTION MANAGEMENT ====================================#
207
+
208
+ # Returns true if the connection is active.
209
+ def active?
210
+ @connection.execute("SELECT 1") { }
211
+ true
212
+ rescue DBI::DatabaseError, DBI::InterfaceError
213
+ false
214
+ end
215
+
216
+ # Reconnects to the database, returns false if no connection could be made.
217
+ def reconnect!
218
+ @connection.disconnect rescue nil
219
+ @connection = DBI.connect(*@connection_options)
220
+ rescue DBI::DatabaseError => e
221
+ @logger.warn "#{adapter_name} reconnection failed: #{e.message}" if @logger
222
+ false
223
+ end
224
+
197
225
  def select_all(sql, name = nil)
198
226
  select(sql, name)
199
227
  end
@@ -234,7 +262,7 @@ module ActiveRecord
234
262
  end
235
263
  log(sql, name) do
236
264
  @connection.execute(sql)
237
- select_one("SELECT @@IDENTITY AS Ident")["Ident"]
265
+ id_value || select_one("SELECT @@IDENTITY AS Ident")["Ident"]
238
266
  end
239
267
  ensure
240
268
  if ii_enabled
@@ -328,7 +356,12 @@ module ActiveRecord
328
356
  if options[:order]
329
357
  options[:order] = options[:order].split(',').map do |field|
330
358
  parts = field.split(" ")
331
- if sql =~ /#{parts[0]} AS (t\d_r\d\d?)/
359
+ tc = parts[0]
360
+ if sql =~ /\.\[/ and tc =~ /\./ # if column quoting used in query
361
+ tc.gsub!(/\./, '\\.\\[')
362
+ tc << '\\]'
363
+ end
364
+ if sql =~ /#{tc} AS (t\d_r\d\d?)/
332
365
  parts[0] = $1
333
366
  end
334
367
  parts.join(' ')
@@ -478,7 +511,7 @@ module ActiveRecord
478
511
  case order
479
512
  when /DESC/i then order.gsub(/DESC/i, "ASC")
480
513
  when /ASC/i then order.gsub(/ASC/i, "DESC")
481
- else String.new(order).insert(-1, " DESC")
514
+ else String.new(order).split(',').join(' DESC,') + ' DESC'
482
515
  end
483
516
  end
484
517
 
@@ -508,6 +508,7 @@ module Test #:nodoc:
508
508
  ActiveRecord::Base.connection.rollback_db_transaction
509
509
  ActiveRecord::Base.unlock_mutex
510
510
  end
511
+ ActiveRecord::Base.clear_connection_cache!
511
512
  end
512
513
 
513
514
  alias_method :teardown, :teardown_with_fixtures
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  # def self.up
21
21
  # add_column :accounts, :ssl_enabled, :boolean, :default => 1
22
22
  # end
23
- #
23
+ #
24
24
  # def self.down
25
25
  # remove_column :accounts, :ssl_enabled
26
26
  # end
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  #
29
29
  # This migration will add a boolean flag to the accounts table and remove it again, if you're backing out of the migration.
30
30
  # It shows how all migrations have two class methods +up+ and +down+ that describes the transformations required to implement
31
- # or remove the migration. These methods can consist of both the migration specific methods, like add_column and remove_column,
31
+ # or remove the migration. These methods can consist of both the migration specific methods, like add_column and remove_column,
32
32
  # but may also contain regular Ruby code for generating data needed for the transformations.
33
33
  #
34
34
  # Example of a more complex migration that also needs to initialize data:
@@ -42,10 +42,10 @@ module ActiveRecord
42
42
  # t.column :type, :string
43
43
  # t.column :position, :integer
44
44
  # end
45
- #
45
+ #
46
46
  # SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
47
47
  # end
48
- #
48
+ #
49
49
  # def self.down
50
50
  # drop_table :system_settings
51
51
  # end
@@ -79,13 +79,29 @@ module ActiveRecord
79
79
  #
80
80
  # == Running migrations from within Rails
81
81
  #
82
- # The Rails package has support for migrations with the <tt>script/generate migration my_new_migration</tt> command and
83
- # with the <tt>rake migrate</tt> command that'll run all the pending migrations. It'll even create the needed schema_info
84
- # table automatically if it's missing.
82
+ # The Rails package has several tools to help create and apply migrations.
83
+ #
84
+ # To generate a new migration, use <tt>script/generate migration MyNewMigration</tt>
85
+ # where MyNewMigration is the name of your migration. The generator will
86
+ # create a file <tt>nnn_my_new_migration.rb</tt> in the <tt>db/migrate/</tt>
87
+ # directory, where <tt>nnn</tt> is the next largest migration number.
88
+ # You may then edit the <tt>self.up</tt> and <tt>self.down</tt> methods of
89
+ # n MyNewMigration.
90
+ #
91
+ # To run migrations against the currently configured database, use
92
+ # <tt>rake migrate</tt>. This will update the database by running all of the
93
+ # pending migrations, creating the <tt>schema_info</tt> table if missing.
94
+ #
95
+ # To roll the database back to a previous migration version, use
96
+ # <tt>rake migrate version=X</tt> where <tt>X</tt> is the version to which
97
+ # you wish to downgrade. If any of the migrations throw an
98
+ # <tt>IrreversibleMigration</tt> exception, that step will fail and you'll
99
+ # have some manual work to do.
85
100
  #
86
101
  # == Database support
87
102
  #
88
- # Migrations are currently only supported in MySQL and PostgreSQL.
103
+ # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
104
+ # SQL Server, and Oracle (all supported databases except DB2).
89
105
  #
90
106
  # == More examples
91
107
  #
@@ -95,7 +111,7 @@ module ActiveRecord
95
111
  # def self.up
96
112
  # Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? }
97
113
  # end
98
- #
114
+ #
99
115
  # def self.down
100
116
  # # not much we can do to restore deleted data
101
117
  # raise IrreversibleMigration
@@ -128,20 +144,21 @@ module ActiveRecord
128
144
  # end
129
145
  # end
130
146
  #
131
- # == Using the class after changing table
147
+ # == Using a model after changing its table
132
148
  #
133
149
  # Sometimes you'll want to add a column in a migration and populate it immediately after. In that case, you'll need
134
- # to make a call to Base#reset_column_information in order to ensure that the class has the latest column data from
150
+ # to make a call to Base#reset_column_information in order to ensure that the model has the latest column data from
135
151
  # after the new column was added. Example:
136
152
  #
137
- # class MakeJoinUnique < ActiveRecord::Migration
153
+ # class AddPeopleSalary < ActiveRecord::Migration
138
154
  # def self.up
139
155
  # add_column :people, :salary, :integer
156
+ # Person.reset_column_information
140
157
  # Person.find(:all).each do |p|
141
158
  # p.salary = SalaryCalculator.compute(p)
142
159
  # end
143
160
  # end
144
- # end
161
+ # end
145
162
  class Migration
146
163
  class << self
147
164
  def up() end
@@ -17,6 +17,8 @@ module ActiveRecord
17
17
  # Active Record validation is reported to and from this object, which is used by Base#save to
18
18
  # determine whether the object in a valid state to be saved. See usage example in Validations.
19
19
  class Errors
20
+ include Enumerable
21
+
20
22
  def initialize(base) # :nodoc:
21
23
  @base, @errors = base, {}
22
24
  end
@@ -485,13 +487,20 @@ module ActiveRecord
485
487
  configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken] }
486
488
  configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
487
489
 
488
- if scope = configuration[:scope]
489
- validates_each(attr_names,configuration) do |record, attr_name, value|
490
- record.errors.add(attr_name, configuration[:message]) if record.class.find(:first, :conditions => (record.new_record? ? ["#{attr_name} = ? AND #{scope} = ?", record.send(attr_name), record.send(scope)] : ["#{attr_name} = ? AND #{record.class.primary_key} <> ? AND #{scope} = ?", record.send(attr_name), record.send(:id), record.send(scope)]))
490
+ validates_each(attr_names,configuration) do |record, attr_name, value|
491
+ condition_sql = "#{attr_name} #{attribute_condition(value)}"
492
+ condition_params = [value]
493
+ if scope = configuration[:scope]
494
+ scope_value = record.send(scope)
495
+ condition_sql << " AND #{scope} #{attribute_condition(scope_value)}"
496
+ condition_params << scope_value
491
497
  end
492
- else
493
- validates_each(attr_names,configuration) do |record, attr_name, value|
494
- record.errors.add(attr_name, configuration[:message]) if record.class.find(:first, :conditions => (record.new_record? ? ["#{attr_name} = ?", record.send(attr_name)] : ["#{attr_name} = ? AND #{record.class.primary_key} <> ?", record.send(attr_name), record.send(:id) ] ))
498
+ unless record.new_record?
499
+ condition_sql << " AND #{record.class.primary_key} <> ?"
500
+ condition_params << record.send(:id)
501
+ end
502
+ if record.class.find(:first, :conditions => [condition_sql, *condition_params])
503
+ record.errors.add(attr_name, configuration[:message])
495
504
  end
496
505
  end
497
506
  end
@@ -500,7 +509,7 @@ module ActiveRecord
500
509
  # provided.
501
510
  #
502
511
  # class Person < ActiveRecord::Base
503
- # validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/, :on => :create
512
+ # validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :on => :create
504
513
  # end
505
514
  #
506
515
  # A regular expression must be provided or else an exception will be raised.
@@ -658,6 +667,8 @@ module ActiveRecord
658
667
  if attributes.is_a?(Array)
659
668
  attributes.collect { |attr| create!(attr) }
660
669
  else
670
+ attributes.reverse_merge!(scope(:create)) if scoped?(:create)
671
+
661
672
  object = new(attributes)
662
673
  object.save!
663
674
  object
@@ -1,14 +1,15 @@
1
- # $Id: mysql.rb,v 1.1 2004/02/24 15:42:29 webster132 Exp $
1
+ # $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $
2
2
  #
3
- # Copyright (C) 2003 TOMITA Masahiro
3
+ # Copyright (C) 2003-2005 TOMITA Masahiro
4
4
  # tommy@tmtm.org
5
5
  #
6
6
 
7
7
  class Mysql
8
8
 
9
- VERSION = "4.0-ruby-0.2.4"
9
+ VERSION = "4.0-ruby-0.2.5"
10
10
 
11
11
  require "socket"
12
+ require "digest/sha1"
12
13
 
13
14
  MAX_PACKET_LENGTH = 256*256*256-1
14
15
  MAX_ALLOWED_PACKET = 1024*1024*1024
@@ -51,11 +52,15 @@ class Mysql
51
52
  CLIENT_ODBC = 1 << 6
52
53
  CLIENT_LOCAL_FILES = 1 << 7
53
54
  CLIENT_IGNORE_SPACE = 1 << 8
55
+ CLIENT_PROTOCOL_41 = 1 << 9
54
56
  CLIENT_INTERACTIVE = 1 << 10
55
57
  CLIENT_SSL = 1 << 11
56
58
  CLIENT_IGNORE_SIGPIPE = 1 << 12
57
59
  CLIENT_TRANSACTIONS = 1 << 13
60
+ CLIENT_RESERVED = 1 << 14
61
+ CLIENT_SECURE_CONNECTION = 1 << 15
58
62
  CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS
63
+ PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION
59
64
 
60
65
  # Connection Option
61
66
  OPT_CONNECT_TIMEOUT = 0
@@ -115,19 +120,37 @@ class Mysql
115
120
  @server_capabilities, = a.slice!(0,2).unpack("v")
116
121
  end
117
122
  if a.size >= 16 then
118
- @server_language, @server_status = a.unpack("cv")
123
+ @server_language, @server_status = a.slice!(0,3).unpack("cv")
119
124
  end
120
125
 
121
126
  flag = 0 if flag == nil
122
127
  flag |= @client_flag | CLIENT_CAPABILITIES
123
128
  flag |= CLIENT_CONNECT_WITH_DB if db
124
- data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+(user||"")+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)
129
+
130
+ if !@server_capabilities & PROTO_AUTH41
131
+ data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+
132
+ (user||"")+"\0"+
133
+ scramble(passwd, @scramble_buff, @protocol_version==9)
134
+ else
135
+ dummy, @salt2 = a.unpack("a13a12")
136
+ @scramble_buff += @salt2
137
+ flag |= PROTO_AUTH41
138
+ data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) +
139
+ ([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+
140
+ scramble41(passwd, @scramble_buff)
141
+ end
142
+
125
143
  if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0 then
126
- data << "\0"+db
144
+ if PROTO_AUTH41
145
+ data << db+"\0"
146
+ else
147
+ data << "\0"+db
148
+ end
127
149
  @db = db.dup
128
150
  end
129
151
  write data
130
152
  read
153
+ ObjectSpace.define_finalizer(self, Mysql.finalizer(@net))
131
154
  self
132
155
  end
133
156
  alias :connect :real_connect
@@ -182,7 +205,11 @@ class Mysql
182
205
  end
183
206
 
184
207
  def change_user(user="", passwd="", db="")
208
+ if !@server_capabilities & PROTO_AUTH41
185
209
  data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db
210
+ else
211
+ data = user+"\0"+ scramble41(passwd, @scramble_buff)
212
+ end
186
213
  command COM_CHANGE_USER, data
187
214
  @user = user
188
215
  @passwd = passwd
@@ -243,7 +270,11 @@ class Mysql
243
270
 
244
271
  def list_fields(table, field=nil)
245
272
  command COM_FIELD_LIST, "#{table}\0#{field}", true
273
+ if !@server_capabilities & PROTO_AUTH41
246
274
  f = read_rows 6
275
+ else
276
+ f = read_rows 7
277
+ end
247
278
  fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0)
248
279
  res = Result::new self, fields, f.length
249
280
  res.eof = true
@@ -253,7 +284,11 @@ class Mysql
253
284
  def list_processes()
254
285
  data = command COM_PROCESS_INFO
255
286
  @field_count = get_length data
287
+ if !@server_capabilities & PROTO_AUTH41
256
288
  fields = read_rows 5
289
+ else
290
+ fields = read_rows 7
291
+ end
257
292
  @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
258
293
  @status = :STATUS_GET_RESULT
259
294
  store_result
@@ -311,7 +346,11 @@ class Mysql
311
346
 
312
347
  def read_one_row(field_count)
313
348
  data = read
314
- return if data[0] == 254 and data.length == 1
349
+ if data[0] == 254 and data.length == 1 ## EOF
350
+ return
351
+ elsif data[0] == 254 and data.length == 5
352
+ return
353
+ end
315
354
  rec = []
316
355
  field_count.times do
317
356
  len = get_length data
@@ -363,7 +402,11 @@ class Mysql
363
402
  end
364
403
  else
365
404
  @extra_info = get_length(data, true)
405
+ if !@server_capabilities & PROTO_AUTH41
366
406
  fields = read_rows 5
407
+ else
408
+ fields = read_rows(7)
409
+ end
367
410
  @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
368
411
  @status = :STATUS_GET_RESULT
369
412
  end
@@ -373,6 +416,7 @@ class Mysql
373
416
  def unpack_fields(data, long_flag_protocol)
374
417
  ret = []
375
418
  data.each do |f|
419
+ if !@server_capabilities & PROTO_AUTH41
376
420
  table = org_table = f[0]
377
421
  name = f[1]
378
422
  length = f[2][0]+f[2][1]*256+f[2][2]*256*256
@@ -386,8 +430,22 @@ class Mysql
386
430
  end
387
431
  def_value = f[5]
388
432
  max_length = 0
433
+ else
434
+ catalog = f[0]
435
+ db = f[1]
436
+ table = f[2]
437
+ org_table = f[3]
438
+ name = f[4]
439
+ org_name = f[5]
440
+ length = f[6][2]+f[6][3]*256+f[6][4]*256*256
441
+ type = f[6][6]
442
+ flags = f[6][7]+f[6][8]*256
443
+ decimals = f[6][9]
444
+ def_value = ""
445
+ max_length = 0
389
446
  ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length)
390
447
  end
448
+ end
391
449
  ret
392
450
  end
393
451
 
@@ -489,6 +547,19 @@ class Mysql
489
547
  to.join
490
548
  end
491
549
 
550
+ def scramble41(password, message)
551
+ if password.length != 0
552
+ buf = [0x14]
553
+ s1 = Digest::SHA1.new(password).digest
554
+ s2 = Digest::SHA1.new(s1).digest
555
+ x = Digest::SHA1.new(message + s2).digest
556
+ (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
557
+ buf.pack("C*")
558
+ else
559
+ 0x00.chr
560
+ end
561
+ end
562
+
492
563
  def error(errno)
493
564
  @errno = errno
494
565
  @error = Error::err errno
@@ -574,7 +645,6 @@ class Mysql
574
645
  def free()
575
646
  @handle.skip_result
576
647
  @handle = @fields = @data = nil
577
- GC::start
578
648
  end
579
649
 
580
650
  def num_fields()
@@ -1023,8 +1093,8 @@ class Mysql
1023
1093
  @sock.sync = true
1024
1094
  buf.join
1025
1095
  rescue
1026
- errno = Error::CR_SERVER_LOST
1027
- raise Error::new(errno, Error::err(errno))
1096
+ errno = Error::CR_SERVER_LOST
1097
+ raise Error::new(errno, Error::err(errno))
1028
1098
  end
1029
1099
 
1030
1100
  def write(data)
@@ -1043,8 +1113,8 @@ class Mysql
1043
1113
  @sock.sync = true
1044
1114
  @sock.flush
1045
1115
  rescue
1046
- errno = Error::CR_SERVER_LOST
1047
- raise Error::new(errno, Error::err(errno))
1116
+ errno = Error::CR_SERVER_LOST
1117
+ raise Error::new(errno, Error::err(errno))
1048
1118
  end
1049
1119
 
1050
1120
  def close()
@@ -1091,6 +1161,13 @@ class << Mysql
1091
1161
  end
1092
1162
  alias :connect :real_connect
1093
1163
 
1164
+ def finalizer(net)
1165
+ proc {
1166
+ net.clear
1167
+ net.write Mysql::COM_QUIT.chr
1168
+ }
1169
+ end
1170
+
1094
1171
  def escape_string(str)
1095
1172
  str.gsub(/([\0\n\r\032\'\"\\])/) do
1096
1173
  case $1