· 8 years ago · Apr 26, 2018, 12:22 AM
1From ebc5d8a6e693e067c40bfe31ca9a322a872e99fb Mon Sep 17 00:00:00 2001
2From: =?utf-8?q?Tarmo=20T=C3=A4nav?= <tarmo@itech.ee>
3Date: Wed, 7 May 2008 02:08:23 +0300
4Subject: [PATCH] Added AbstractAdapter#table_exists? and made AbstractAdapter#table implementation non-optional
5
6---
7 activerecord/lib/active_record/base.rb | 13 +-
8 .../abstract/schema_statements.rb | 4 +
9 activerecord/test/cases/adapter_test.rb | 19 +-
10 activerecord/test/cases/schema_dumper_test.rb | 211 ++++++++++----------
11 4 files changed, 119 insertions(+), 128 deletions(-)
12
13diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
14index ffefc3c..1223418 100755
15--- a/activerecord/lib/active_record/base.rb
16+++ b/activerecord/lib/active_record/base.rb
17@@ -1118,18 +1118,7 @@ module ActiveRecord #:nodoc:
18
19 # Indicates whether the table associated with this class exists
20 def table_exists?
21- if connection.respond_to?(:tables)
22- connection.tables.include? table_name
23- else
24- # if the connection adapter hasn't implemented tables, there are two crude tests that can be
25- # used - see if getting column info raises an error, or if the number of columns returned is zero
26- begin
27- reset_column_information
28- columns.size > 0
29- rescue ActiveRecord::StatementInvalid
30- false
31- end
32- end
33+ connection.table_exists?(table_name)
34 end
35
36 # Returns an array of column objects for the table associated with this class.
37diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
38index b556516..e2b8896 100644
39--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
40+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
41@@ -20,6 +20,10 @@ module ActiveRecord
42
43 # def tables(name = nil) end
44
45+ def table_exists?(table_name)
46+ tables.include?(table_name.to_s)
47+ end
48+
49 # Returns an array of indexes for the given table.
50 # def indexes(table_name, name = nil) end
51
52diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
53index 8a74b6d..91504af 100644
54--- a/activerecord/test/cases/adapter_test.rb
55+++ b/activerecord/test/cases/adapter_test.rb
56@@ -6,15 +6,16 @@ class AdapterTest < ActiveRecord::TestCase
57 end
58
59 def test_tables
60- if @connection.respond_to?(:tables)
61- tables = @connection.tables
62- assert tables.include?("accounts")
63- assert tables.include?("authors")
64- assert tables.include?("tasks")
65- assert tables.include?("topics")
66- else
67- warn "#{@connection.class} does not respond to #tables"
68- end
69+ tables = @connection.tables
70+ assert tables.include?("accounts")
71+ assert tables.include?("authors")
72+ assert tables.include?("tasks")
73+ assert tables.include?("topics")
74+ end
75+
76+ def test_table_exists?
77+ assert @connection.table_exists?("accounts")
78+ assert !@connection.table_exists?("nonexistingtable")
79 end
80
81 def test_indexes
82diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
83index ba8bff3..c42b0ef 100644
84--- a/activerecord/test/cases/schema_dumper_test.rb
85+++ b/activerecord/test/cases/schema_dumper_test.rb
86@@ -2,140 +2,137 @@ require "cases/helper"
87 require 'active_record/schema_dumper'
88 require 'stringio'
89
90-if ActiveRecord::Base.connection.respond_to?(:tables)
91
92- class SchemaDumperTest < ActiveRecord::TestCase
93- def standard_dump
94- stream = StringIO.new
95- ActiveRecord::SchemaDumper.ignore_tables = []
96- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
97- stream.string
98- end
99+class SchemaDumperTest < ActiveRecord::TestCase
100+ def standard_dump
101+ stream = StringIO.new
102+ ActiveRecord::SchemaDumper.ignore_tables = []
103+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
104+ stream.string
105+ end
106
107- def test_schema_dump
108- output = standard_dump
109- assert_match %r{create_table "accounts"}, output
110- assert_match %r{create_table "authors"}, output
111- assert_no_match %r{create_table "schema_migrations"}, output
112- end
113+ def test_schema_dump
114+ output = standard_dump
115+ assert_match %r{create_table "accounts"}, output
116+ assert_match %r{create_table "authors"}, output
117+ assert_no_match %r{create_table "schema_migrations"}, output
118+ end
119
120- def test_schema_dump_excludes_sqlite_sequence
121- output = standard_dump
122- assert_no_match %r{create_table "sqlite_sequence"}, output
123- end
124+ def test_schema_dump_excludes_sqlite_sequence
125+ output = standard_dump
126+ assert_no_match %r{create_table "sqlite_sequence"}, output
127+ end
128
129- def assert_line_up(lines, pattern, required = false)
130- return assert(true) if lines.empty?
131- matches = lines.map { |line| line.match(pattern) }
132- assert matches.all? if required
133- matches.compact!
134- return assert(true) if matches.empty?
135- assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
136- end
137+ def assert_line_up(lines, pattern, required = false)
138+ return assert(true) if lines.empty?
139+ matches = lines.map { |line| line.match(pattern) }
140+ assert matches.all? if required
141+ matches.compact!
142+ return assert(true) if matches.empty?
143+ assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
144+ end
145
146- def column_definition_lines(output = standard_dump)
147- output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
148- end
149+ def column_definition_lines(output = standard_dump)
150+ output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
151+ end
152
153- def test_types_line_up
154- column_definition_lines.each do |column_set|
155- next if column_set.empty?
156+ def test_types_line_up
157+ column_definition_lines.each do |column_set|
158+ next if column_set.empty?
159
160- lengths = column_set.map do |column|
161- if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
162- match[0].length
163- end
164+ lengths = column_set.map do |column|
165+ if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
166+ match[0].length
167 end
168-
169- assert_equal 1, lengths.uniq.length
170 end
171- end
172
173- def test_arguments_line_up
174- column_definition_lines.each do |column_set|
175- assert_line_up(column_set, /:default => /)
176- assert_line_up(column_set, /:limit => /)
177- assert_line_up(column_set, /:null => /)
178- end
179+ assert_equal 1, lengths.uniq.length
180 end
181+ end
182
183- def test_no_dump_errors
184- output = standard_dump
185- assert_no_match %r{\# Could not dump table}, output
186+ def test_arguments_line_up
187+ column_definition_lines.each do |column_set|
188+ assert_line_up(column_set, /:default => /)
189+ assert_line_up(column_set, /:limit => /)
190+ assert_line_up(column_set, /:null => /)
191 end
192+ end
193
194- def test_schema_dump_includes_not_null_columns
195- stream = StringIO.new
196+ def test_no_dump_errors
197+ output = standard_dump
198+ assert_no_match %r{\# Could not dump table}, output
199+ end
200
201- ActiveRecord::SchemaDumper.ignore_tables = [/^[^r]/]
202- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
203- output = stream.string
204- assert_match %r{:null => false}, output
205- end
206+ def test_schema_dump_includes_not_null_columns
207+ stream = StringIO.new
208
209- def test_schema_dump_with_string_ignored_table
210- stream = StringIO.new
211+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^r]/]
212+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
213+ output = stream.string
214+ assert_match %r{:null => false}, output
215+ end
216
217- ActiveRecord::SchemaDumper.ignore_tables = ['accounts']
218- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
219- output = stream.string
220- assert_no_match %r{create_table "accounts"}, output
221- assert_match %r{create_table "authors"}, output
222- assert_no_match %r{create_table "schema_migrations"}, output
223- end
224+ def test_schema_dump_with_string_ignored_table
225+ stream = StringIO.new
226+
227+ ActiveRecord::SchemaDumper.ignore_tables = ['accounts']
228+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
229+ output = stream.string
230+ assert_no_match %r{create_table "accounts"}, output
231+ assert_match %r{create_table "authors"}, output
232+ assert_no_match %r{create_table "schema_migrations"}, output
233+ end
234+
235+ def test_schema_dump_with_regexp_ignored_table
236+ stream = StringIO.new
237
238- def test_schema_dump_with_regexp_ignored_table
239- stream = StringIO.new
240+ ActiveRecord::SchemaDumper.ignore_tables = [/^account/]
241+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
242+ output = stream.string
243+ assert_no_match %r{create_table "accounts"}, output
244+ assert_match %r{create_table "authors"}, output
245+ assert_no_match %r{create_table "schema_migrations"}, output
246+ end
247
248- ActiveRecord::SchemaDumper.ignore_tables = [/^account/]
249+ def test_schema_dump_illegal_ignored_table_value
250+ stream = StringIO.new
251+ ActiveRecord::SchemaDumper.ignore_tables = [5]
252+ assert_raise(StandardError) do
253 ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
254- output = stream.string
255- assert_no_match %r{create_table "accounts"}, output
256- assert_match %r{create_table "authors"}, output
257- assert_no_match %r{create_table "schema_migrations"}, output
258 end
259+ end
260
261- def test_schema_dump_illegal_ignored_table_value
262- stream = StringIO.new
263- ActiveRecord::SchemaDumper.ignore_tables = [5]
264- assert_raise(StandardError) do
265- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
266- end
267+ if current_adapter?(:MysqlAdapter)
268+ def test_schema_dump_should_not_add_default_value_for_mysql_text_field
269+ output = standard_dump
270+ assert_match %r{t.text\s+"body",\s+:null => false$}, output
271 end
272
273- if current_adapter?(:MysqlAdapter)
274- def test_schema_dump_should_not_add_default_value_for_mysql_text_field
275- output = standard_dump
276- assert_match %r{t.text\s+"body",\s+:null => false$}, output
277- end
278-
279- def test_mysql_schema_dump_should_honor_nonstandard_primary_keys
280- output = standard_dump
281- match = output.match(%r{create_table "movies"(.*)do})
282- assert_not_nil(match, "nonstandardpk table not found")
283- assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
284- end
285-
286- def test_schema_dump_includes_length_for_mysql_blob_and_text_fields
287- output = standard_dump
288- assert_match %r{t.binary\s+"tiny_blob",\s+:limit => 255$}, output
289- assert_match %r{t.binary\s+"normal_blob"$}, output
290- assert_match %r{t.binary\s+"medium_blob",\s+:limit => 16777215$}, output
291- assert_match %r{t.binary\s+"long_blob",\s+:limit => 2147483647$}, output
292- assert_match %r{t.text\s+"tiny_text",\s+:limit => 255$}, output
293- assert_match %r{t.text\s+"normal_text"$}, output
294- assert_match %r{t.text\s+"medium_text",\s+:limit => 16777215$}, output
295- assert_match %r{t.text\s+"long_text",\s+:limit => 2147483647$}, output
296- end
297+ def test_mysql_schema_dump_should_honor_nonstandard_primary_keys
298+ output = standard_dump
299+ match = output.match(%r{create_table "movies"(.*)do})
300+ assert_not_nil(match, "nonstandardpk table not found")
301+ assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
302 end
303
304- def test_schema_dump_includes_decimal_options
305- stream = StringIO.new
306- ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
307- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
308- output = stream.string
309- assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 2.78}, output
310+ def test_schema_dump_includes_length_for_mysql_blob_and_text_fields
311+ output = standard_dump
312+ assert_match %r{t.binary\s+"tiny_blob",\s+:limit => 255$}, output
313+ assert_match %r{t.binary\s+"normal_blob"$}, output
314+ assert_match %r{t.binary\s+"medium_blob",\s+:limit => 16777215$}, output
315+ assert_match %r{t.binary\s+"long_blob",\s+:limit => 2147483647$}, output
316+ assert_match %r{t.text\s+"tiny_text",\s+:limit => 255$}, output
317+ assert_match %r{t.text\s+"normal_text"$}, output
318+ assert_match %r{t.text\s+"medium_text",\s+:limit => 16777215$}, output
319+ assert_match %r{t.text\s+"long_text",\s+:limit => 2147483647$}, output
320 end
321 end
322
323+ def test_schema_dump_includes_decimal_options
324+ stream = StringIO.new
325+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
326+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
327+ output = stream.string
328+ assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 2.78}, output
329+ end
330 end
331--
3321.5.5.1
333
334
335From ce4894fc531de705669062b8e0ecaa9dafb32d24 Mon Sep 17 00:00:00 2001
336From: =?utf-8?q?Tarmo=20T=C3=A4nav?= <tarmo@itech.ee>
337Date: Wed, 7 May 2008 02:08:57 +0300
338Subject: [PATCH] create_table :force => true no longer tries to drop a non-existing table
339
340---
341 .../abstract/schema_statements.rb | 4 ++--
342 activerecord/test/cases/migration_test.rb | 18 ++++++++++++++++++
343 2 files changed, 20 insertions(+), 2 deletions(-)
344
345diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
346index e2b8896..1594be4 100644
347--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
348+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
349@@ -97,8 +97,8 @@ module ActiveRecord
350
351 yield table_definition
352
353- if options[:force]
354- drop_table(table_name, options) rescue nil
355+ if options[:force] && table_exists?(table_name)
356+ drop_table(table_name, options)
357 end
358
359 create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
360diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
361index d4e8182..6be31b5 100644
362--- a/activerecord/test/cases/migration_test.rb
363+++ b/activerecord/test/cases/migration_test.rb
364@@ -209,6 +209,24 @@ if ActiveRecord::Base.connection.supports_migrations?
365 ActiveRecord::Base.primary_key_prefix_type = nil
366 end
367
368+ uses_mocha('test_create_table_with_force_true_does_not_drop_nonexisting_table') do
369+ def test_create_table_with_force_true_does_not_drop_nonexisting_table
370+ if Person.connection.table_exists?(:testings2)
371+ Person.connection.drop_table :testings2
372+ end
373+
374+ # using a copy as we need the drop_table method to
375+ # continue to work for the ensure block of the test
376+ temp_conn = Person.connection.dup
377+ temp_conn.expects(:drop_table).never
378+ temp_conn.create_table :testings2, :force => true do |t|
379+ t.column :foo, :string
380+ end
381+ ensure
382+ Person.connection.drop_table :testings2 rescue nil
383+ end
384+ end
385+
386
387 # SQL Server, Sybase, and SQLite3 will not allow you to add a NOT NULL
388 # column to a table without a default value.
389--
3901.5.5.1