activerecord 1.13.2 → 1.14.0

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 (144) hide show
  1. data/CHANGELOG +452 -10
  2. data/RUNNING_UNIT_TESTS +1 -1
  3. data/lib/active_record.rb +5 -2
  4. data/lib/active_record/acts/list.rb +1 -1
  5. data/lib/active_record/acts/tree.rb +29 -25
  6. data/lib/active_record/aggregations.rb +3 -2
  7. data/lib/active_record/associations.rb +783 -337
  8. data/lib/active_record/associations/association_collection.rb +7 -12
  9. data/lib/active_record/associations/association_proxy.rb +62 -24
  10. data/lib/active_record/associations/belongs_to_association.rb +27 -46
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  12. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
  13. data/lib/active_record/associations/has_many_association.rb +61 -56
  14. data/lib/active_record/associations/has_many_through_association.rb +144 -0
  15. data/lib/active_record/associations/has_one_association.rb +22 -16
  16. data/lib/active_record/base.rb +482 -182
  17. data/lib/active_record/calculations.rb +225 -0
  18. data/lib/active_record/callbacks.rb +7 -7
  19. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
  20. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
  22. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
  23. data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
  24. data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
  25. data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
  26. data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
  27. data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
  29. data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
  30. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
  31. data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
  32. data/lib/active_record/fixtures.rb +42 -17
  33. data/lib/active_record/locking.rb +36 -15
  34. data/lib/active_record/migration.rb +111 -8
  35. data/lib/active_record/observer.rb +25 -1
  36. data/lib/active_record/reflection.rb +103 -41
  37. data/lib/active_record/schema.rb +2 -2
  38. data/lib/active_record/schema_dumper.rb +55 -18
  39. data/lib/active_record/timestamp.rb +6 -6
  40. data/lib/active_record/validations.rb +65 -40
  41. data/lib/active_record/vendor/db2.rb +10 -5
  42. data/lib/active_record/vendor/simple.rb +693 -702
  43. data/lib/active_record/version.rb +2 -2
  44. data/rakefile +4 -4
  45. data/test/aaa_create_tables_test.rb +25 -6
  46. data/test/abstract_unit.rb +39 -1
  47. data/test/adapter_test.rb +31 -4
  48. data/test/associations_cascaded_eager_loading_test.rb +106 -0
  49. data/test/associations_go_eager_test.rb +85 -16
  50. data/test/associations_join_model_test.rb +338 -0
  51. data/test/associations_test.rb +129 -50
  52. data/test/base_test.rb +204 -49
  53. data/test/binary_test.rb +1 -1
  54. data/test/calculations_test.rb +169 -0
  55. data/test/callbacks_test.rb +5 -23
  56. data/test/class_inheritable_attributes_test.rb +1 -1
  57. data/test/column_alias_test.rb +1 -1
  58. data/test/connections/native_mysql/connection.rb +1 -0
  59. data/test/connections/native_openbase/connection.rb +22 -0
  60. data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
  61. data/test/connections/native_sqlite/connection.rb +1 -1
  62. data/test/connections/native_sqlite3/connection.rb +1 -0
  63. data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
  64. data/test/connections/native_sybase/connection.rb +24 -0
  65. data/test/defaults_test.rb +18 -0
  66. data/test/deprecated_associations_test.rb +2 -2
  67. data/test/deprecated_finder_test.rb +0 -6
  68. data/test/finder_test.rb +26 -23
  69. data/test/fixtures/accounts.yml +10 -0
  70. data/test/fixtures/author.rb +31 -6
  71. data/test/fixtures/author_favorites.yml +4 -0
  72. data/test/fixtures/categories/special_categories.yml +9 -0
  73. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  74. data/test/fixtures/categories_posts.yml +4 -0
  75. data/test/fixtures/categorization.rb +5 -0
  76. data/test/fixtures/categorizations.yml +11 -0
  77. data/test/fixtures/category.rb +6 -0
  78. data/test/fixtures/company.rb +17 -5
  79. data/test/fixtures/company_in_module.rb +19 -5
  80. data/test/fixtures/db_definitions/db2.drop.sql +3 -0
  81. data/test/fixtures/db_definitions/db2.sql +121 -100
  82. data/test/fixtures/db_definitions/db22.sql +2 -2
  83. data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
  84. data/test/fixtures/db_definitions/firebird.sql +26 -0
  85. data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
  86. data/test/fixtures/db_definitions/mysql.sql +21 -1
  87. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  88. data/test/fixtures/db_definitions/openbase.sql +282 -0
  89. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  90. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  91. data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
  92. data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
  93. data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
  94. data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
  95. data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
  96. data/test/fixtures/db_definitions/postgresql.sql +22 -1
  97. data/test/fixtures/db_definitions/schema.rb +32 -0
  98. data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
  99. data/test/fixtures/db_definitions/sqlite.sql +18 -0
  100. data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
  101. data/test/fixtures/db_definitions/sqlserver.sql +23 -3
  102. data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
  103. data/test/fixtures/db_definitions/sybase.sql +204 -0
  104. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  105. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  106. data/test/fixtures/developers.yml +6 -1
  107. data/test/fixtures/developers_projects.yml +4 -0
  108. data/test/fixtures/funny_jokes.yml +14 -0
  109. data/test/fixtures/joke.rb +6 -0
  110. data/test/fixtures/legacy_thing.rb +3 -0
  111. data/test/fixtures/legacy_things.yml +3 -0
  112. data/test/fixtures/mixin.rb +1 -1
  113. data/test/fixtures/person.rb +4 -1
  114. data/test/fixtures/post.rb +26 -1
  115. data/test/fixtures/project.rb +1 -0
  116. data/test/fixtures/reader.rb +4 -0
  117. data/test/fixtures/readers.yml +4 -0
  118. data/test/fixtures/reply.rb +2 -1
  119. data/test/fixtures/tag.rb +5 -0
  120. data/test/fixtures/tagging.rb +6 -0
  121. data/test/fixtures/taggings.yml +18 -0
  122. data/test/fixtures/tags.yml +7 -0
  123. data/test/fixtures/tasks.yml +2 -2
  124. data/test/fixtures/topic.rb +2 -2
  125. data/test/fixtures/topics.yml +1 -0
  126. data/test/fixtures_test.rb +47 -13
  127. data/test/inheritance_test.rb +2 -2
  128. data/test/locking_test.rb +15 -1
  129. data/test/method_scoping_test.rb +248 -13
  130. data/test/migration_test.rb +68 -11
  131. data/test/mixin_nested_set_test.rb +1 -1
  132. data/test/modules_test.rb +6 -1
  133. data/test/readonly_test.rb +1 -1
  134. data/test/reflection_test.rb +63 -9
  135. data/test/schema_dumper_test.rb +41 -0
  136. data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
  137. data/test/threaded_connections_test.rb +10 -0
  138. data/test/unconnected_test.rb +12 -5
  139. data/test/validations_test.rb +197 -10
  140. metadata +295 -260
  141. data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
  142. data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
  143. data/test/fixtures/fixture_database.sqlite +0 -0
  144. data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  def quote(value, column = nil)
7
7
  case value
8
8
  when String
9
- if column && column.type == :binary
9
+ if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
10
10
  "'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
11
11
  elsif column && [:integer, :float].include?(column.type)
12
12
  value.to_s
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module ConnectionAdapters #:nodoc:
5
5
  # An abstract definition of a column in a table.
6
6
  class Column
7
- attr_reader :name, :default, :type, :limit, :null
7
+ attr_reader :name, :default, :type, :limit, :null, :sql_type
8
8
  attr_accessor :primary
9
9
 
10
10
  # Instantiates a new column in the table.
@@ -15,6 +15,7 @@ module ActiveRecord
15
15
  # +null+ determines if this column allows +NULL+ values.
16
16
  def initialize(name, default, sql_type = nil, null = true)
17
17
  @name, @type, @null = name, simplified_type(sql_type), null
18
+ @sql_type = sql_type
18
19
  # have to do this one separately because type_cast depends on #type
19
20
  @default = type_cast(default)
20
21
  @limit = extract_limit(sql_type) unless sql_type.nil?
@@ -8,6 +8,16 @@ module ActiveRecord
8
8
  {}
9
9
  end
10
10
 
11
+ # This is the maximum length a table alias can be
12
+ def table_alias_length
13
+ 255
14
+ end
15
+
16
+ # Truncates a table alias according to the limits of the current adapter.
17
+ def table_alias_for(table_name)
18
+ table_name[0..table_alias_length-1].gsub(/\./, '_')
19
+ end
20
+
11
21
  # def tables(name = nil) end
12
22
 
13
23
  # Returns an array of indexes for the given table.
@@ -153,6 +163,13 @@ module ActiveRecord
153
163
  # The index will be named after the table and the first column names,
154
164
  # unless you pass +:name+ as an option.
155
165
  #
166
+ # When creating an index on multiple columns, the first column is used as a name
167
+ # for the index. For example, when you specify an index on two columns
168
+ # [+:first+, +:last+], the DBMS creates an index for both columns as well as an
169
+ # index for the first colum +:first+. Using just the first name for this index
170
+ # makes sense, because you will never have to create a singular index with this
171
+ # name.
172
+ #
156
173
  # ===== Examples
157
174
  # ====== Creating a simple index
158
175
  # add_index(:suppliers, :name)
@@ -187,7 +204,10 @@ module ActiveRecord
187
204
  # remove_index :accounts, :column => :branch_id
188
205
  # Remove the index named by_branch_party in the accounts table.
189
206
  # remove_index :accounts, :name => :by_branch_party
190
-
207
+ #
208
+ # You can remove an index on multiple columns by specifying the first column.
209
+ # add_index :accounts, [:username, :password]
210
+ # remove_index :accounts, :username
191
211
  def remove_index(table_name, options = {})
192
212
  execute "DROP INDEX #{index_name(table_name, options)} ON #{table_name}"
193
213
  end
@@ -21,10 +21,11 @@ module ActiveRecord
21
21
  class AbstractAdapter
22
22
  include Quoting, DatabaseStatements, SchemaStatements
23
23
  @@row_even = true
24
-
24
+
25
25
  def initialize(connection, logger = nil) #:nodoc:
26
26
  @connection, @logger = connection, logger
27
27
  @runtime = 0
28
+ @last_verification = 0
28
29
  end
29
30
 
30
31
  # Returns the human-readable name of the adapter. Use mixed case - one
@@ -38,6 +39,12 @@ module ActiveRecord
38
39
  def supports_migrations?
39
40
  false
40
41
  end
42
+
43
+ # Does this adapter support using DISTINCT within COUNT? This is +true+
44
+ # for all adapters except sqlite.
45
+ def supports_count_distinct?
46
+ true
47
+ end
41
48
 
42
49
  # Should primary key values be selected from their corresponding
43
50
  # sequence before the insert statement? If true, next_sequence_value
@@ -57,13 +64,35 @@ module ActiveRecord
57
64
 
58
65
  # Is this connection active and ready to perform queries?
59
66
  def active?
60
- true
67
+ @active != false
61
68
  end
62
69
 
63
70
  # Close this connection and open a new one in its place.
64
71
  def reconnect!
72
+ @active = true
65
73
  end
66
74
 
75
+ # Close this connection
76
+ def disconnect!
77
+ @active = false
78
+ end
79
+
80
+ # Lazily verify this connection, calling +active?+ only if it hasn't
81
+ # been called for +timeout+ seconds.
82
+ def verify!(timeout)
83
+ now = Time.now.to_i
84
+ if (now - @last_verification) > timeout
85
+ reconnect! unless active?
86
+ @last_verification = now
87
+ end
88
+ end
89
+
90
+ # Provides access to the underlying database connection. Useful for
91
+ # when you need to call a proprietary method such as postgresql's lo_*
92
+ # methods
93
+ def raw_connection
94
+ @connection
95
+ end
67
96
 
68
97
  protected
69
98
  def log(sql, name)
@@ -83,6 +112,9 @@ module ActiveRecord
83
112
  end
84
113
  rescue Exception => e
85
114
  # Log message and raise exception.
115
+ # Set last_verfication to 0, so that connection gets verified
116
+ # upon reentering the request loop
117
+ @last_verification = 0
86
118
  message = "#{e.class.name}: #{e.message}: #{sql}"
87
119
  log_info(message, name, 0)
88
120
  raise ActiveRecord::StatementInvalid, message
@@ -14,16 +14,17 @@ begin
14
14
  config = config.symbolize_keys
15
15
  usr = config[:username]
16
16
  pwd = config[:password]
17
+ schema = config[:schema]
17
18
 
18
19
  if config.has_key?(:database)
19
20
  database = config[:database]
20
21
  else
21
- raise ArgumentError, "No database specified. Missing argument: database."
22
+ raise ArgumentError, 'No database specified. Missing argument: database.'
22
23
  end
23
24
 
24
25
  connection = DB2::Connection.new(DB2::Environment.new)
25
26
  connection.connect(database, usr, pwd)
26
- ConnectionAdapters::DB2Adapter.new(connection)
27
+ ConnectionAdapters::DB2Adapter.new(connection, logger, :schema => schema)
27
28
  end
28
29
  end
29
30
 
@@ -35,7 +36,18 @@ begin
35
36
  # * <tt>:username</tt> -- Defaults to nothing
36
37
  # * <tt>:password</tt> -- Defaults to nothing
37
38
  # * <tt>:database</tt> -- The name of the database. No default, must be provided.
39
+ # * <tt>:schema</tt> -- Database schema to be set initially.
38
40
  class DB2Adapter < AbstractAdapter
41
+ def initialize(connection, logger, connection_options)
42
+ super(connection, logger)
43
+ @connection_options = connection_options
44
+ if schema = @connection_options[:schema]
45
+ with_statement do |stmt|
46
+ stmt.exec_direct("SET SCHEMA=#{schema}")
47
+ end
48
+ end
49
+ end
50
+
39
51
  def select_all(sql, name = nil)
40
52
  select(sql, name)
41
53
  end
@@ -51,14 +63,12 @@ begin
51
63
 
52
64
  def execute(sql, name = nil)
53
65
  rows_affected = 0
54
-
55
- log(sql, name) do
56
- stmt = DB2::Statement.new(@connection)
57
- stmt.exec_direct(sql)
58
- rows_affected = stmt.row_count
59
- stmt.free
66
+ with_statement do |stmt|
67
+ log(sql, name) do
68
+ stmt.exec_direct(sql)
69
+ rows_affected = stmt.row_count
70
+ end
60
71
  end
61
-
62
72
  rows_affected
63
73
  end
64
74
 
@@ -92,64 +102,72 @@ begin
92
102
  end
93
103
 
94
104
  def add_limit_offset!(sql, options)
95
- if options[:limit] and !options[:limit].nil?
96
- # "FETCH FIRST 0 ROWS ONLY" is not allowed, so we have
97
- # to use a cheap trick.
98
- if options[:limit] == 0
99
- if sql =~ /WHERE/i
100
- sql.sub!(/WHERE/i, 'WHERE 1 = 2 AND ')
101
- elsif
102
- sql =~ /ORDER\s+BY/i
103
- sql.sub!(/ORDER\s+BY/i, 'WHERE 1 = 2 ORDER BY')
104
- else
105
- sql << 'WHERE 1 = 2'
106
- end
107
- else
108
- sql << " FETCH FIRST #{options[:limit]} ROWS ONLY"
109
- end
110
- end
111
- if options[:offset] and !options[:offset].nil?
112
- raise ArgumentError, ':offset option is not yet supported!'
105
+ if limit = options[:limit]
106
+ offset = options[:offset] || 0
107
+ # The following trick was added by andrea+rails@webcom.it.
108
+ sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
109
+ sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
113
110
  end
114
111
  end
115
112
 
116
113
  def tables(name = nil)
117
- stmt = DB2::Statement.new(@connection)
118
114
  result = []
119
- stmt.tables.each { |t| result << t[2].downcase }
120
- stmt.free
115
+ schema = @connection_options[:schema] || '%'
116
+ with_statement do |stmt|
117
+ stmt.tables(schema).each { |t| result << t[2].downcase }
118
+ end
121
119
  result
122
120
  end
123
121
 
122
+ def indexes(table_name, name = nil)
123
+ tmp = {}
124
+ schema = @connection_options[:schema] || ''
125
+ with_statement do |stmt|
126
+ stmt.indexes(table_name, schema).each do |t|
127
+ next unless t[5]
128
+ next if t[4] == 'SYSIBM' # Skip system indexes.
129
+ idx_name = t[5].downcase
130
+ col_name = t[8].downcase
131
+ if tmp.has_key?(idx_name)
132
+ tmp[idx_name].columns << col_name
133
+ else
134
+ is_unique = t[3] == 0
135
+ tmp[idx_name] = IndexDefinition.new(table_name, idx_name, is_unique, [col_name])
136
+ end
137
+ end
138
+ end
139
+ tmp.values
140
+ end
141
+
124
142
  def columns(table_name, name = nil)
125
- stmt = DB2::Statement.new(@connection)
126
143
  result = []
127
-
128
- stmt.columns(table_name.upcase).each do |c|
129
- c_name = c[3].downcase
130
- c_default = c[12] == 'NULL' ? nil : c[12]
131
- c_type = c[5].downcase
132
- c_type += "(#{c[6]})" if !c[6].nil? && c[6] != ''
133
- result << Column.new(c_name, c_default, c_type)
134
- end
135
-
136
- stmt.free
144
+ schema = @connection_options[:schema] || '%'
145
+ with_statement do |stmt|
146
+ stmt.columns(table_name, schema).each do |c|
147
+ c_name = c[3].downcase
148
+ c_default = c[12] == 'NULL' ? nil : c[12]
149
+ c_default.gsub!(/^'(.*)'$/, '\1') if !c_default.nil?
150
+ c_type = c[5].downcase
151
+ c_type += "(#{c[6]})" if !c[6].nil? && c[6] != ''
152
+ result << Column.new(c_name, c_default, c_type, c[17] == 'YES')
153
+ end
154
+ end
137
155
  result
138
156
  end
139
157
 
140
158
  def native_database_types
141
159
  {
142
- :primary_key => "int generated by default as identity primary key",
143
- :string => { :name => "varchar", :limit => 255 },
144
- :text => { :name => "clob", :limit => 32768 },
145
- :integer => { :name => "int" },
146
- :float => { :name => "float" },
147
- :datetime => { :name => "timestamp" },
148
- :timestamp => { :name => "timestamp" },
149
- :time => { :name => "time" },
150
- :date => { :name => "date" },
151
- :binary => { :name => "blob", :limit => 32768 },
152
- :boolean => { :name => "decimal", :limit => 1 }
160
+ :primary_key => 'int generated by default as identity (start with 42) primary key',
161
+ :string => { :name => 'varchar', :limit => 255 },
162
+ :text => { :name => 'clob', :limit => 32768 },
163
+ :integer => { :name => 'int' },
164
+ :float => { :name => 'float' },
165
+ :datetime => { :name => 'timestamp' },
166
+ :timestamp => { :name => 'timestamp' },
167
+ :time => { :name => 'time' },
168
+ :date => { :name => 'date' },
169
+ :binary => { :name => 'blob', :limit => 32768 },
170
+ :boolean => { :name => 'decimal', :limit => 1 }
153
171
  }
154
172
  end
155
173
 
@@ -161,8 +179,28 @@ begin
161
179
  '0'
162
180
  end
163
181
 
182
+ def active?
183
+ @connection.select_one 'select 1 from ibm.sysdummy1'
184
+ true
185
+ rescue Exception
186
+ false
187
+ end
188
+
189
+ def reconnect!
190
+ end
191
+
192
+ def table_alias_length
193
+ 128
194
+ end
195
+
164
196
  private
165
197
 
198
+ def with_statement
199
+ stmt = DB2::Statement.new(@connection)
200
+ yield stmt
201
+ stmt.free
202
+ end
203
+
166
204
  def last_insert_id
167
205
  row = select_one(<<-GETID.strip)
168
206
  with temp(id) as (values (identity_val_local())) select * from temp
@@ -171,17 +209,17 @@ begin
171
209
  end
172
210
 
173
211
  def select(sql, name = nil)
174
- stmt = nil
175
- log(sql, name) do
176
- stmt = DB2::Statement.new(@connection)
177
- stmt.exec_direct("#{sql.gsub(/=\s*null/i, 'IS NULL')} with ur")
178
- end
179
-
180
212
  rows = []
181
- while row = stmt.fetch_as_hash
182
- rows << row
213
+ with_statement do |stmt|
214
+ log(sql, name) do
215
+ stmt.exec_direct("#{sql.gsub(/=\s*null/i, 'IS NULL')} with ur")
216
+ end
217
+
218
+ while row = stmt.fetch_as_hash
219
+ row.delete('internal$rownum')
220
+ rows << row
221
+ end
183
222
  end
184
- stmt.free
185
223
  rows
186
224
  end
187
225
  end
@@ -189,4 +227,12 @@ begin
189
227
  end
190
228
  rescue LoadError
191
229
  # DB2 driver is unavailable.
230
+ module ActiveRecord # :nodoc:
231
+ class Base
232
+ def self.db2_connection(config) # :nodoc:
233
+ # Set up a reasonable error message
234
+ raise LoadError, "DB2 Libraries could not be loaded."
235
+ end
236
+ end
237
+ end
192
238
  end
@@ -42,7 +42,8 @@ module ActiveRecord
42
42
  class MysqlColumn < Column #:nodoc:
43
43
  private
44
44
  def simplified_type(field_type)
45
- return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase == "tinyint(1)"
45
+ return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
46
+ return :string if field_type =~ /enum/i
46
47
  super
47
48
  end
48
49
  end
@@ -115,7 +116,7 @@ module ActiveRecord
115
116
  # QUOTING ==================================================
116
117
 
117
118
  def quote(value, column = nil)
118
- if value.kind_of?(String) && column && column.type == :binary
119
+ if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
119
120
  s = column.class.string_to_binary(value).unpack("H*")[0]
120
121
  "x'#{s}'"
121
122
  else
@@ -160,9 +161,13 @@ module ActiveRecord
160
161
  end
161
162
 
162
163
  def reconnect!
163
- @connection.close rescue nil
164
+ disconnect!
164
165
  connect
165
166
  end
167
+
168
+ def disconnect!
169
+ @connection.close rescue nil
170
+ end
166
171
 
167
172
 
168
173
  # DATABASE STATEMENTS ======================================
@@ -232,7 +237,14 @@ module ActiveRecord
232
237
  # SCHEMA STATEMENTS ========================================
233
238
 
234
239
  def structure_dump #:nodoc:
235
- select_all("SHOW TABLES").inject("") do |structure, table|
240
+ if supports_views?
241
+ sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
242
+ else
243
+ sql = "SHOW TABLES"
244
+ end
245
+
246
+ select_all(sql).inject("") do |structure, table|
247
+ table.delete('Table_type')
236
248
  structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
237
249
  end
238
250
  end
@@ -243,13 +255,16 @@ module ActiveRecord
243
255
  end
244
256
 
245
257
  def create_database(name) #:nodoc:
246
- execute "CREATE DATABASE #{name}"
258
+ execute "CREATE DATABASE `#{name}`"
247
259
  end
248
260
 
249
261
  def drop_database(name) #:nodoc:
250
- execute "DROP DATABASE IF EXISTS #{name}"
262
+ execute "DROP DATABASE IF EXISTS `#{name}`"
251
263
  end
252
264
 
265
+ def current_database
266
+ select_one("SELECT DATABASE() as db")["db"]
267
+ end
253
268
 
254
269
  def tables(name = nil) #:nodoc:
255
270
  tables = []
@@ -330,6 +345,14 @@ module ActiveRecord
330
345
  result.free
331
346
  rows
332
347
  end
348
+
349
+ def supports_views?
350
+ version[0] >= 5
351
+ end
352
+
353
+ def version
354
+ @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
355
+ end
333
356
  end
334
357
  end
335
358
  end