square-activerecord 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6140 -0
- data/README.rdoc +222 -0
- data/examples/associations.png +0 -0
- data/examples/performance.rb +179 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +124 -0
- data/lib/active_record/aggregations.rb +277 -0
- data/lib/active_record/association_preload.rb +430 -0
- data/lib/active_record/associations.rb +2307 -0
- data/lib/active_record/associations/association_collection.rb +572 -0
- data/lib/active_record/associations/association_proxy.rb +299 -0
- data/lib/active_record/associations/belongs_to_association.rb +91 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +82 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
- data/lib/active_record/associations/has_many_association.rb +128 -0
- data/lib/active_record/associations/has_many_through_association.rb +115 -0
- data/lib/active_record/associations/has_one_association.rb +143 -0
- data/lib/active_record/associations/has_one_through_association.rb +40 -0
- data/lib/active_record/associations/through_association_scope.rb +154 -0
- data/lib/active_record/attribute_methods.rb +60 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +30 -0
- data/lib/active_record/attribute_methods/dirty.rb +95 -0
- data/lib/active_record/attribute_methods/primary_key.rb +56 -0
- data/lib/active_record/attribute_methods/query.rb +39 -0
- data/lib/active_record/attribute_methods/read.rb +145 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +64 -0
- data/lib/active_record/attribute_methods/write.rb +43 -0
- data/lib/active_record/autosave_association.rb +369 -0
- data/lib/active_record/base.rb +1904 -0
- data/lib/active_record/callbacks.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +364 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +333 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +73 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +539 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +217 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +657 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1031 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +401 -0
- data/lib/active_record/counter_cache.rb +115 -0
- data/lib/active_record/dynamic_finder_match.rb +56 -0
- data/lib/active_record/dynamic_scope_match.rb +23 -0
- data/lib/active_record/errors.rb +172 -0
- data/lib/active_record/fixtures.rb +1006 -0
- data/lib/active_record/locale/en.yml +40 -0
- data/lib/active_record/locking/optimistic.rb +172 -0
- data/lib/active_record/locking/pessimistic.rb +55 -0
- data/lib/active_record/log_subscriber.rb +48 -0
- data/lib/active_record/migration.rb +617 -0
- data/lib/active_record/named_scope.rb +138 -0
- data/lib/active_record/nested_attributes.rb +419 -0
- data/lib/active_record/observer.rb +125 -0
- data/lib/active_record/persistence.rb +290 -0
- data/lib/active_record/query_cache.rb +36 -0
- data/lib/active_record/railtie.rb +91 -0
- data/lib/active_record/railties/controller_runtime.rb +38 -0
- data/lib/active_record/railties/databases.rake +512 -0
- data/lib/active_record/reflection.rb +411 -0
- data/lib/active_record/relation.rb +394 -0
- data/lib/active_record/relation/batches.rb +89 -0
- data/lib/active_record/relation/calculations.rb +295 -0
- data/lib/active_record/relation/finder_methods.rb +363 -0
- data/lib/active_record/relation/predicate_builder.rb +48 -0
- data/lib/active_record/relation/query_methods.rb +303 -0
- data/lib/active_record/relation/spawn_methods.rb +132 -0
- data/lib/active_record/schema.rb +59 -0
- data/lib/active_record/schema_dumper.rb +195 -0
- data/lib/active_record/serialization.rb +60 -0
- data/lib/active_record/serializers/xml_serializer.rb +244 -0
- data/lib/active_record/session_store.rb +340 -0
- data/lib/active_record/test_case.rb +67 -0
- data/lib/active_record/timestamp.rb +88 -0
- data/lib/active_record/transactions.rb +359 -0
- data/lib/active_record/validations.rb +84 -0
- data/lib/active_record/validations/associated.rb +48 -0
- data/lib/active_record/validations/uniqueness.rb +190 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/rails/generators/active_record.rb +19 -0
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
- data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
- data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
- metadata +223 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'active_record/connection_adapters/sqlite_adapter'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class Base
|
5
|
+
# sqlite3 adapter reuses sqlite_connection.
|
6
|
+
def self.sqlite3_connection(config) # :nodoc:
|
7
|
+
# Require database.
|
8
|
+
unless config[:database]
|
9
|
+
raise ArgumentError, "No database file specified. Missing argument: database"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Allow database path relative to Rails.root, but only if
|
13
|
+
# the database path is not the special path that tells
|
14
|
+
# Sqlite to build a database only in memory.
|
15
|
+
if defined?(Rails.root) && ':memory:' != config[:database]
|
16
|
+
config[:database] = File.expand_path(config[:database], Rails.root)
|
17
|
+
end
|
18
|
+
|
19
|
+
unless 'sqlite3' == config[:adapter]
|
20
|
+
raise ArgumentError, 'adapter name should be "sqlite3"'
|
21
|
+
end
|
22
|
+
|
23
|
+
unless self.class.const_defined?(:SQLite3)
|
24
|
+
require_library_or_gem(config[:adapter])
|
25
|
+
end
|
26
|
+
|
27
|
+
db = SQLite3::Database.new(
|
28
|
+
config[:database],
|
29
|
+
:results_as_hash => true
|
30
|
+
)
|
31
|
+
|
32
|
+
db.busy_timeout(config[:timeout]) unless config[:timeout].nil?
|
33
|
+
|
34
|
+
ConnectionAdapters::SQLite3Adapter.new(db, logger, config)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module ConnectionAdapters #:nodoc:
|
39
|
+
class SQLite3Adapter < SQLiteAdapter # :nodoc:
|
40
|
+
def quote(value, column = nil)
|
41
|
+
if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
42
|
+
s = column.class.string_to_binary(value).unpack("H*")[0]
|
43
|
+
"x'#{s}'"
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the current database encoding format as a string, eg: 'UTF-8'
|
50
|
+
def encoding
|
51
|
+
if @connection.respond_to?(:encoding)
|
52
|
+
@connection.encoding.to_s
|
53
|
+
else
|
54
|
+
encoding = @connection.execute('PRAGMA encoding')
|
55
|
+
encoding[0]['encoding']
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,401 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
2
|
+
require 'active_support/core_ext/kernel/requires'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionAdapters #:nodoc:
|
6
|
+
class SQLiteColumn < Column #:nodoc:
|
7
|
+
class << self
|
8
|
+
def string_to_binary(value)
|
9
|
+
value.gsub(/\0|\%/n) do |b|
|
10
|
+
case b
|
11
|
+
when "\0" then "%00"
|
12
|
+
when "%" then "%25"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def binary_to_string(value)
|
18
|
+
if value.respond_to?(:force_encoding) && value.encoding != Encoding::ASCII_8BIT
|
19
|
+
value = value.force_encoding(Encoding::ASCII_8BIT)
|
20
|
+
end
|
21
|
+
|
22
|
+
value.gsub(/%00|%25/n) do |b|
|
23
|
+
case b
|
24
|
+
when "%00" then "\0"
|
25
|
+
when "%25" then "%"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby
|
33
|
+
# drivers (available both as gems and from http://rubyforge.org/projects/sqlite-ruby/).
|
34
|
+
#
|
35
|
+
# Options:
|
36
|
+
#
|
37
|
+
# * <tt>:database</tt> - Path to the database file.
|
38
|
+
class SQLiteAdapter < AbstractAdapter
|
39
|
+
class Version
|
40
|
+
include Comparable
|
41
|
+
|
42
|
+
def initialize(version_string)
|
43
|
+
@version = version_string.split('.').map { |v| v.to_i }
|
44
|
+
end
|
45
|
+
|
46
|
+
def <=>(version_string)
|
47
|
+
@version <=> version_string.split('.').map { |v| v.to_i }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(connection, logger, config)
|
52
|
+
super(connection, logger)
|
53
|
+
@config = config
|
54
|
+
end
|
55
|
+
|
56
|
+
def adapter_name #:nodoc:
|
57
|
+
'SQLite'
|
58
|
+
end
|
59
|
+
|
60
|
+
def supports_ddl_transactions?
|
61
|
+
sqlite_version >= '2.0.0'
|
62
|
+
end
|
63
|
+
|
64
|
+
def supports_migrations? #:nodoc:
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
def supports_primary_key? #:nodoc:
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
def requires_reloading?
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
def supports_add_column?
|
77
|
+
sqlite_version >= '3.1.6'
|
78
|
+
end
|
79
|
+
|
80
|
+
def disconnect!
|
81
|
+
super
|
82
|
+
@connection.close rescue nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def supports_count_distinct? #:nodoc:
|
86
|
+
sqlite_version >= '3.2.6'
|
87
|
+
end
|
88
|
+
|
89
|
+
def supports_autoincrement? #:nodoc:
|
90
|
+
sqlite_version >= '3.1.0'
|
91
|
+
end
|
92
|
+
|
93
|
+
def native_database_types #:nodoc:
|
94
|
+
{
|
95
|
+
:primary_key => default_primary_key_type,
|
96
|
+
:string => { :name => "varchar", :limit => 255 },
|
97
|
+
:text => { :name => "text" },
|
98
|
+
:integer => { :name => "integer" },
|
99
|
+
:float => { :name => "float" },
|
100
|
+
:decimal => { :name => "decimal" },
|
101
|
+
:datetime => { :name => "datetime" },
|
102
|
+
:timestamp => { :name => "datetime" },
|
103
|
+
:time => { :name => "time" },
|
104
|
+
:date => { :name => "date" },
|
105
|
+
:binary => { :name => "blob" },
|
106
|
+
:boolean => { :name => "boolean" }
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# QUOTING ==================================================
|
112
|
+
|
113
|
+
def quote_string(s) #:nodoc:
|
114
|
+
@connection.class.quote(s)
|
115
|
+
end
|
116
|
+
|
117
|
+
def quote_column_name(name) #:nodoc:
|
118
|
+
%Q("#{name}")
|
119
|
+
end
|
120
|
+
|
121
|
+
# Quote date/time values for use in SQL input. Includes microseconds
|
122
|
+
# if the value is a Time responding to usec.
|
123
|
+
def quoted_date(value) #:nodoc:
|
124
|
+
if value.acts_like?(:time) && value.respond_to?(:usec)
|
125
|
+
"#{super}.#{sprintf("%06d", value.usec)}"
|
126
|
+
else
|
127
|
+
super
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# DATABASE STATEMENTS ======================================
|
133
|
+
|
134
|
+
def execute(sql, name = nil) #:nodoc:
|
135
|
+
log(sql, name) { @connection.execute(sql) }
|
136
|
+
end
|
137
|
+
|
138
|
+
def update_sql(sql, name = nil) #:nodoc:
|
139
|
+
super
|
140
|
+
@connection.changes
|
141
|
+
end
|
142
|
+
|
143
|
+
def delete_sql(sql, name = nil) #:nodoc:
|
144
|
+
sql += " WHERE 1=1" unless sql =~ /WHERE/i
|
145
|
+
super sql, name
|
146
|
+
end
|
147
|
+
|
148
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
149
|
+
super || @connection.last_insert_row_id
|
150
|
+
end
|
151
|
+
alias :create :insert_sql
|
152
|
+
|
153
|
+
def select_rows(sql, name = nil)
|
154
|
+
execute(sql, name).map do |row|
|
155
|
+
(0...(row.size / 2)).map { |i| row[i] }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def begin_db_transaction #:nodoc:
|
160
|
+
@connection.transaction
|
161
|
+
end
|
162
|
+
|
163
|
+
def commit_db_transaction #:nodoc:
|
164
|
+
@connection.commit
|
165
|
+
end
|
166
|
+
|
167
|
+
def rollback_db_transaction #:nodoc:
|
168
|
+
@connection.rollback
|
169
|
+
end
|
170
|
+
|
171
|
+
# SCHEMA STATEMENTS ========================================
|
172
|
+
|
173
|
+
def tables(name = nil) #:nodoc:
|
174
|
+
sql = <<-SQL
|
175
|
+
SELECT name
|
176
|
+
FROM sqlite_master
|
177
|
+
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
178
|
+
SQL
|
179
|
+
|
180
|
+
execute(sql, name).map do |row|
|
181
|
+
row['name']
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def columns(table_name, name = nil) #:nodoc:
|
186
|
+
table_structure(table_name).map do |field|
|
187
|
+
SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def indexes(table_name, name = nil) #:nodoc:
|
192
|
+
execute("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
|
193
|
+
IndexDefinition.new(
|
194
|
+
table_name,
|
195
|
+
row['name'],
|
196
|
+
row['unique'].to_i != 0,
|
197
|
+
execute("PRAGMA index_info('#{row['name']}')").map { |col|
|
198
|
+
col['name']
|
199
|
+
})
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def primary_key(table_name) #:nodoc:
|
204
|
+
column = table_structure(table_name).find { |field|
|
205
|
+
field['pk'].to_i == 1
|
206
|
+
}
|
207
|
+
column && column['name']
|
208
|
+
end
|
209
|
+
|
210
|
+
def remove_index!(table_name, index_name) #:nodoc:
|
211
|
+
execute "DROP INDEX #{quote_column_name(index_name)}"
|
212
|
+
end
|
213
|
+
|
214
|
+
def rename_table(name, new_name)
|
215
|
+
execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
|
216
|
+
end
|
217
|
+
|
218
|
+
# See: http://www.sqlite.org/lang_altertable.html
|
219
|
+
# SQLite has an additional restriction on the ALTER TABLE statement
|
220
|
+
def valid_alter_table_options( type, options)
|
221
|
+
type.to_sym != :primary_key
|
222
|
+
end
|
223
|
+
|
224
|
+
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
225
|
+
if supports_add_column? && valid_alter_table_options( type, options )
|
226
|
+
super(table_name, column_name, type, options)
|
227
|
+
else
|
228
|
+
alter_table(table_name) do |definition|
|
229
|
+
definition.column(column_name, type, options)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def remove_column(table_name, *column_names) #:nodoc:
|
235
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
236
|
+
column_names.flatten.each do |column_name|
|
237
|
+
alter_table(table_name) do |definition|
|
238
|
+
definition.columns.delete(definition[column_name])
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
alias :remove_columns :remove_column
|
243
|
+
|
244
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
245
|
+
alter_table(table_name) do |definition|
|
246
|
+
definition[column_name].default = default
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def change_column_null(table_name, column_name, null, default = nil)
|
251
|
+
unless null || default.nil?
|
252
|
+
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
253
|
+
end
|
254
|
+
alter_table(table_name) do |definition|
|
255
|
+
definition[column_name].null = null
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
260
|
+
alter_table(table_name) do |definition|
|
261
|
+
include_default = options_include_default?(options)
|
262
|
+
definition[column_name].instance_eval do
|
263
|
+
self.type = type
|
264
|
+
self.limit = options[:limit] if options.include?(:limit)
|
265
|
+
self.default = options[:default] if include_default
|
266
|
+
self.null = options[:null] if options.include?(:null)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
272
|
+
unless columns(table_name).detect{|c| c.name == column_name.to_s }
|
273
|
+
raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
|
274
|
+
end
|
275
|
+
alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
|
276
|
+
end
|
277
|
+
|
278
|
+
def empty_insert_statement_value
|
279
|
+
"VALUES(NULL)"
|
280
|
+
end
|
281
|
+
|
282
|
+
protected
|
283
|
+
def select(sql, name = nil) #:nodoc:
|
284
|
+
execute(sql, name).map do |row|
|
285
|
+
record = {}
|
286
|
+
row.each do |key, value|
|
287
|
+
record[key.sub(/^"?\w+"?\./, '')] = value if key.is_a?(String)
|
288
|
+
end
|
289
|
+
record
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def table_structure(table_name)
|
294
|
+
structure = @connection.table_info(quote_table_name(table_name))
|
295
|
+
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
296
|
+
structure
|
297
|
+
end
|
298
|
+
|
299
|
+
def alter_table(table_name, options = {}) #:nodoc:
|
300
|
+
altered_table_name = "altered_#{table_name}"
|
301
|
+
caller = lambda {|definition| yield definition if block_given?}
|
302
|
+
|
303
|
+
transaction do
|
304
|
+
move_table(table_name, altered_table_name,
|
305
|
+
options.merge(:temporary => true))
|
306
|
+
move_table(altered_table_name, table_name, &caller)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def move_table(from, to, options = {}, &block) #:nodoc:
|
311
|
+
copy_table(from, to, options, &block)
|
312
|
+
drop_table(from)
|
313
|
+
end
|
314
|
+
|
315
|
+
def copy_table(from, to, options = {}) #:nodoc:
|
316
|
+
options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
|
317
|
+
create_table(to, options) do |definition|
|
318
|
+
@definition = definition
|
319
|
+
columns(from).each do |column|
|
320
|
+
column_name = options[:rename] ?
|
321
|
+
(options[:rename][column.name] ||
|
322
|
+
options[:rename][column.name.to_sym] ||
|
323
|
+
column.name) : column.name
|
324
|
+
|
325
|
+
@definition.column(column_name, column.type,
|
326
|
+
:limit => column.limit, :default => column.default,
|
327
|
+
:null => column.null)
|
328
|
+
end
|
329
|
+
@definition.primary_key(primary_key(from)) if primary_key(from)
|
330
|
+
yield @definition if block_given?
|
331
|
+
end
|
332
|
+
|
333
|
+
copy_table_indexes(from, to, options[:rename] || {})
|
334
|
+
copy_table_contents(from, to,
|
335
|
+
@definition.columns.map {|column| column.name},
|
336
|
+
options[:rename] || {})
|
337
|
+
end
|
338
|
+
|
339
|
+
def copy_table_indexes(from, to, rename = {}) #:nodoc:
|
340
|
+
indexes(from).each do |index|
|
341
|
+
name = index.name
|
342
|
+
if to == "altered_#{from}"
|
343
|
+
name = "temp_#{name}"
|
344
|
+
elsif from == "altered_#{to}"
|
345
|
+
name = name[5..-1]
|
346
|
+
end
|
347
|
+
|
348
|
+
to_column_names = columns(to).map { |c| c.name }
|
349
|
+
columns = index.columns.map {|c| rename[c] || c }.select do |column|
|
350
|
+
to_column_names.include?(column)
|
351
|
+
end
|
352
|
+
|
353
|
+
unless columns.empty?
|
354
|
+
# index name can't be the same
|
355
|
+
opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
|
356
|
+
opts[:unique] = true if index.unique
|
357
|
+
add_index(to, columns, opts)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
|
363
|
+
column_mappings = Hash[columns.map {|name| [name, name]}]
|
364
|
+
rename.each { |a| column_mappings[a.last] = a.first }
|
365
|
+
from_columns = columns(from).collect {|col| col.name}
|
366
|
+
columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
|
367
|
+
quoted_columns = columns.map { |col| quote_column_name(col) } * ','
|
368
|
+
|
369
|
+
quoted_to = quote_table_name(to)
|
370
|
+
@connection.execute "SELECT * FROM #{quote_table_name(from)}" do |row|
|
371
|
+
sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
|
372
|
+
sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
|
373
|
+
sql << ')'
|
374
|
+
@connection.execute sql
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def sqlite_version
|
379
|
+
@sqlite_version ||= SQLiteAdapter::Version.new(select_value('select sqlite_version(*)'))
|
380
|
+
end
|
381
|
+
|
382
|
+
def default_primary_key_type
|
383
|
+
if supports_autoincrement?
|
384
|
+
'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'
|
385
|
+
else
|
386
|
+
'INTEGER PRIMARY KEY NOT NULL'
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def translate_exception(exception, message)
|
391
|
+
case exception.message
|
392
|
+
when /column(s)? .* (is|are) not unique/
|
393
|
+
RecordNotUnique.new(message, exception)
|
394
|
+
else
|
395
|
+
super
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|