activerecord-jdbc-adapter 1.0.3-java → 50.1-java
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.
- checksums.yaml +7 -0
- data/.gitignore +33 -0
- data/.travis.yml +79 -0
- data/.yardopts +4 -0
- data/CONTRIBUTING.md +50 -0
- data/Gemfile +91 -0
- data/History.md +1191 -0
- data/LICENSE.txt +22 -17
- data/README.md +169 -0
- data/RUNNING_TESTS.md +127 -0
- data/Rakefile +294 -5
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +55 -0
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/activerecord-jdbc-adapter.rb +0 -5
- data/lib/arel/visitors/compat.rb +60 -0
- data/lib/arel/visitors/db2.rb +128 -6
- data/lib/arel/visitors/derby.rb +103 -10
- data/lib/arel/visitors/firebird.rb +79 -0
- data/lib/arel/visitors/h2.rb +25 -0
- data/lib/arel/visitors/hsqldb.rb +18 -10
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +225 -0
- data/lib/arel/visitors/sql_server/ng42.rb +293 -0
- data/lib/arjdbc.rb +11 -21
- data/lib/arjdbc/abstract/connection_management.rb +35 -0
- data/lib/arjdbc/abstract/core.rb +64 -0
- data/lib/arjdbc/abstract/database_statements.rb +64 -0
- data/lib/arjdbc/abstract/statement_cache.rb +58 -0
- data/lib/arjdbc/abstract/transaction_support.rb +86 -0
- data/lib/arjdbc/db2.rb +3 -1
- data/lib/arjdbc/db2/adapter.rb +630 -250
- data/lib/arjdbc/db2/as400.rb +130 -0
- data/lib/arjdbc/db2/column.rb +167 -0
- data/lib/arjdbc/db2/connection_methods.rb +44 -0
- data/lib/arjdbc/derby.rb +1 -5
- data/lib/arjdbc/derby/active_record_patch.rb +13 -0
- data/lib/arjdbc/derby/adapter.rb +409 -217
- data/lib/arjdbc/derby/connection_methods.rb +16 -14
- data/lib/arjdbc/derby/schema_creation.rb +15 -0
- data/lib/arjdbc/discover.rb +62 -50
- data/lib/arjdbc/firebird.rb +3 -1
- data/lib/arjdbc/firebird/adapter.rb +365 -62
- data/lib/arjdbc/firebird/connection_methods.rb +23 -0
- data/lib/arjdbc/h2.rb +2 -3
- data/lib/arjdbc/h2/adapter.rb +273 -6
- data/lib/arjdbc/h2/connection_methods.rb +23 -8
- data/lib/arjdbc/hsqldb.rb +2 -3
- data/lib/arjdbc/hsqldb/adapter.rb +204 -77
- data/lib/arjdbc/hsqldb/connection_methods.rb +24 -10
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
- data/lib/arjdbc/informix.rb +4 -2
- data/lib/arjdbc/informix/adapter.rb +78 -54
- data/lib/arjdbc/informix/connection_methods.rb +8 -9
- data/lib/arjdbc/jdbc.rb +59 -2
- data/lib/arjdbc/jdbc/adapter.rb +356 -166
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/base_ext.rb +15 -0
- data/lib/arjdbc/jdbc/callbacks.rb +27 -18
- data/lib/arjdbc/jdbc/column.rb +79 -20
- data/lib/arjdbc/jdbc/connection.rb +5 -119
- data/lib/arjdbc/jdbc/connection_methods.rb +32 -4
- data/lib/arjdbc/jdbc/error.rb +65 -0
- data/lib/arjdbc/jdbc/extension.rb +41 -29
- data/lib/arjdbc/jdbc/java.rb +5 -6
- data/lib/arjdbc/jdbc/jdbc.rake +3 -126
- data/lib/arjdbc/jdbc/railtie.rb +2 -9
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
- data/lib/arjdbc/jdbc/type_cast.rb +166 -0
- data/lib/arjdbc/jdbc/type_converter.rb +35 -19
- data/lib/arjdbc/mssql.rb +6 -3
- data/lib/arjdbc/mssql/adapter.rb +630 -298
- data/lib/arjdbc/mssql/column.rb +200 -0
- data/lib/arjdbc/mssql/connection_methods.rb +66 -17
- data/lib/arjdbc/mssql/explain_support.rb +99 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +189 -50
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +82 -0
- data/lib/arjdbc/mysql.rb +2 -3
- data/lib/arjdbc/mysql/adapter.rb +86 -356
- data/lib/arjdbc/mysql/connection_methods.rb +159 -23
- data/lib/arjdbc/oracle/adapter.rb +714 -263
- data/lib/arjdbc/postgresql.rb +2 -3
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +24 -0
- data/lib/arjdbc/postgresql/adapter.rb +570 -400
- data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
- data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
- data/lib/arjdbc/postgresql/column.rb +51 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +57 -18
- data/lib/arjdbc/postgresql/name.rb +24 -0
- data/lib/arjdbc/postgresql/oid_types.rb +192 -0
- data/lib/arjdbc/railtie.rb +11 -0
- data/lib/arjdbc/sqlite3.rb +2 -3
- data/lib/arjdbc/sqlite3/adapter.rb +518 -198
- data/lib/arjdbc/sqlite3/connection_methods.rb +49 -24
- data/lib/arjdbc/sybase.rb +2 -2
- data/lib/arjdbc/sybase/adapter.rb +7 -6
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +52 -0
- data/lib/arjdbc/tasks/databases.rake +91 -0
- data/lib/arjdbc/tasks/databases3.rake +215 -0
- data/lib/arjdbc/tasks/databases4.rake +39 -0
- data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
- data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
- data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/serialized_attributes.rb +98 -0
- data/lib/arjdbc/util/table_copier.rb +110 -0
- data/lib/arjdbc/version.rb +1 -6
- data/lib/generators/jdbc/USAGE +9 -0
- data/lib/generators/jdbc/jdbc_generator.rb +8 -0
- data/lib/jdbc_adapter.rb +1 -1
- data/lib/jdbc_adapter/rake_tasks.rb +3 -2
- data/lib/jdbc_adapter/version.rb +2 -1
- data/pom.xml +114 -0
- data/rails_generators/jdbc_generator.rb +1 -1
- data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
- data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
- data/rakelib/01-tomcat.rake +51 -0
- data/rakelib/02-test.rake +132 -0
- data/rakelib/bundler_ext.rb +11 -0
- data/rakelib/compile.rake +67 -22
- data/rakelib/db.rake +61 -0
- data/rakelib/rails.rake +204 -29
- data/src/java/arjdbc/ArJdbcModule.java +286 -0
- data/src/java/arjdbc/db2/DB2Module.java +76 -0
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
- data/src/java/arjdbc/derby/DerbyModule.java +99 -243
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
- data/src/java/arjdbc/{jdbc/JdbcConnectionFactory.java → h2/H2Module.java} +20 -6
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +27 -12
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +7 -29
- data/src/java/arjdbc/jdbc/Callable.java +44 -0
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +132 -0
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +157 -0
- data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
- data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
- data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3622 -948
- data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +181 -0
- data/src/java/arjdbc/mysql/MySQLModule.java +99 -81
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
- data/src/java/arjdbc/oracle/OracleModule.java +80 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +387 -17
- data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
- data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
- data/src/java/arjdbc/postgresql/PostgreSQLResult.java +184 -0
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +952 -0
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
- data/src/java/arjdbc/util/CallResultSet.java +826 -0
- data/src/java/arjdbc/util/DateTimeUtils.java +580 -0
- data/src/java/arjdbc/util/ObjectSupport.java +65 -0
- data/src/java/arjdbc/util/QuotingUtils.java +138 -0
- data/src/java/arjdbc/util/StringCache.java +63 -0
- data/src/java/arjdbc/util/StringHelper.java +159 -0
- metadata +245 -268
- data/History.txt +0 -369
- data/Manifest.txt +0 -180
- data/README.txt +0 -181
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
- data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
- data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
- data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
- data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
- data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
- data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
- data/lib/arel/visitors/mssql.rb +0 -44
- data/lib/arjdbc/jdbc/compatibility.rb +0 -51
- data/lib/arjdbc/jdbc/core_ext.rb +0 -24
- data/lib/arjdbc/jdbc/discover.rb +0 -18
- data/lib/arjdbc/jdbc/driver.rb +0 -44
- data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -87
- data/lib/arjdbc/jdbc/quoted_primary_key.rb +0 -28
- data/lib/arjdbc/jdbc/require_driver.rb +0 -16
- data/lib/arjdbc/mimer.rb +0 -2
- data/lib/arjdbc/mimer/adapter.rb +0 -142
- data/lib/arjdbc/mssql/tsql_helper.rb +0 -61
- data/lib/arjdbc/oracle.rb +0 -3
- data/lib/arjdbc/oracle/connection_methods.rb +0 -11
- data/lib/pg.rb +0 -4
- data/rakelib/package.rake +0 -92
- data/rakelib/test.rake +0 -81
- data/src/java/arjdbc/jdbc/SQLBlock.java +0 -48
- data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +0 -127
- data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +0 -57
- data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +0 -64
- data/test/abstract_db_create.rb +0 -117
- data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -31
- data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
- data/test/db/db2.rb +0 -11
- data/test/db/derby.rb +0 -12
- data/test/db/h2.rb +0 -11
- data/test/db/hsqldb.rb +0 -13
- data/test/db/informix.rb +0 -11
- data/test/db/jdbc.rb +0 -11
- data/test/db/jndi_config.rb +0 -40
- data/test/db/logger.rb +0 -3
- data/test/db/mssql.rb +0 -9
- data/test/db/mysql.rb +0 -10
- data/test/db/oracle.rb +0 -34
- data/test/db/postgres.rb +0 -9
- data/test/db/sqlite3.rb +0 -11
- data/test/db2_simple_test.rb +0 -66
- data/test/derby_migration_test.rb +0 -68
- data/test/derby_multibyte_test.rb +0 -12
- data/test/derby_simple_test.rb +0 -99
- data/test/generic_jdbc_connection_test.rb +0 -29
- data/test/h2_simple_test.rb +0 -41
- data/test/has_many_through.rb +0 -79
- data/test/helper.rb +0 -5
- data/test/hsqldb_simple_test.rb +0 -6
- data/test/informix_simple_test.rb +0 -48
- data/test/jdbc_common.rb +0 -25
- data/test/jndi_callbacks_test.rb +0 -40
- data/test/jndi_test.rb +0 -25
- data/test/manualTestDatabase.rb +0 -191
- data/test/models/add_not_null_column_to_table.rb +0 -12
- data/test/models/auto_id.rb +0 -18
- data/test/models/data_types.rb +0 -28
- data/test/models/entry.rb +0 -43
- data/test/models/mixed_case.rb +0 -25
- data/test/models/reserved_word.rb +0 -18
- data/test/models/string_id.rb +0 -18
- data/test/models/validates_uniqueness_of_string.rb +0 -19
- data/test/mssql_db_create_test.rb +0 -26
- data/test/mssql_identity_insert_test.rb +0 -19
- data/test/mssql_legacy_types_test.rb +0 -58
- data/test/mssql_limit_offset_test.rb +0 -136
- data/test/mssql_multibyte_test.rb +0 -18
- data/test/mssql_simple_test.rb +0 -55
- data/test/mysql_db_create_test.rb +0 -27
- data/test/mysql_info_test.rb +0 -113
- data/test/mysql_multibyte_test.rb +0 -10
- data/test/mysql_nonstandard_primary_key_test.rb +0 -42
- data/test/mysql_simple_test.rb +0 -49
- data/test/oracle_simple_test.rb +0 -18
- data/test/oracle_specific_test.rb +0 -83
- data/test/pick_rails_version.rb +0 -3
- data/test/postgres_db_create_test.rb +0 -32
- data/test/postgres_drop_db_test.rb +0 -16
- data/test/postgres_mixed_case_test.rb +0 -29
- data/test/postgres_nonseq_pkey_test.rb +0 -38
- data/test/postgres_reserved_test.rb +0 -22
- data/test/postgres_schema_search_path_test.rb +0 -44
- data/test/postgres_simple_test.rb +0 -51
- data/test/postgres_table_alias_length_test.rb +0 -15
- data/test/simple.rb +0 -546
- data/test/sqlite3_simple_test.rb +0 -233
- data/test/sybase_jtds_simple_test.rb +0 -28
data/lib/arjdbc/sqlite3.rb
CHANGED
|
@@ -1,226 +1,353 @@
|
|
|
1
|
-
|
|
1
|
+
ArJdbc.load_java_part :SQLite3
|
|
2
|
+
|
|
3
|
+
require "arjdbc/abstract/core"
|
|
4
|
+
require "arjdbc/abstract/database_statements"
|
|
5
|
+
require 'arjdbc/abstract/statement_cache'
|
|
6
|
+
require "arjdbc/abstract/transaction_support"
|
|
7
|
+
require "active_record/connection_adapters/statement_pool"
|
|
8
|
+
require "active_record/connection_adapters/abstract/database_statements"
|
|
9
|
+
require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
|
|
10
|
+
require "active_record/connection_adapters/sqlite3/quoting"
|
|
11
|
+
require "active_record/connection_adapters/sqlite3/schema_creation"
|
|
12
|
+
|
|
13
|
+
module ArJdbc
|
|
14
|
+
# All the code in this module is a copy of ConnectionAdapters::SQLite3Adapter from active_record 5.
|
|
15
|
+
# The constants at the front of this file are to allow the rest of the file to remain with no modifications
|
|
16
|
+
# from its original source. If you hack on this file try not to modify this module and instead try and
|
|
17
|
+
# put those overrides in SQL3Adapter below. We try and keep a copy of the Rails this adapter supports
|
|
18
|
+
# with the current goal of being able to diff changes easily over time and to also eventually remove
|
|
19
|
+
# this module from ARJDBC altogether.
|
|
20
|
+
module SQLite3
|
|
21
|
+
# DIFFERENCE: Some common constant names to reduce differences in rest of this module from AR5 version
|
|
22
|
+
ConnectionAdapters = ::ActiveRecord::ConnectionAdapters
|
|
23
|
+
IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
|
|
24
|
+
Quoting = ::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
|
|
25
|
+
RecordNotUnique = ::ActiveRecord::RecordNotUnique
|
|
26
|
+
SchemaCreation = ConnectionAdapters::SQLite3::SchemaCreation
|
|
27
|
+
SQLite3Adapter = ConnectionAdapters::AbstractAdapter
|
|
28
|
+
|
|
29
|
+
ADAPTER_NAME = 'SQLite'.freeze
|
|
30
|
+
|
|
31
|
+
include Quoting
|
|
32
|
+
|
|
33
|
+
NATIVE_DATABASE_TYPES = {
|
|
34
|
+
primary_key: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
|
|
35
|
+
string: { name: "varchar" },
|
|
36
|
+
text: { name: "text" },
|
|
37
|
+
integer: { name: "integer" },
|
|
38
|
+
float: { name: "float" },
|
|
39
|
+
decimal: { name: "decimal" },
|
|
40
|
+
datetime: { name: "datetime" },
|
|
41
|
+
time: { name: "time" },
|
|
42
|
+
date: { name: "date" },
|
|
43
|
+
binary: { name: "blob" },
|
|
44
|
+
boolean: { name: "boolean" }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
class StatementPool < ConnectionAdapters::StatementPool
|
|
48
|
+
private
|
|
2
49
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
end
|
|
50
|
+
def dealloc(stmt)
|
|
51
|
+
stmt[:stmt].close unless stmt[:stmt].closed?
|
|
52
|
+
end
|
|
53
|
+
end
|
|
6
54
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def self.column_selector
|
|
10
|
-
[/sqlite/i, lambda {|cfg,col| col.extend(::ArJdbc::SQLite3::Column)}]
|
|
55
|
+
def schema_creation # :nodoc:
|
|
56
|
+
SQLite3::SchemaCreation.new self
|
|
11
57
|
end
|
|
12
58
|
|
|
13
|
-
def
|
|
14
|
-
::
|
|
59
|
+
def arel_visitor # :nodoc:
|
|
60
|
+
Arel::Visitors::SQLite.new(self)
|
|
15
61
|
end
|
|
16
62
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
end
|
|
63
|
+
# Difference we remove connection_options because we are not using it.
|
|
64
|
+
def initialize(connection, logger, config)
|
|
65
|
+
super(connection, logger, config)
|
|
21
66
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
when :string then value
|
|
26
|
-
when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
|
27
|
-
when :float then value.to_f
|
|
28
|
-
when :decimal then self.class.value_to_decimal(value)
|
|
29
|
-
when :boolean then self.class.value_to_boolean(value)
|
|
30
|
-
else super
|
|
31
|
-
end
|
|
32
|
-
end
|
|
67
|
+
@active = nil
|
|
68
|
+
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
|
69
|
+
end
|
|
33
70
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
when /boolean/i then :boolean
|
|
38
|
-
when /text/i then :text
|
|
39
|
-
when /varchar/i then :string
|
|
40
|
-
when /int/i then :integer
|
|
41
|
-
when /float/i then :float
|
|
42
|
-
when /real/i then @scale == 0 ? :integer : :decimal
|
|
43
|
-
when /datetime/i then :datetime
|
|
44
|
-
when /date/i then :date
|
|
45
|
-
when /time/i then :time
|
|
46
|
-
when /blob/i then :binary
|
|
47
|
-
end
|
|
48
|
-
end
|
|
71
|
+
def supports_ddl_transactions?
|
|
72
|
+
true
|
|
73
|
+
end
|
|
49
74
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
else super
|
|
54
|
-
end
|
|
55
|
-
end
|
|
75
|
+
def supports_savepoints?
|
|
76
|
+
true
|
|
77
|
+
end
|
|
56
78
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
|
|
61
|
-
else super
|
|
62
|
-
end
|
|
63
|
-
end
|
|
79
|
+
def supports_partial_index?
|
|
80
|
+
sqlite_version >= "3.8.0"
|
|
81
|
+
end
|
|
64
82
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
# Returns true, since this connection adapter supports prepared statement
|
|
84
|
+
# caching.
|
|
85
|
+
def supports_statement_cache?
|
|
86
|
+
true
|
|
87
|
+
end
|
|
69
88
|
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
# Returns true, since this connection adapter supports migrations.
|
|
90
|
+
def supports_migrations? #:nodoc:
|
|
91
|
+
true
|
|
72
92
|
end
|
|
73
93
|
|
|
74
|
-
def
|
|
75
|
-
|
|
94
|
+
def supports_primary_key? #:nodoc:
|
|
95
|
+
true
|
|
76
96
|
end
|
|
77
97
|
|
|
78
|
-
def
|
|
79
|
-
|
|
98
|
+
def requires_reloading?
|
|
99
|
+
true
|
|
80
100
|
end
|
|
81
101
|
|
|
82
|
-
def
|
|
83
|
-
|
|
102
|
+
def supports_views?
|
|
103
|
+
true
|
|
84
104
|
end
|
|
85
105
|
|
|
86
|
-
def
|
|
87
|
-
|
|
106
|
+
def supports_datetime_with_precision?
|
|
107
|
+
true
|
|
88
108
|
end
|
|
89
109
|
|
|
90
|
-
def
|
|
91
|
-
|
|
110
|
+
def supports_multi_insert?
|
|
111
|
+
sqlite_version >= "3.7.11"
|
|
92
112
|
end
|
|
93
113
|
|
|
94
|
-
def
|
|
95
|
-
|
|
96
|
-
tp[:string] = { :name => "VARCHAR", :limit => 255 }
|
|
97
|
-
tp[:float] = { :name => "REAL" }
|
|
98
|
-
tp[:decimal] = { :name => "REAL" }
|
|
99
|
-
tp[:datetime] = { :name => "DATETIME" }
|
|
100
|
-
tp[:timestamp] = { :name => "DATETIME" }
|
|
101
|
-
tp[:time] = { :name => "TIME" }
|
|
102
|
-
tp[:date] = { :name => "DATE" }
|
|
103
|
-
tp[:boolean] = { :name => "BOOLEAN" }
|
|
104
|
-
tp[:binary] = { :name => "BLOB" }
|
|
105
|
-
tp
|
|
114
|
+
def active?
|
|
115
|
+
@active != false
|
|
106
116
|
end
|
|
107
117
|
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
# Disconnects from the database if already connected. Otherwise, this
|
|
119
|
+
# method does nothing.
|
|
120
|
+
def disconnect!
|
|
121
|
+
super
|
|
122
|
+
@active = false
|
|
123
|
+
@connection.close rescue nil
|
|
110
124
|
end
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
# Clears the prepared statements cache.
|
|
127
|
+
def clear_cache!
|
|
128
|
+
@statements.clear
|
|
114
129
|
end
|
|
115
130
|
|
|
116
|
-
def
|
|
117
|
-
|
|
131
|
+
def supports_index_sort_order?
|
|
132
|
+
true
|
|
118
133
|
end
|
|
119
134
|
|
|
120
|
-
def
|
|
121
|
-
|
|
135
|
+
def valid_type?(type)
|
|
136
|
+
true
|
|
122
137
|
end
|
|
123
138
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
139
|
+
# Returns 62. SQLite supports index names up to 64
|
|
140
|
+
# characters. The rest is used by Rails internally to perform
|
|
141
|
+
# temporary rename operations
|
|
142
|
+
def allowed_index_name_length
|
|
143
|
+
index_name_length - 2
|
|
127
144
|
end
|
|
128
145
|
|
|
129
|
-
def
|
|
130
|
-
|
|
146
|
+
def native_database_types #:nodoc:
|
|
147
|
+
NATIVE_DATABASE_TYPES
|
|
131
148
|
end
|
|
132
149
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
|
138
|
-
SQL
|
|
150
|
+
# Returns the current database encoding format as a string, eg: 'UTF-8'
|
|
151
|
+
def encoding
|
|
152
|
+
@connection.encoding.to_s
|
|
153
|
+
end
|
|
139
154
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
end
|
|
155
|
+
def supports_explain?
|
|
156
|
+
true
|
|
143
157
|
end
|
|
144
158
|
|
|
145
|
-
|
|
146
|
-
|
|
159
|
+
#--
|
|
160
|
+
# DATABASE STATEMENTS ======================================
|
|
161
|
+
#++
|
|
162
|
+
|
|
163
|
+
def explain(arel, binds = [])
|
|
164
|
+
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
|
165
|
+
::ActiveRecord::ConnectionAdapters::SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
|
147
166
|
end
|
|
148
167
|
|
|
149
|
-
def
|
|
150
|
-
|
|
168
|
+
def exec_query(sql, name = nil, binds = [], prepare: false)
|
|
169
|
+
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
|
|
151
170
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
171
|
+
log(sql, name, binds) do
|
|
172
|
+
# Don't cache statements if they are not prepared
|
|
173
|
+
unless prepare
|
|
174
|
+
stmt = @connection.prepare(sql)
|
|
175
|
+
begin
|
|
176
|
+
cols = stmt.columns
|
|
177
|
+
unless without_prepared_statement?(binds)
|
|
178
|
+
stmt.bind_params(type_casted_binds)
|
|
179
|
+
end
|
|
180
|
+
records = stmt.to_a
|
|
181
|
+
ensure
|
|
182
|
+
stmt.close
|
|
183
|
+
end
|
|
184
|
+
stmt = records
|
|
185
|
+
else
|
|
186
|
+
cache = @statements[sql] ||= {
|
|
187
|
+
:stmt => @connection.prepare(sql)
|
|
188
|
+
}
|
|
189
|
+
stmt = cache[:stmt]
|
|
190
|
+
cols = cache[:cols] ||= stmt.columns
|
|
191
|
+
stmt.reset!
|
|
192
|
+
stmt.bind_params(type_casted_binds)
|
|
158
193
|
end
|
|
159
|
-
|
|
194
|
+
|
|
195
|
+
ActiveRecord::Result.new(cols, stmt.to_a)
|
|
160
196
|
end
|
|
161
197
|
end
|
|
162
198
|
|
|
163
|
-
def
|
|
164
|
-
|
|
165
|
-
|
|
199
|
+
def exec_delete(sql, name = 'SQL', binds = [])
|
|
200
|
+
exec_query(sql, name, binds)
|
|
201
|
+
@connection.changes
|
|
166
202
|
end
|
|
203
|
+
alias :exec_update :exec_delete
|
|
167
204
|
|
|
168
|
-
def
|
|
169
|
-
|
|
205
|
+
def last_inserted_id(result)
|
|
206
|
+
@connection.last_insert_row_id
|
|
170
207
|
end
|
|
171
208
|
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql) ? last_insert_id : result
|
|
209
|
+
def execute(sql, name = nil) #:nodoc:
|
|
210
|
+
log(sql, name) { @connection.execute(sql) }
|
|
175
211
|
end
|
|
176
212
|
|
|
177
|
-
def
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
213
|
+
def begin_db_transaction #:nodoc:
|
|
214
|
+
log("begin transaction",nil) { @connection.transaction }
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def commit_db_transaction #:nodoc:
|
|
218
|
+
log("commit transaction",nil) { @connection.commit }
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def exec_rollback_db_transaction #:nodoc:
|
|
222
|
+
log("rollback transaction",nil) { @connection.rollback }
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# SCHEMA STATEMENTS ========================================
|
|
226
|
+
|
|
227
|
+
def tables(name = nil) # :nodoc:
|
|
228
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
|
229
|
+
#tables currently returns both tables and views.
|
|
230
|
+
This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
|
|
231
|
+
Use #data_sources instead.
|
|
232
|
+
MSG
|
|
233
|
+
|
|
234
|
+
if name
|
|
235
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
|
236
|
+
Passing arguments to #tables is deprecated without replacement.
|
|
237
|
+
MSG
|
|
186
238
|
end
|
|
239
|
+
|
|
240
|
+
data_sources
|
|
187
241
|
end
|
|
188
242
|
|
|
189
|
-
def
|
|
190
|
-
|
|
191
|
-
raise ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'" if structure.empty?
|
|
192
|
-
structure
|
|
243
|
+
def data_sources
|
|
244
|
+
select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", "SCHEMA")
|
|
193
245
|
end
|
|
194
246
|
|
|
195
|
-
def
|
|
247
|
+
def table_exists?(table_name)
|
|
248
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
|
249
|
+
#table_exists? currently checks both tables and views.
|
|
250
|
+
This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
|
|
251
|
+
Use #data_source_exists? instead.
|
|
252
|
+
MSG
|
|
253
|
+
|
|
254
|
+
data_source_exists?(table_name)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def data_source_exists?(table_name)
|
|
258
|
+
return false unless table_name.present?
|
|
259
|
+
|
|
260
|
+
sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'"
|
|
261
|
+
sql << " AND name = #{quote(table_name)}"
|
|
262
|
+
|
|
263
|
+
select_values(sql, "SCHEMA").any?
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def views # :nodoc:
|
|
267
|
+
select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", "SCHEMA")
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def view_exists?(view_name) # :nodoc:
|
|
271
|
+
return false unless view_name.present?
|
|
272
|
+
|
|
273
|
+
sql = "SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'"
|
|
274
|
+
sql << " AND name = #{quote(view_name)}"
|
|
275
|
+
|
|
276
|
+
select_values(sql, "SCHEMA").any?
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
|
280
|
+
def columns(table_name) # :nodoc:
|
|
281
|
+
table_name = table_name.to_s
|
|
196
282
|
table_structure(table_name).map do |field|
|
|
197
|
-
|
|
283
|
+
case field["dflt_value"]
|
|
284
|
+
when /^null$/i
|
|
285
|
+
field["dflt_value"] = nil
|
|
286
|
+
when /^'(.*)'$/m
|
|
287
|
+
field["dflt_value"] = $1.gsub("''", "'")
|
|
288
|
+
when /^"(.*)"$/m
|
|
289
|
+
field["dflt_value"] = $1.gsub('""', '"')
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
collation = field["collation"]
|
|
293
|
+
sql_type = field["type"]
|
|
294
|
+
type_metadata = fetch_type_metadata(sql_type)
|
|
295
|
+
new_column(field["name"], field["dflt_value"], type_metadata, field["notnull"].to_i == 0, table_name, nil, collation)
|
|
198
296
|
end
|
|
199
297
|
end
|
|
200
298
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
299
|
+
# Returns an array of indexes for the given table.
|
|
300
|
+
def indexes(table_name, name = nil) #:nodoc:
|
|
301
|
+
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
|
|
302
|
+
sql = <<-SQL
|
|
303
|
+
SELECT sql
|
|
304
|
+
FROM sqlite_master
|
|
305
|
+
WHERE name=#{quote(row['name'])} AND type='index'
|
|
306
|
+
UNION ALL
|
|
307
|
+
SELECT sql
|
|
308
|
+
FROM sqlite_temp_master
|
|
309
|
+
WHERE name=#{quote(row['name'])} AND type='index'
|
|
310
|
+
SQL
|
|
311
|
+
index_sql = exec_query(sql).first["sql"]
|
|
312
|
+
match = /\sWHERE\s+(.+)$/i.match(index_sql)
|
|
313
|
+
where = match[1] if match
|
|
314
|
+
IndexDefinition.new(
|
|
315
|
+
table_name,
|
|
316
|
+
row["name"],
|
|
317
|
+
row["unique"] != 0,
|
|
318
|
+
exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
|
|
319
|
+
col["name"]
|
|
320
|
+
}, nil, nil, where)
|
|
321
|
+
end
|
|
206
322
|
end
|
|
207
323
|
|
|
208
|
-
def
|
|
209
|
-
|
|
324
|
+
def primary_keys(table_name) # :nodoc:
|
|
325
|
+
pks = table_structure(table_name).select { |f| f["pk"] > 0 }
|
|
326
|
+
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
|
|
210
327
|
end
|
|
211
328
|
|
|
212
|
-
def
|
|
213
|
-
|
|
329
|
+
def remove_index(table_name, options = {}) #:nodoc:
|
|
330
|
+
index_name = index_name_for_remove(table_name, options)
|
|
331
|
+
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Renames a table.
|
|
335
|
+
#
|
|
336
|
+
# Example:
|
|
337
|
+
# rename_table('octopuses', 'octopi')
|
|
338
|
+
def rename_table(table_name, new_name)
|
|
339
|
+
exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
|
|
340
|
+
rename_table_indexes(table_name, new_name)
|
|
214
341
|
end
|
|
215
342
|
|
|
216
343
|
# See: http://www.sqlite.org/lang_altertable.html
|
|
217
344
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
|
218
|
-
def
|
|
345
|
+
def valid_alter_table_type?(type)
|
|
219
346
|
type.to_sym != :primary_key
|
|
220
347
|
end
|
|
221
348
|
|
|
222
349
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
|
223
|
-
if
|
|
350
|
+
if valid_alter_table_type?(type)
|
|
224
351
|
super(table_name, column_name, type, options)
|
|
225
352
|
else
|
|
226
353
|
alter_table(table_name) do |definition|
|
|
@@ -229,25 +356,23 @@ module ::ArJdbc
|
|
|
229
356
|
end
|
|
230
357
|
end
|
|
231
358
|
|
|
232
|
-
def remove_column(table_name,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
alter_table(table_name) do |definition|
|
|
236
|
-
definition.columns.delete(definition[column_name])
|
|
237
|
-
end
|
|
359
|
+
def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
|
|
360
|
+
alter_table(table_name) do |definition|
|
|
361
|
+
definition.remove_column column_name
|
|
238
362
|
end
|
|
239
363
|
end
|
|
240
|
-
alias :remove_columns :remove_column
|
|
241
364
|
|
|
242
|
-
def change_column_default(table_name, column_name,
|
|
365
|
+
def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
|
|
366
|
+
default = extract_new_default_value(default_or_changes)
|
|
367
|
+
|
|
243
368
|
alter_table(table_name) do |definition|
|
|
244
369
|
definition[column_name].default = default
|
|
245
370
|
end
|
|
246
371
|
end
|
|
247
372
|
|
|
248
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
|
373
|
+
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
|
|
249
374
|
unless null || default.nil?
|
|
250
|
-
|
|
375
|
+
exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
|
251
376
|
end
|
|
252
377
|
alter_table(table_name) do |definition|
|
|
253
378
|
definition[column_name].null = null
|
|
@@ -262,47 +387,166 @@ module ::ArJdbc
|
|
|
262
387
|
self.limit = options[:limit] if options.include?(:limit)
|
|
263
388
|
self.default = options[:default] if include_default
|
|
264
389
|
self.null = options[:null] if options.include?(:null)
|
|
390
|
+
self.precision = options[:precision] if options.include?(:precision)
|
|
391
|
+
self.scale = options[:scale] if options.include?(:scale)
|
|
392
|
+
self.collation = options[:collation] if options.include?(:collation)
|
|
265
393
|
end
|
|
266
394
|
end
|
|
267
395
|
end
|
|
268
396
|
|
|
269
397
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
|
270
|
-
|
|
271
|
-
|
|
398
|
+
column = column_for(table_name, column_name)
|
|
399
|
+
alter_table(table_name, rename: { column.name => new_column_name.to_s })
|
|
400
|
+
rename_column_indexes(table_name, column.name, new_column_name)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
protected
|
|
404
|
+
|
|
405
|
+
def table_structure(table_name)
|
|
406
|
+
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
|
407
|
+
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
|
408
|
+
table_structure_with_collation(table_name, structure)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def alter_table(table_name, options = {}) #:nodoc:
|
|
412
|
+
altered_table_name = "a#{table_name}"
|
|
413
|
+
caller = lambda { |definition| yield definition if block_given? }
|
|
414
|
+
|
|
415
|
+
transaction do
|
|
416
|
+
move_table(table_name, altered_table_name,
|
|
417
|
+
options.merge(temporary: true))
|
|
418
|
+
move_table(altered_table_name, table_name, &caller)
|
|
272
419
|
end
|
|
273
|
-
alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
|
|
274
420
|
end
|
|
275
421
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
422
|
+
def move_table(from, to, options = {}, &block) #:nodoc:
|
|
423
|
+
copy_table(from, to, options, &block)
|
|
424
|
+
drop_table(from)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def copy_table(from, to, options = {}) #:nodoc:
|
|
428
|
+
from_primary_key = primary_key(from)
|
|
429
|
+
options[:id] = false
|
|
430
|
+
create_table(to, options) do |definition|
|
|
431
|
+
@definition = definition
|
|
432
|
+
@definition.primary_key(from_primary_key) if from_primary_key.present?
|
|
433
|
+
columns(from).each do |column|
|
|
434
|
+
column_name = options[:rename] ?
|
|
435
|
+
(options[:rename][column.name] ||
|
|
436
|
+
options[:rename][column.name.to_sym] ||
|
|
437
|
+
column.name) : column.name
|
|
438
|
+
next if column_name == from_primary_key
|
|
439
|
+
|
|
440
|
+
@definition.column(column_name, column.type,
|
|
441
|
+
limit: column.limit, default: column.default,
|
|
442
|
+
precision: column.precision, scale: column.scale,
|
|
443
|
+
null: column.null, collation: column.collation)
|
|
444
|
+
end
|
|
445
|
+
yield @definition if block_given?
|
|
446
|
+
end
|
|
447
|
+
copy_table_indexes(from, to, options[:rename] || {})
|
|
448
|
+
copy_table_contents(from, to,
|
|
449
|
+
@definition.columns.map(&:name),
|
|
450
|
+
options[:rename] || {})
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def copy_table_indexes(from, to, rename = {}) #:nodoc:
|
|
454
|
+
indexes(from).each do |index|
|
|
455
|
+
name = index.name
|
|
456
|
+
if to == "a#{from}"
|
|
457
|
+
name = "t#{name}"
|
|
458
|
+
elsif from == "a#{to}"
|
|
459
|
+
name = name[1..-1]
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
to_column_names = columns(to).map(&:name)
|
|
463
|
+
columns = index.columns.map { |c| rename[c] || c }.select do |column|
|
|
464
|
+
to_column_names.include?(column)
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
unless columns.empty?
|
|
468
|
+
# index name can't be the same
|
|
469
|
+
opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
|
470
|
+
opts[:unique] = true if index.unique
|
|
471
|
+
add_index(to, columns, opts)
|
|
472
|
+
end
|
|
473
|
+
end
|
|
279
474
|
end
|
|
280
475
|
|
|
281
|
-
def
|
|
282
|
-
|
|
476
|
+
def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
|
|
477
|
+
column_mappings = Hash[columns.map { |name| [name, name] }]
|
|
478
|
+
rename.each { |a| column_mappings[a.last] = a.first }
|
|
479
|
+
from_columns = columns(from).collect(&:name)
|
|
480
|
+
columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
|
|
481
|
+
from_columns_to_copy = columns.map { |col| column_mappings[col] }
|
|
482
|
+
quoted_columns = columns.map { |col| quote_column_name(col) } * ","
|
|
483
|
+
quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
|
|
484
|
+
|
|
485
|
+
exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
|
|
486
|
+
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
|
|
283
487
|
end
|
|
284
488
|
|
|
285
|
-
|
|
286
|
-
|
|
489
|
+
def sqlite_version
|
|
490
|
+
@sqlite_version ||= SQLite3Adapter::Version.new(select_value("select sqlite_version(*)"))
|
|
491
|
+
end
|
|
287
492
|
|
|
288
493
|
def translate_exception(exception, message)
|
|
289
494
|
case exception.message
|
|
290
|
-
|
|
291
|
-
|
|
495
|
+
# SQLite 3.8.2 returns a newly formatted error message:
|
|
496
|
+
# UNIQUE constraint failed: *table_name*.*column_name*
|
|
497
|
+
# Older versions of SQLite return:
|
|
498
|
+
# column *column_name* is not unique
|
|
499
|
+
when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
|
|
500
|
+
RecordNotUnique.new(message)
|
|
501
|
+
else
|
|
502
|
+
super
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
private
|
|
507
|
+
COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
|
|
508
|
+
|
|
509
|
+
def table_structure_with_collation(table_name, basic_structure)
|
|
510
|
+
collation_hash = {}
|
|
511
|
+
sql = "SELECT sql FROM
|
|
512
|
+
(SELECT * FROM sqlite_master UNION ALL
|
|
513
|
+
SELECT * FROM sqlite_temp_master)
|
|
514
|
+
WHERE type='table' and name='#{ table_name }' \;"
|
|
515
|
+
|
|
516
|
+
# Result will have following sample string
|
|
517
|
+
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
518
|
+
# "password_digest" varchar COLLATE "NOCASE");
|
|
519
|
+
result = exec_query(sql, 'SCHEMA').first
|
|
520
|
+
|
|
521
|
+
if result
|
|
522
|
+
# Splitting with left parentheses and picking up last will return all
|
|
523
|
+
# columns separated with comma(,).
|
|
524
|
+
columns_string = result["sql"].split('(').last
|
|
525
|
+
|
|
526
|
+
columns_string.split(',').each do |column_string|
|
|
527
|
+
# This regex will match the column name and collation type and will save
|
|
528
|
+
# the value in $1 and $2 respectively.
|
|
529
|
+
collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string)
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
basic_structure.map! do |column|
|
|
533
|
+
column_name = column['name']
|
|
534
|
+
|
|
535
|
+
if collation_hash.has_key? column_name
|
|
536
|
+
column['collation'] = collation_hash[column_name]
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
column
|
|
540
|
+
end
|
|
292
541
|
else
|
|
293
|
-
|
|
542
|
+
basic_structure.to_hash
|
|
294
543
|
end
|
|
295
544
|
end
|
|
296
545
|
end
|
|
297
546
|
end
|
|
298
547
|
|
|
299
548
|
module ActiveRecord::ConnectionAdapters
|
|
300
|
-
remove_const(:SQLite3Adapter) if const_defined?(:SQLite3Adapter)
|
|
301
|
-
remove_const(:SQLiteAdapter) if const_defined?(:SQLiteAdapter)
|
|
302
|
-
|
|
303
549
|
class SQLite3Column < JdbcColumn
|
|
304
|
-
include ArJdbc::SQLite3::Column
|
|
305
|
-
|
|
306
550
|
def initialize(name, *args)
|
|
307
551
|
if Hash === name
|
|
308
552
|
super
|
|
@@ -311,49 +555,125 @@ module ActiveRecord::ConnectionAdapters
|
|
|
311
555
|
end
|
|
312
556
|
end
|
|
313
557
|
|
|
314
|
-
def call_discovered_column_callbacks(*)
|
|
315
|
-
end
|
|
316
|
-
|
|
317
558
|
def self.string_to_binary(value)
|
|
318
|
-
|
|
559
|
+
value
|
|
319
560
|
end
|
|
320
561
|
|
|
321
562
|
def self.binary_to_string(value)
|
|
322
|
-
if value.respond_to?(:
|
|
563
|
+
if value.respond_to?(:encoding) && value.encoding != Encoding::ASCII_8BIT
|
|
323
564
|
value = value.force_encoding(Encoding::ASCII_8BIT)
|
|
324
565
|
end
|
|
566
|
+
value
|
|
567
|
+
end
|
|
325
568
|
|
|
326
|
-
|
|
327
|
-
|
|
569
|
+
# @override {ActiveRecord::ConnectionAdapters::JdbcColumn#init_column}
|
|
570
|
+
def init_column(name, default, *args)
|
|
571
|
+
if default =~ /NULL/
|
|
572
|
+
@default = nil
|
|
328
573
|
else
|
|
329
|
-
|
|
574
|
+
super
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
# @override {ActiveRecord::ConnectionAdapters::JdbcColumn#default_value}
|
|
579
|
+
def default_value(value)
|
|
580
|
+
# JDBC returns column default strings with actual single quotes :
|
|
581
|
+
return $1 if value =~ /^'(.*)'$/
|
|
582
|
+
|
|
583
|
+
value
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
# @override {ActiveRecord::ConnectionAdapters::Column#type_cast}
|
|
587
|
+
def type_cast(value)
|
|
588
|
+
return nil if value.nil?
|
|
589
|
+
case type
|
|
590
|
+
when :string then value
|
|
591
|
+
when :primary_key
|
|
592
|
+
value.respond_to?(:to_i) ? value.to_i : ( value ? 1 : 0 )
|
|
593
|
+
when :float then value.to_f
|
|
594
|
+
when :decimal then self.class.value_to_decimal(value)
|
|
595
|
+
when :boolean then self.class.value_to_boolean(value)
|
|
596
|
+
else super
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
private
|
|
601
|
+
|
|
602
|
+
# @override {ActiveRecord::ConnectionAdapters::Column#simplified_type}
|
|
603
|
+
def simplified_type(field_type)
|
|
604
|
+
case field_type
|
|
605
|
+
when /boolean/i then :boolean
|
|
606
|
+
when /text/i then :text
|
|
607
|
+
when /varchar/i then :string
|
|
608
|
+
when /int/i then :integer
|
|
609
|
+
when /float/i then :float
|
|
610
|
+
when /real|decimal/i then
|
|
611
|
+
extract_scale(field_type) == 0 ? :integer : :decimal
|
|
612
|
+
when /datetime/i then :datetime
|
|
613
|
+
when /date/i then :date
|
|
614
|
+
when /time/i then :time
|
|
615
|
+
when /blob/i then :binary
|
|
616
|
+
else super
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
# @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
|
|
621
|
+
def extract_limit(sql_type)
|
|
622
|
+
return nil if sql_type =~ /^(real)\(\d+/i
|
|
623
|
+
super
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
def extract_precision(sql_type)
|
|
627
|
+
case sql_type
|
|
628
|
+
when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
|
|
629
|
+
else super
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
def extract_scale(sql_type)
|
|
634
|
+
case sql_type
|
|
635
|
+
when /^(real)\((\d+)\)/i then 0
|
|
636
|
+
when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
|
|
637
|
+
else super
|
|
330
638
|
end
|
|
331
639
|
end
|
|
332
640
|
end
|
|
333
641
|
|
|
334
|
-
|
|
642
|
+
remove_const(:SQLite3Adapter) if const_defined?(:SQLite3Adapter)
|
|
643
|
+
|
|
644
|
+
# Currently our adapter is named the same as what AR5 names its adapter. We will need to get
|
|
645
|
+
# this changed at some point so this can be a unique name and we can extend activerecord
|
|
646
|
+
# ActiveRecord::ConnectionAdapters::SQLite3Adapter. Once we can do that we can remove the
|
|
647
|
+
# module SQLite3 above and remove a majority of this file.
|
|
648
|
+
class SQLite3Adapter < AbstractAdapter
|
|
649
|
+
include ArJdbc::Abstract::Core
|
|
335
650
|
include ArJdbc::SQLite3
|
|
651
|
+
include ArJdbc::Abstract::DatabaseStatements
|
|
652
|
+
include ArJdbc::Abstract::StatementCache
|
|
653
|
+
include ArJdbc::Abstract::TransactionSupport
|
|
336
654
|
|
|
337
|
-
def
|
|
338
|
-
|
|
655
|
+
def begin_isolated_db_transaction(isolation)
|
|
656
|
+
raise ActiveRecord::TransactionIsolationError, 'adapter does not support setting transaction isolation'
|
|
339
657
|
end
|
|
340
658
|
|
|
341
|
-
|
|
342
|
-
|
|
659
|
+
# SQLite driver doesn't support all types of insert statements with executeUpdate so
|
|
660
|
+
# make it act like a regular query and the ids will be returned from #last_inserted_id
|
|
661
|
+
# example: INSERT INTO "aircraft" DEFAULT VALUES
|
|
662
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
|
663
|
+
exec_query(sql, name, binds)
|
|
343
664
|
end
|
|
344
665
|
|
|
345
666
|
def jdbc_column_class
|
|
346
|
-
ActiveRecord::ConnectionAdapters::SQLite3Column
|
|
667
|
+
::ActiveRecord::ConnectionAdapters::SQLite3Column
|
|
347
668
|
end
|
|
348
|
-
end
|
|
349
669
|
|
|
350
|
-
|
|
351
|
-
|
|
670
|
+
def jdbc_connection_class(spec)
|
|
671
|
+
self.class.jdbc_connection_class
|
|
672
|
+
end
|
|
352
673
|
|
|
353
|
-
#
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
VERSION = '1.2.6' # query_cache_test.rb requires SQLite3::Version::VERSION > '1.2.5'
|
|
674
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
|
675
|
+
def self.jdbc_connection_class
|
|
676
|
+
::ActiveRecord::ConnectionAdapters::SQLite3JdbcConnection
|
|
677
|
+
end
|
|
358
678
|
end
|
|
359
679
|
end
|