diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb | 103 |
1 files changed, 66 insertions, 37 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 7c809b088c..163cbb875f 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -33,7 +33,7 @@ module ActiveRecord ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config) rescue Errno::ENOENT => error if error.message.include?("No such file or directory") - raise ActiveRecord::NoDatabaseError.new(error.message, error) + raise ActiveRecord::NoDatabaseError else raise end @@ -65,18 +65,6 @@ module ActiveRecord boolean: { name: "boolean" } } - class Version - include Comparable - - def initialize(version_string) - @version = version_string.split('.').map(&:to_i) - end - - def <=>(version_string) - @version <=> version_string.split('.').map(&:to_i) - end - end - class StatementPool < ConnectionAdapters::StatementPool private @@ -90,18 +78,17 @@ module ActiveRecord end def initialize(connection, logger, connection_options, config) - super(connection, logger) + super(connection, logger, config) @active = nil - @statements = StatementPool.new(@connection, - self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 })) - @config = config + @statements = StatementPool.new(self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 })) @visitor = Arel::Visitors::SQLite.new self @quoted_column_names = {} if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true }) @prepared_statements = true + @visitor.extend(DetermineIfPreparableVisitor) else @prepared_statements = false end @@ -142,6 +129,10 @@ module ActiveRecord true end + def supports_datetime_with_precision? + true + end + def active? @active != false end @@ -231,7 +222,7 @@ module ActiveRecord end class ExplainPrettyPrinter - # Pretty prints the result of a EXPLAIN QUERY PLAN in a way that resembles + # Pretty prints the result of an EXPLAIN QUERY PLAN in a way that resembles # the output of the SQLite shell: # # 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows) @@ -244,15 +235,18 @@ module ActiveRecord end end - def exec_query(sql, name = nil, binds = []) + def exec_query(sql, name = nil, binds = [], prepare: false) type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } log(sql, name, binds) do # Don't cache statements if they are not prepared - if without_prepared_statement?(binds) + unless prepare stmt = @connection.prepare(sql) begin cols = stmt.columns + unless without_prepared_statement?(binds) + stmt.bind_params(type_casted_binds) + end records = stmt.to_a ensure stmt.close @@ -265,7 +259,7 @@ module ActiveRecord stmt = cache[:stmt] cols = cache[:cols] ||= stmt.columns stmt.reset! - stmt.bind_params type_casted_binds + stmt.bind_params(type_casted_binds) end ActiveRecord::Result.new(cols, stmt.to_a) @@ -320,21 +314,56 @@ module ActiveRecord # SCHEMA STATEMENTS ======================================== - def tables(name = nil, table_name = nil) #:nodoc: - sql = <<-SQL - SELECT name - FROM sqlite_master - WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence' - SQL - sql << " AND name = #{quote_table_name(table_name)}" if table_name - - exec_query(sql, 'SCHEMA').map do |row| - row['name'] + def tables(name = nil) # :nodoc: + ActiveSupport::Deprecation.warn(<<-MSG.squish) + #tables currently returns both tables and views. + This behavior is deprecated and will be changed with Rails 5.1 to only return tables. + Use #data_sources instead. + MSG + + if name + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Passing arguments to #tables is deprecated without replacement. + MSG end + + data_sources + end + + def data_sources + select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", 'SCHEMA') end def table_exists?(table_name) - table_name && tables(nil, table_name).any? + ActiveSupport::Deprecation.warn(<<-MSG.squish) + #table_exists? currently checks both tables and views. + This behavior is deprecated and will be changed with Rails 5.1 to only check tables. + Use #data_source_exists? instead. + MSG + + data_source_exists?(table_name) + end + + def data_source_exists?(table_name) + return false unless table_name.present? + + sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'" + sql << " AND name = #{quote(table_name)}" + + select_values(sql, 'SCHEMA').any? + end + + def views # :nodoc: + select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", 'SCHEMA') + end + + def view_exists?(view_name) # :nodoc: + return false unless view_name.present? + + sql = "SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'" + sql << " AND name = #{quote(view_name)}" + + select_values(sql, 'SCHEMA').any? end # Returns an array of +Column+ objects for the table specified by +table_name+. @@ -381,13 +410,13 @@ module ActiveRecord end end - def primary_key(table_name) #:nodoc: + def primary_keys(table_name) # :nodoc: pks = table_structure(table_name).select { |f| f['pk'] > 0 } - return nil unless pks.count == 1 - pks[0]['name'] + pks.sort_by { |f| f['pk'] }.map { |f| f['name'] } end - def remove_index!(table_name, index_name) #:nodoc: + def remove_index(table_name, options = {}) #:nodoc: + index_name = index_name_for_remove(table_name, options) exec_query "DROP INDEX #{quote_column_name(index_name)}" end @@ -557,7 +586,7 @@ module ActiveRecord # Older versions of SQLite return: # column *column_name* is not unique when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/ - RecordNotUnique.new(message, exception) + RecordNotUnique.new(message) else super end |