activerecord 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +4928 -3
- data/README +45 -46
- data/RUNNING_UNIT_TESTS +8 -11
- data/Rakefile +247 -0
- data/install.rb +8 -38
- data/lib/active_record/aggregations.rb +64 -49
- data/lib/active_record/associations/association_collection.rb +217 -47
- data/lib/active_record/associations/association_proxy.rb +159 -0
- data/lib/active_record/associations/belongs_to_association.rb +56 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
- data/lib/active_record/associations/has_many_association.rb +145 -75
- data/lib/active_record/associations/has_many_through_association.rb +283 -0
- data/lib/active_record/associations/has_one_association.rb +96 -0
- data/lib/active_record/associations.rb +1537 -304
- data/lib/active_record/attribute_methods.rb +328 -0
- data/lib/active_record/base.rb +2001 -588
- data/lib/active_record/calculations.rb +269 -0
- data/lib/active_record/callbacks.rb +169 -165
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
- data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
- data/lib/active_record/fixtures.rb +946 -100
- data/lib/active_record/locking/optimistic.rb +144 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +417 -0
- data/lib/active_record/observer.rb +142 -32
- data/lib/active_record/query_cache.rb +23 -0
- data/lib/active_record/reflection.rb +163 -70
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +171 -0
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/serializers/xml_serializer.rb +315 -0
- data/lib/active_record/timestamp.rb +41 -0
- data/lib/active_record/transactions.rb +87 -57
- data/lib/active_record/validations.rb +909 -122
- data/lib/active_record/vendor/db2.rb +362 -0
- data/lib/active_record/vendor/mysql.rb +126 -29
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record.rb +35 -7
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +72 -0
- data/test/abstract_unit.rb +73 -5
- data/test/active_schema_test_mysql.rb +43 -0
- data/test/adapter_test.rb +105 -0
- data/test/adapter_test_sqlserver.rb +95 -0
- data/test/aggregations_test.rb +110 -16
- data/test/all.sh +2 -2
- data/test/ar_schema_test.rb +33 -0
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +147 -0
- data/test/associations/cascaded_eager_loading_test.rb +110 -0
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +442 -0
- data/test/associations/extension_test.rb +47 -0
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +553 -0
- data/test/associations_test.rb +1930 -267
- data/test/attribute_methods_test.rb +146 -0
- data/test/base_test.rb +1316 -84
- data/test/binary_test.rb +32 -0
- data/test/calculations_test.rb +251 -0
- data/test/callbacks_test.rb +400 -0
- data/test/class_inheritable_attributes_test.rb +3 -4
- data/test/column_alias_test.rb +17 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +21 -18
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +17 -18
- data/test/connections/native_sqlite/connection.rb +17 -16
- data/test/connections/native_sqlite3/connection.rb +25 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/copy_table_test_sqlite.rb +69 -0
- data/test/datatype_test_postgresql.rb +203 -0
- data/test/date_time_test.rb +37 -0
- data/test/default_test_firebird.rb +16 -0
- data/test/defaults_test.rb +67 -0
- data/test/deprecated_finder_test.rb +30 -0
- data/test/finder_test.rb +607 -32
- data/test/fixtures/accounts.yml +28 -0
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +107 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +7 -0
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
- data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
- data/test/fixtures/bad_fixtures/blank_line +3 -0
- data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
- data/test/fixtures/bad_fixtures/missing_value +1 -0
- data/test/fixtures/binaries.yml +132 -0
- data/test/fixtures/binary.rb +2 -0
- data/test/fixtures/book.rb +4 -0
- data/test/fixtures/books.yml +7 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/category.rb +26 -0
- data/test/fixtures/citation.rb +6 -0
- data/test/fixtures/comment.rb +23 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +55 -0
- data/test/fixtures/company.rb +81 -4
- data/test/fixtures/company_in_module.rb +32 -6
- data/test/fixtures/computer.rb +4 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customer.rb +28 -3
- data/test/fixtures/customers.yml +17 -0
- data/test/fixtures/db_definitions/db2.drop.sql +33 -0
- data/test/fixtures/db_definitions/db2.sql +235 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
- data/test/fixtures/db_definitions/firebird.sql +310 -0
- data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
- data/test/fixtures/db_definitions/firebird2.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
- data/test/fixtures/db_definitions/frontbase.sql +273 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +318 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
- data/test/fixtures/db_definitions/oracle.sql +330 -0
- data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
- data/test/fixtures/db_definitions/postgresql.sql +217 -38
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +2 -2
- data/test/fixtures/db_definitions/schema.rb +354 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
- data/test/fixtures/db_definitions/sqlite.sql +139 -5
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +1 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
- data/test/fixtures/db_definitions/sybase.sql +222 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developer.rb +70 -6
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects/david_action_controller +2 -1
- data/test/fixtures/developers_projects/david_active_record +2 -1
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +3 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
- data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixed_case_monkey.rb +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixins.yml +29 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/people.yml +3 -0
- data/test/fixtures/person.rb +4 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +59 -0
- data/test/fixtures/posts.yml +48 -0
- data/test/fixtures/project.rb +27 -2
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +18 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +4 -3
- data/test/fixtures/tag.rb +7 -0
- data/test/fixtures/tagging.rb +10 -0
- data/test/fixtures/taggings.yml +25 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/task.rb +3 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topic.rb +20 -3
- data/test/fixtures/topics.yml +22 -0
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +574 -8
- data/test/inheritance_test.rb +113 -27
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +56 -29
- data/test/locking_test.rb +273 -0
- data/test/method_scoping_test.rb +416 -0
- data/test/migration_test.rb +933 -0
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_test.rb +95 -0
- data/test/modules_test.rb +23 -10
- data/test/multiple_db_test.rb +17 -3
- data/test/pk_test.rb +59 -15
- data/test/query_cache_test.rb +104 -0
- data/test/readonly_test.rb +107 -0
- data/test/reflection_test.rb +124 -27
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +131 -0
- data/test/schema_test_postgresql.rb +64 -0
- data/test/serialization_test.rb +47 -0
- data/test/synonym_test_oracle.rb +17 -0
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +48 -0
- data/test/transactions_test.rb +227 -29
- data/test/unconnected_test.rb +14 -6
- data/test/validations_test.rb +1293 -32
- data/test/xml_serialization_test.rb +202 -0
- metadata +347 -143
- data/dev-utils/eval_debugger.rb +0 -9
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -88
- data/lib/active_record/deprecated_associations.rb +0 -70
- data/lib/active_record/support/class_attribute_accessors.rb +0 -43
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/inflector.rb +0 -70
- data/lib/active_record/vendor/simple.rb +0 -702
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -59
- data/rakefile +0 -122
- data/test/deprecated_associations_test.rb +0 -336
- data/test/fixtures/accounts/signals37 +0 -3
- data/test/fixtures/accounts/unknown +0 -2
- data/test/fixtures/companies/first_client +0 -6
- data/test/fixtures/companies/first_firm +0 -4
- data/test/fixtures/companies/second_client +0 -6
- data/test/fixtures/courses/java +0 -2
- data/test/fixtures/courses/ruby +0 -2
- data/test/fixtures/customers/david +0 -6
- data/test/fixtures/db_definitions/mysql.sql +0 -96
- data/test/fixtures/db_definitions/mysql2.sql +0 -4
- data/test/fixtures/developers/david +0 -2
- data/test/fixtures/developers/jamis +0 -2
- data/test/fixtures/entrants/first +0 -3
- data/test/fixtures/entrants/second +0 -3
- data/test/fixtures/entrants/third +0 -3
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movies/first +0 -2
- data/test/fixtures/movies/second +0 -2
- data/test/fixtures/projects/action_controller +0 -2
- data/test/fixtures/projects/active_record +0 -2
- data/test/fixtures/topics/first +0 -9
- data/test/fixtures/topics/second +0 -8
- data/test/inflector_test.rb +0 -104
- data/test/thread_safety_test.rb +0 -33
@@ -0,0 +1,34 @@
|
|
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
|
+
parse_sqlite_config!(config)
|
8
|
+
|
9
|
+
unless self.class.const_defined?(:SQLite3)
|
10
|
+
require_library_or_gem(config[:adapter])
|
11
|
+
end
|
12
|
+
|
13
|
+
db = SQLite3::Database.new(
|
14
|
+
config[:database],
|
15
|
+
:results_as_hash => true,
|
16
|
+
:type_translation => false
|
17
|
+
)
|
18
|
+
|
19
|
+
db.busy_timeout(config[:timeout]) unless config[:timeout].nil?
|
20
|
+
|
21
|
+
ConnectionAdapters::SQLite3Adapter.new(db, logger)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ConnectionAdapters #:nodoc:
|
26
|
+
class SQLite3Adapter < SQLiteAdapter # :nodoc:
|
27
|
+
def table_structure(table_name)
|
28
|
+
returning structure = @connection.table_info(table_name) do
|
29
|
+
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,107 +1,391 @@
|
|
1
|
-
# sqlite_adapter.rb
|
2
|
-
# author: Luke Holden <lholden@cablelan.net>
|
3
|
-
|
4
1
|
require 'active_record/connection_adapters/abstract_adapter'
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
module ActiveRecord
|
10
|
-
class Base
|
3
|
+
module ActiveRecord
|
4
|
+
class Base
|
5
|
+
class << self
|
11
6
|
# Establishes a connection to the database that's used by all Active Record objects
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
def sqlite_connection(config) # :nodoc:
|
8
|
+
parse_sqlite_config!(config)
|
9
|
+
|
10
|
+
unless self.class.const_defined?(:SQLite)
|
11
|
+
require_library_or_gem(config[:adapter])
|
12
|
+
|
13
|
+
db = SQLite::Database.new(config[:database], 0)
|
14
|
+
db.show_datatypes = "ON" if !defined? SQLite::Version
|
15
|
+
db.results_as_hash = true if defined? SQLite::Version
|
16
|
+
db.type_translation = false
|
17
|
+
|
18
|
+
# "Downgrade" deprecated sqlite API
|
19
|
+
if SQLite.const_defined?(:Version)
|
20
|
+
ConnectionAdapters::SQLite2Adapter.new(db, logger)
|
21
|
+
else
|
22
|
+
ConnectionAdapters::DeprecatedSQLiteAdapter.new(db, logger)
|
23
|
+
end
|
16
24
|
end
|
25
|
+
end
|
17
26
|
|
18
|
-
|
27
|
+
private
|
28
|
+
def parse_sqlite_config!(config)
|
29
|
+
config[:database] ||= config[:dbfile]
|
30
|
+
# Require database.
|
31
|
+
unless config[:database]
|
32
|
+
raise ArgumentError, "No database file specified. Missing argument: database"
|
33
|
+
end
|
19
34
|
|
20
|
-
|
21
|
-
|
22
|
-
|
35
|
+
# Allow database path relative to RAILS_ROOT, but only if
|
36
|
+
# the database path is not the special path that tells
|
37
|
+
# Sqlite to build a database only in memory.
|
38
|
+
if Object.const_defined?(:RAILS_ROOT) && ':memory:' != config[:database]
|
39
|
+
config[:database] = File.expand_path(config[:database], RAILS_ROOT)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module ConnectionAdapters #:nodoc:
|
46
|
+
class SQLiteColumn < Column #:nodoc:
|
47
|
+
class << self
|
48
|
+
def string_to_binary(value)
|
49
|
+
value.gsub(/\0|\%/n) do |b|
|
50
|
+
case b
|
51
|
+
when "\0" then "%00"
|
52
|
+
when "%" then "%25"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
23
56
|
|
24
|
-
|
57
|
+
def binary_to_string(value)
|
58
|
+
value.gsub(/%00|%25/n) do |b|
|
59
|
+
case b
|
60
|
+
when "%00" then "\0"
|
61
|
+
when "%25" then "%"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
25
65
|
end
|
26
66
|
end
|
27
67
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
68
|
+
# The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby drivers (available both as gems and
|
69
|
+
# from http://rubyforge.org/projects/sqlite-ruby/).
|
70
|
+
#
|
71
|
+
# Options:
|
72
|
+
#
|
73
|
+
# * <tt>:database</tt> -- Path to the database file.
|
74
|
+
class SQLiteAdapter < AbstractAdapter
|
75
|
+
def adapter_name #:nodoc:
|
76
|
+
'SQLite'
|
77
|
+
end
|
78
|
+
|
79
|
+
def supports_migrations? #:nodoc:
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def requires_reloading?
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
87
|
+
def disconnect!
|
88
|
+
super
|
89
|
+
@connection.close rescue nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def supports_count_distinct? #:nodoc:
|
93
|
+
sqlite_version >= '3.2.6'
|
94
|
+
end
|
95
|
+
|
96
|
+
def supports_autoincrement? #:nodoc:
|
97
|
+
sqlite_version >= '3.1.0'
|
98
|
+
end
|
99
|
+
|
100
|
+
def native_database_types #:nodoc:
|
101
|
+
{
|
102
|
+
:primary_key => default_primary_key_type,
|
103
|
+
:string => { :name => "varchar", :limit => 255 },
|
104
|
+
:text => { :name => "text" },
|
105
|
+
:integer => { :name => "integer" },
|
106
|
+
:float => { :name => "float" },
|
107
|
+
:decimal => { :name => "decimal" },
|
108
|
+
:datetime => { :name => "datetime" },
|
109
|
+
:timestamp => { :name => "datetime" },
|
110
|
+
:time => { :name => "datetime" },
|
111
|
+
:date => { :name => "date" },
|
112
|
+
:binary => { :name => "blob" },
|
113
|
+
:boolean => { :name => "boolean" }
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# QUOTING ==================================================
|
119
|
+
|
120
|
+
def quote_string(s) #:nodoc:
|
121
|
+
@connection.class.quote(s)
|
122
|
+
end
|
123
|
+
|
124
|
+
def quote_column_name(name) #:nodoc:
|
125
|
+
%Q("#{name}")
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
# DATABASE STATEMENTS ======================================
|
130
|
+
|
131
|
+
def execute(sql, name = nil) #:nodoc:
|
132
|
+
catch_schema_changes { log(sql, name) { @connection.execute(sql) } }
|
133
|
+
end
|
134
|
+
|
135
|
+
def update_sql(sql, name = nil) #:nodoc:
|
136
|
+
super
|
137
|
+
@connection.changes
|
138
|
+
end
|
139
|
+
|
140
|
+
def delete_sql(sql, name = nil) #:nodoc:
|
141
|
+
sql += " WHERE 1=1" unless sql =~ /WHERE/i
|
142
|
+
super sql, name
|
143
|
+
end
|
144
|
+
|
145
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
146
|
+
super || @connection.last_insert_row_id
|
147
|
+
end
|
148
|
+
|
149
|
+
def select_rows(sql, name = nil)
|
150
|
+
execute(sql, name).map do |row|
|
151
|
+
(0...(row.size / 2)).map { |i| row[i] }
|
32
152
|
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def begin_db_transaction #:nodoc:
|
156
|
+
catch_schema_changes { @connection.transaction }
|
157
|
+
end
|
158
|
+
|
159
|
+
def commit_db_transaction #:nodoc:
|
160
|
+
catch_schema_changes { @connection.commit }
|
161
|
+
end
|
162
|
+
|
163
|
+
def rollback_db_transaction #:nodoc:
|
164
|
+
catch_schema_changes { @connection.rollback }
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
# SELECT ... FOR UPDATE is redundant since the table is locked.
|
169
|
+
def add_lock!(sql, options) #:nodoc:
|
170
|
+
sql
|
171
|
+
end
|
172
|
+
|
33
173
|
|
34
|
-
|
35
|
-
|
36
|
-
|
174
|
+
# SCHEMA STATEMENTS ========================================
|
175
|
+
|
176
|
+
def tables(name = nil) #:nodoc:
|
177
|
+
sql = <<-SQL
|
178
|
+
SELECT name
|
179
|
+
FROM sqlite_master
|
180
|
+
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
181
|
+
SQL
|
182
|
+
|
183
|
+
execute(sql, name).map do |row|
|
184
|
+
row[0]
|
37
185
|
end
|
186
|
+
end
|
38
187
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
columns
|
43
|
-
end
|
188
|
+
def columns(table_name, name = nil) #:nodoc:
|
189
|
+
table_structure(table_name).map do |field|
|
190
|
+
SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'] == "0")
|
44
191
|
end
|
192
|
+
end
|
45
193
|
|
46
|
-
|
47
|
-
|
48
|
-
|
194
|
+
def indexes(table_name, name = nil) #:nodoc:
|
195
|
+
execute("PRAGMA index_list(#{table_name})", name).map do |row|
|
196
|
+
index = IndexDefinition.new(table_name, row['name'])
|
197
|
+
index.unique = row['unique'] != '0'
|
198
|
+
index.columns = execute("PRAGMA index_info('#{index.name}')").map { |col| col['name'] }
|
199
|
+
index
|
49
200
|
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def primary_key(table_name) #:nodoc:
|
204
|
+
column = table_structure(table_name).find {|field| field['pk'].to_i == 1}
|
205
|
+
column ? column['name'] : nil
|
206
|
+
end
|
50
207
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
208
|
+
def remove_index(table_name, options={}) #:nodoc:
|
209
|
+
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
|
210
|
+
end
|
211
|
+
|
212
|
+
def rename_table(name, new_name)
|
213
|
+
execute "ALTER TABLE #{name} RENAME TO #{new_name}"
|
214
|
+
end
|
215
|
+
|
216
|
+
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
217
|
+
super(table_name, column_name, type, options)
|
218
|
+
# See last paragraph on http://www.sqlite.org/lang_altertable.html
|
219
|
+
execute "VACUUM"
|
220
|
+
end
|
221
|
+
|
222
|
+
def remove_column(table_name, column_name) #:nodoc:
|
223
|
+
alter_table(table_name) do |definition|
|
224
|
+
definition.columns.delete(definition[column_name])
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
229
|
+
alter_table(table_name) do |definition|
|
230
|
+
definition[column_name].default = default
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
235
|
+
alter_table(table_name) do |definition|
|
236
|
+
include_default = options_include_default?(options)
|
237
|
+
definition[column_name].instance_eval do
|
238
|
+
self.type = type
|
239
|
+
self.limit = options[:limit] if options.include?(:limit)
|
240
|
+
self.default = options[:default] if include_default
|
241
|
+
self.null = options[:null] if options.include?(:null)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
247
|
+
alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
|
248
|
+
end
|
249
|
+
|
250
|
+
def empty_insert_statement(table_name)
|
251
|
+
"INSERT INTO #{table_name} VALUES(NULL)"
|
252
|
+
end
|
253
|
+
|
254
|
+
protected
|
255
|
+
def select(sql, name = nil) #:nodoc:
|
256
|
+
execute(sql, name).map do |row|
|
257
|
+
record = {}
|
258
|
+
row.each_key do |key|
|
259
|
+
if key.is_a?(String)
|
260
|
+
record[key.sub(/^\w+\./, '')] = row[key]
|
59
261
|
end
|
60
|
-
else
|
61
|
-
connection.execute( sql )
|
62
262
|
end
|
263
|
+
record
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def table_structure(table_name)
|
268
|
+
returning structure = execute("PRAGMA table_info(#{table_name})") do
|
269
|
+
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
63
270
|
end
|
64
271
|
end
|
65
272
|
|
66
|
-
|
67
|
-
|
273
|
+
def alter_table(table_name, options = {}) #:nodoc:
|
274
|
+
altered_table_name = "altered_#{table_name}"
|
275
|
+
caller = lambda {|definition| yield definition if block_given?}
|
68
276
|
|
69
|
-
|
70
|
-
|
71
|
-
|
277
|
+
transaction do
|
278
|
+
move_table(table_name, altered_table_name,
|
279
|
+
options.merge(:temporary => true))
|
280
|
+
move_table(altered_table_name, table_name, &caller)
|
281
|
+
end
|
282
|
+
end
|
72
283
|
|
73
|
-
def
|
74
|
-
|
284
|
+
def move_table(from, to, options = {}, &block) #:nodoc:
|
285
|
+
copy_table(from, to, options, &block)
|
286
|
+
drop_table(from)
|
75
287
|
end
|
76
288
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
289
|
+
def copy_table(from, to, options = {}) #:nodoc:
|
290
|
+
options = options.merge(:id => !columns(from).detect{|c| c.name == 'id'}.nil?)
|
291
|
+
create_table(to, options) do |definition|
|
292
|
+
@definition = definition
|
293
|
+
columns(from).each do |column|
|
294
|
+
column_name = options[:rename] ?
|
295
|
+
(options[:rename][column.name] ||
|
296
|
+
options[:rename][column.name.to_sym] ||
|
297
|
+
column.name) : column.name
|
298
|
+
|
299
|
+
@definition.column(column_name, column.type,
|
300
|
+
:limit => column.limit, :default => column.default,
|
301
|
+
:null => column.null)
|
302
|
+
end
|
303
|
+
@definition.primary_key(primary_key(from)) if primary_key(from)
|
304
|
+
yield @definition if block_given?
|
305
|
+
end
|
81
306
|
|
82
|
-
|
307
|
+
copy_table_indexes(from, to)
|
308
|
+
copy_table_contents(from, to,
|
309
|
+
@definition.columns.map {|column| column.name},
|
310
|
+
options[:rename] || {})
|
311
|
+
end
|
83
312
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
313
|
+
def copy_table_indexes(from, to) #:nodoc:
|
314
|
+
indexes(from).each do |index|
|
315
|
+
name = index.name
|
316
|
+
if to == "altered_#{from}"
|
317
|
+
name = "temp_#{name}"
|
318
|
+
elsif from == "altered_#{to}"
|
319
|
+
name = name[5..-1]
|
90
320
|
end
|
91
321
|
|
92
|
-
|
322
|
+
# index name can't be the same
|
323
|
+
opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
|
324
|
+
opts[:unique] = true if index.unique
|
325
|
+
add_index(to, index.columns, opts)
|
93
326
|
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
|
330
|
+
column_mappings = Hash[*columns.map {|name| [name, name]}.flatten]
|
331
|
+
rename.inject(column_mappings) {|map, a| map[a.last] = a.first; map}
|
332
|
+
from_columns = columns(from).collect {|col| col.name}
|
333
|
+
columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
|
334
|
+
quoted_columns = columns.map { |col| quote_column_name(col) } * ','
|
94
335
|
|
95
|
-
|
96
|
-
sql = "
|
97
|
-
|
98
|
-
|
99
|
-
|
336
|
+
@connection.execute "SELECT * FROM #{from}" do |row|
|
337
|
+
sql = "INSERT INTO #{to} (#{quoted_columns}) VALUES ("
|
338
|
+
sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
|
339
|
+
sql << ')'
|
340
|
+
@connection.execute sql
|
100
341
|
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def catch_schema_changes
|
345
|
+
return yield
|
346
|
+
rescue ActiveRecord::StatementInvalid => exception
|
347
|
+
if exception.message =~ /database schema has changed/
|
348
|
+
reconnect!
|
349
|
+
retry
|
350
|
+
else
|
351
|
+
raise
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def sqlite_version
|
356
|
+
@sqlite_version ||= select_value('select sqlite_version(*)')
|
357
|
+
end
|
358
|
+
|
359
|
+
def default_primary_key_type
|
360
|
+
if supports_autoincrement?
|
361
|
+
'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'.freeze
|
362
|
+
else
|
363
|
+
'INTEGER PRIMARY KEY NOT NULL'.freeze
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
class SQLite2Adapter < SQLiteAdapter # :nodoc:
|
369
|
+
def supports_count_distinct? #:nodoc:
|
370
|
+
false
|
371
|
+
end
|
372
|
+
|
373
|
+
def rename_table(name, new_name)
|
374
|
+
move_table(name, new_name)
|
375
|
+
end
|
376
|
+
|
377
|
+
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
378
|
+
alter_table(table_name) do |definition|
|
379
|
+
definition.column(column_name, type, options)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
class DeprecatedSQLiteAdapter < SQLite2Adapter # :nodoc:
|
385
|
+
def insert(sql, name = nil, pk = nil, id_value = nil)
|
386
|
+
execute(sql, name = nil)
|
387
|
+
id_value || @connection.last_insert_rowid
|
101
388
|
end
|
102
389
|
end
|
103
390
|
end
|
104
|
-
rescue LoadError
|
105
|
-
retry if require('rubygems') rescue LoadError
|
106
|
-
# SQLite driver is not availible
|
107
391
|
end
|