sqlite3_adapter.rb 20.6 KB
Newer Older
1 2
require 'active_record/connection_adapters/abstract_adapter'
require 'active_record/connection_adapters/statement_pool'
3
require 'active_record/connection_adapters/sqlite3/schema_creation'
4

5
gem 'sqlite3', '~> 1.3.6'
6
require 'sqlite3'
7 8

module ActiveRecord
9
  module ConnectionHandling # :nodoc:
10
    # sqlite3 adapter reuses sqlite_connection.
11
    def sqlite3_connection(config)
12 13 14 15 16
      # Require database.
      unless config[:database]
        raise ArgumentError, "No database file specified. Missing argument: database"
      end

17 18 19
      # Allow database path relative to Rails.root, but only if the database
      # path is not the special path that tells sqlite to build a database only
      # in memory.
20
      if ':memory:' != config[:database]
21 22 23
        config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
        dirname = File.dirname(config[:database])
        Dir.mkdir(dirname) unless File.directory?(dirname)
24
      end
25 26

      db = SQLite3::Database.new(
27
        config[:database].to_s,
28
        :results_as_hash => true
29 30
      )

31
      db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
32

33
      ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
34 35
    rescue Errno::ENOENT => error
      if error.message.include?("No such file or directory")
36
        raise ActiveRecord::NoDatabaseError
37
      else
38
        raise
39
      end
40 41 42 43
    end
  end

  module ConnectionAdapters #:nodoc:
A
Andrey Deryabin 已提交
44 45
    # The SQLite3 adapter works SQLite 3.6.16 or newer
    # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
46 47 48 49 50
    #
    # Options:
    #
    # * <tt>:database</tt> - Path to the database file.
    class SQLite3Adapter < AbstractAdapter
51
      ADAPTER_NAME = 'SQLite'.freeze
52 53
      include Savepoints

54 55
      NATIVE_DATABASE_TYPES = {
        primary_key:  'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL',
56
        string:       { name: "varchar" },
57 58 59 60 61 62 63 64 65 66 67
        text:         { name: "text" },
        integer:      { name: "integer" },
        float:        { name: "float" },
        decimal:      { name: "decimal" },
        datetime:     { name: "datetime" },
        time:         { name: "time" },
        date:         { name: "date" },
        binary:       { name: "blob" },
        boolean:      { name: "boolean" }
      }

68 69 70 71
      class StatementPool < ConnectionAdapters::StatementPool
        private

        def dealloc(stmt)
72
          stmt[:stmt].close unless stmt[:stmt].closed?
73 74
        end
      end
75

76 77 78 79
      def schema_creation # :nodoc:
        SQLite3::SchemaCreation.new self
      end

80
      def initialize(connection, logger, connection_options, config)
81
        super(connection, logger, config)
82 83

        @active     = nil
84
        @statements = StatementPool.new(self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
85

86
        @visitor = Arel::Visitors::SQLite.new self
87
        @quoted_column_names = {}
88

89
        if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
90
          @prepared_statements = true
91
          @visitor.extend(DetermineIfPreparableVisitor)
92
        else
93 94 95 96
          @prepared_statements = false
        end
      end

97
      def supports_ddl_transactions?
98
        true
99 100 101
      end

      def supports_savepoints?
102
        true
103 104
      end

105 106 107 108
      def supports_partial_index?
        sqlite_version >= '3.8.0'
      end

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
      # Returns true, since this connection adapter supports prepared statement
      # caching.
      def supports_statement_cache?
        true
      end

      # Returns true, since this connection adapter supports migrations.
      def supports_migrations? #:nodoc:
        true
      end

      def supports_primary_key? #:nodoc:
        true
      end

      def requires_reloading?
        true
      end

128 129 130 131
      def supports_views?
        true
      end

132 133 134 135
      def supports_datetime_with_precision?
        true
      end

136 137 138 139
      def active?
        @active != false
      end

140 141 142 143
      # Disconnects from the database if already connected. Otherwise, this
      # method does nothing.
      def disconnect!
        super
144
        @active = false
145 146 147 148 149 150 151 152 153
        @connection.close rescue nil
      end

      # Clears the prepared statements cache.
      def clear_cache!
        @statements.clear
      end

      def supports_index_sort_order?
154
        true
155 156
      end

157
      # Returns 62. SQLite supports index names up to 64
158 159 160
      # characters. The rest is used by rails internally to perform
      # temporary rename operations
      def allowed_index_name_length
161
        index_name_length - 2
162 163
      end

164
      def native_database_types #:nodoc:
165
        NATIVE_DATABASE_TYPES
166 167
      end

168 169
      # Returns the current database encoding format as a string, eg: 'UTF-8'
      def encoding
170
        @connection.encoding.to_s
171 172
      end

A
Andrey Deryabin 已提交
173 174 175 176
      def supports_explain?
        true
      end

177 178
      # QUOTING ==================================================

179
      def _quote(value) # :nodoc:
180 181
        case value
        when Type::Binary::Data
182
          "x'#{value.hex}'"
183 184 185 186 187
        else
          super
        end
      end

188 189 190 191
      def _type_cast(value) # :nodoc:
        case value
        when BigDecimal
          value.to_f
192 193 194 195 196 197
        when String
          if value.encoding == Encoding::ASCII_8BIT
            super(value.encode(Encoding::UTF_8))
          else
            super
          end
198 199 200 201 202
        else
          super
        end
      end

203 204 205 206
      def quote_string(s) #:nodoc:
        @connection.class.quote(s)
      end

207 208 209 210
      def quote_table_name_for_assignment(table, attr)
        quote_column_name(attr)
      end

211
      def quote_column_name(name) #:nodoc:
212
        @quoted_column_names[name] ||= %Q("#{name.to_s.gsub('"', '""')}")
213 214
      end

215
      #--
A
Andrey Deryabin 已提交
216
      # DATABASE STATEMENTS ======================================
217
      #++
A
Andrey Deryabin 已提交
218 219 220

      def explain(arel, binds = [])
        sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
221
        ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
A
Andrey Deryabin 已提交
222 223 224
      end

      class ExplainPrettyPrinter
225
        # Pretty prints the result of an EXPLAIN QUERY PLAN in a way that resembles
A
Andrey Deryabin 已提交
226 227 228 229 230 231 232 233 234 235 236
        # the output of the SQLite shell:
        #
        #   0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
        #   0|1|1|SCAN TABLE posts (~100000 rows)
        #
        def pp(result) # :nodoc:
          result.rows.map do |row|
            row.join('|')
          end.join("\n") + "\n"
        end
      end
237

238
      def exec_query(sql, name = nil, binds = [], prepare: false)
S
Sean Griffin 已提交
239
        type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
240

S
Sean Griffin 已提交
241
        log(sql, name, binds) do
242
          # Don't cache statements if they are not prepared
243
          unless prepare
244
            stmt    = @connection.prepare(sql)
245 246
            begin
              cols    = stmt.columns
247 248 249
              unless without_prepared_statement?(binds)
                stmt.bind_params(type_casted_binds)
              end
250 251 252 253
              records = stmt.to_a
            ensure
              stmt.close
            end
254 255 256 257 258 259 260 261
            stmt = records
          else
            cache = @statements[sql] ||= {
              :stmt => @connection.prepare(sql)
            }
            stmt = cache[:stmt]
            cols = cache[:cols] ||= stmt.columns
            stmt.reset!
262
            stmt.bind_params(type_casted_binds)
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
          end

          ActiveRecord::Result.new(cols, stmt.to_a)
        end
      end

      def exec_delete(sql, name = 'SQL', binds = [])
        exec_query(sql, name, binds)
        @connection.changes
      end
      alias :exec_update :exec_delete

      def last_inserted_id(result)
        @connection.last_insert_row_id
      end

      def execute(sql, name = nil) #:nodoc:
        log(sql, name) { @connection.execute(sql) }
      end

      def update_sql(sql, name = nil) #:nodoc:
        super
        @connection.changes
      end

      def delete_sql(sql, name = nil) #:nodoc:
        sql += " WHERE 1=1" unless sql =~ /WHERE/i
        super sql, name
      end

      def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
        super
        id_value || @connection.last_insert_row_id
      end

298 299
      def select_rows(sql, name = nil, binds = [])
        exec_query(sql, name, binds).rows
300 301 302 303 304 305 306 307 308 309
      end

      def begin_db_transaction #:nodoc:
        log('begin transaction',nil) { @connection.transaction }
      end

      def commit_db_transaction #:nodoc:
        log('commit transaction',nil) { @connection.commit }
      end

310
      def exec_rollback_db_transaction #:nodoc:
311 312 313 314 315
        log('rollback transaction',nil) { @connection.rollback }
      end

      # SCHEMA STATEMENTS ========================================

R
Ryuta Kamizono 已提交
316
      def tables(name = nil) # :nodoc:
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
        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
R
Ryuta Kamizono 已提交
333
        select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", 'SCHEMA')
334 335
      end

K
kennyj 已提交
336
      def table_exists?(table_name)
337 338 339 340 341 342 343 344 345 346
        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)
R
Ryuta Kamizono 已提交
347 348 349 350 351 352
        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?
353 354
      end

355 356 357 358 359 360 361 362 363 364 365 366 367
      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

368
      # Returns an array of +Column+ objects for the table specified by +table_name+.
369 370 371 372 373
      def columns(table_name) #:nodoc:
        table_structure(table_name).map do |field|
          case field["dflt_value"]
          when /^null$/i
            field["dflt_value"] = nil
374
          when /^'(.*)'$/m
375
            field["dflt_value"] = $1.gsub("''", "'")
376
          when /^"(.*)"$/m
377 378 379
            field["dflt_value"] = $1.gsub('""', '"')
          end

380
          collation = field['collation']
381
          sql_type = field['type']
S
Sean Griffin 已提交
382
          type_metadata = fetch_type_metadata(sql_type)
383
          new_column(field['name'], field['dflt_value'], type_metadata, field['notnull'].to_i == 0, nil, collation)
384 385 386 387 388
        end
      end

      # Returns an array of indexes for the given table.
      def indexes(table_name, name = nil) #:nodoc:
K
kennyj 已提交
389
        exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row|
390 391 392 393 394 395 396 397 398 399 400 401
          sql = <<-SQL
            SELECT sql
            FROM sqlite_master
            WHERE name=#{quote(row['name'])} AND type='index'
            UNION ALL
            SELECT sql
            FROM sqlite_temp_master
            WHERE name=#{quote(row['name'])} AND type='index'
          SQL
          index_sql = exec_query(sql).first['sql']
          match = /\sWHERE\s+(.+)$/i.match(index_sql)
          where = match[1] if match
402 403 404 405
          IndexDefinition.new(
            table_name,
            row['name'],
            row['unique'] != 0,
406
            exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
407
              col['name']
408
            }, nil, nil, where)
409 410 411
        end
      end

412
      def primary_keys(table_name) # :nodoc:
413
        pks = table_structure(table_name).select { |f| f['pk'] > 0 }
414
        pks.sort_by { |f| f['pk'] }.map { |f| f['name'] }
415 416
      end

417 418
      def remove_index(table_name, options = {}) #:nodoc:
        index_name = index_name_for_remove(table_name, options)
419 420 421 422 423 424 425
        exec_query "DROP INDEX #{quote_column_name(index_name)}"
      end

      # Renames a table.
      #
      # Example:
      #   rename_table('octopuses', 'octopi')
426 427 428
      def rename_table(table_name, new_name)
        exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
        rename_table_indexes(table_name, new_name)
429 430 431 432
      end

      # See: http://www.sqlite.org/lang_altertable.html
      # SQLite has an additional restriction on the ALTER TABLE statement
433
      def valid_alter_table_type?(type)
434 435 436 437
        type.to_sym != :primary_key
      end

      def add_column(table_name, column_name, type, options = {}) #:nodoc:
438
        if valid_alter_table_type?(type)
439 440 441 442 443 444 445 446
          super(table_name, column_name, type, options)
        else
          alter_table(table_name) do |definition|
            definition.column(column_name, type, options)
          end
        end
      end

447 448
      def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
        alter_table(table_name) do |definition|
449
          definition.remove_column column_name
450 451 452
        end
      end

453 454 455
      def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
        default = extract_new_default_value(default_or_changes)

456 457 458 459 460
        alter_table(table_name) do |definition|
          definition[column_name].default = default
        end
      end

461
      def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
        unless null || default.nil?
          exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
        end
        alter_table(table_name) do |definition|
          definition[column_name].null = null
        end
      end

      def change_column(table_name, column_name, type, options = {}) #:nodoc:
        alter_table(table_name) do |definition|
          include_default = options_include_default?(options)
          definition[column_name].instance_eval do
            self.type    = type
            self.limit   = options[:limit] if options.include?(:limit)
            self.default = options[:default] if include_default
            self.null    = options[:null] if options.include?(:null)
            self.precision = options[:precision] if options.include?(:precision)
            self.scale   = options[:scale] if options.include?(:scale)
480
            self.collation = options[:collation] if options.include?(:collation)
481 482 483 484 485
          end
        end
      end

      def rename_column(table_name, column_name, new_column_name) #:nodoc:
486 487 488
        column = column_for(table_name, column_name)
        alter_table(table_name, rename: {column.name => new_column_name.to_s})
        rename_column_indexes(table_name, column.name, new_column_name)
489 490 491
      end

      protected
492

493
        def table_structure(table_name)
494
          structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA')
495
          raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
496
          table_structure_with_collation(table_name, structure)
497 498 499
        end

        def alter_table(table_name, options = {}) #:nodoc:
500
          altered_table_name = "a#{table_name}"
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
          caller = lambda {|definition| yield definition if block_given?}

          transaction do
            move_table(table_name, altered_table_name,
              options.merge(:temporary => true))
            move_table(altered_table_name, table_name, &caller)
          end
        end

        def move_table(from, to, options = {}, &block) #:nodoc:
          copy_table(from, to, options, &block)
          drop_table(from)
        end

        def copy_table(from, to, options = {}) #:nodoc:
516
          from_primary_key = primary_key(from)
517
          options[:id] = false
518 519
          create_table(to, options) do |definition|
            @definition = definition
520
            @definition.primary_key(from_primary_key) if from_primary_key.present?
521 522 523 524 525
            columns(from).each do |column|
              column_name = options[:rename] ?
                (options[:rename][column.name] ||
                 options[:rename][column.name.to_sym] ||
                 column.name) : column.name
526
              next if column_name == from_primary_key
527 528 529 530

              @definition.column(column_name, column.type,
                :limit => column.limit, :default => column.default,
                :precision => column.precision, :scale => column.scale,
531
                :null => column.null, collation: column.collation)
532 533 534 535 536
            end
            yield @definition if block_given?
          end
          copy_table_indexes(from, to, options[:rename] || {})
          copy_table_contents(from, to,
537
            @definition.columns.map(&:name),
538 539 540 541 542 543
            options[:rename] || {})
        end

        def copy_table_indexes(from, to, rename = {}) #:nodoc:
          indexes(from).each do |index|
            name = index.name
544 545 546 547
            if to == "a#{from}"
              name = "t#{name}"
            elsif from == "a#{to}"
              name = name[1..-1]
548 549
            end

550
            to_column_names = columns(to).map(&:name)
551 552 553 554 555 556
            columns = index.columns.map {|c| rename[c] || c }.select do |column|
              to_column_names.include?(column)
            end

            unless columns.empty?
              # index name can't be the same
557
              opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
558 559 560 561 562 563 564 565 566
              opts[:unique] = true if index.unique
              add_index(to, columns, opts)
            end
          end
        end

        def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
          column_mappings = Hash[columns.map {|name| [name, name]}]
          rename.each { |a| column_mappings[a.last] = a.first }
567
          from_columns = columns(from).collect(&:name)
568
          columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
569
          from_columns_to_copy = columns.map { |col| column_mappings[col] }
570
          quoted_columns = columns.map { |col| quote_column_name(col) } * ','
571
          quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ','
572

573 574
          exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
                     SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
575 576 577 578 579 580 581 582
        end

        def sqlite_version
          @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)'))
        end

        def translate_exception(exception, message)
          case exception.message
583 584 585 586 587
          # SQLite 3.8.2 returns a newly formatted error message:
          #   UNIQUE constraint failed: *table_name*.*column_name*
          # Older versions of SQLite return:
          #   column *column_name* is not unique
          when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
588
            RecordNotUnique.new(message)
589 590 591 592
          else
            super
          end
        end
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632

      private
        COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze

        def table_structure_with_collation(table_name, basic_structure)
          collation_hash = {}
          sql            = "SELECT sql FROM
                              (SELECT * FROM sqlite_master UNION ALL
                               SELECT * FROM sqlite_temp_master)
                            WHERE type='table' and name='#{ table_name }' \;"

          # Result will have following sample string
          # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
          #                       "password_digest" varchar COLLATE "NOCASE");
          result = exec_query(sql, 'SCHEMA').first

          if result
            # Splitting with left parantheses and picking up last will return all
            # columns separated with comma(,).
            columns_string = result["sql"].split('(').last

            columns_string.split(',').each do |column_string|
              # This regex will match the column name and collation type and will save
              # the value in $1 and $2 respectively.
              collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string)
            end

            basic_structure.map! do |column|
              column_name = column['name']

              if collation_hash.has_key? column_name
                column['collation'] = collation_hash[column_name]
              end

              column
            end
          else
            basic_structure.to_hash
          end
        end
633 634 635
    end
  end
end