1 require 'arjdbc/jdbc/missing_functionality_helper'
3 module ActiveRecord::ConnectionAdapters
4 Sqlite3Adapter = Class.new(AbstractAdapter) unless const_defined?(:Sqlite3Adapter)
9 def self.column_selector
10 [/sqlite/i, lambda {|cfg,col| col.extend(::ArJdbc::SQLite3::Column)}]
13 def self.jdbc_connection_class
14 ::ActiveRecord::ConnectionAdapters::Sqlite3JdbcConnection
18 def init_column(name, default, *args)
19 @default = '' if default =~ /NULL/
23 return nil if value.nil?
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)
35 def simplified_type(field_type)
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|decimal/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
50 def extract_limit(sql_type)
51 return nil if sql_type =~ /^(real)\(\d+/i
55 def extract_precision(sql_type)
57 when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
62 def extract_scale(sql_type)
64 when /^(real)\((\d+)\)/i then 0
65 when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
70 # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
71 def default_value(value)
72 # jdbc returns column default strings with actual single quotes around the value.
73 return $1 if value =~ /^'(.*)'$/
79 def adapter_name #:nodoc:
84 {'jdbcsqlite3' => ::Arel::Visitors::SQLite}
87 def supports_ddl_transactions?
88 true # sqlite_version >= '2.0.0'
91 def supports_add_column?
92 sqlite_version >= '3.1.6'
95 def supports_count_distinct? #:nodoc:
96 sqlite_version >= '3.2.6'
99 def supports_autoincrement? #:nodoc:
100 sqlite_version >= '3.1.0'
104 @sqlite_version ||= select_value('select sqlite_version(*)')
108 tp[:primary_key] = "integer primary key autoincrement not null"
109 tp[:string] = { :name => "varchar", :limit => 255 }
110 tp[:text] = { :name => "text" }
111 tp[:float] = { :name => "float" }
112 tp[:decimal] = { :name => "decimal" }
113 tp[:datetime] = { :name => "datetime" }
114 tp[:timestamp] = { :name => "datetime" }
115 tp[:time] = { :name => "time" }
116 tp[:date] = { :name => "date" }
117 tp[:boolean] = { :name => "boolean" }
118 tp[:binary] = { :name => "blob" }
122 def quote_column_name(name) #:nodoc:
126 def quote_string(str)
138 # Quote date/time values for use in SQL input. Includes microseconds
139 # if the value is a Time responding to usec.
140 def quoted_date(value) #:nodoc:
141 if value.respond_to?(:usec)
142 "#{super}.#{sprintf("%06d", value.usec)}"
148 def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
149 @connection.execute_update(sql)
150 id_value || last_insert_id
154 Integer(select_value("SELECT last_insert_rowid()"))
157 def tables(name = nil) #:nodoc:
161 WHERE type = 'table' AND NOT name = 'sqlite_sequence'
164 select_rows(sql, name).map do |row|
169 def indexes(table_name, name = nil)
170 result = select_rows("SELECT name, sql FROM sqlite_master WHERE tbl_name = #{quote_table_name(table_name)} AND type = 'index'", name)
172 result.collect do |row|
175 unique = (index_sql =~ /unique/i)
176 cols = index_sql.match(/\((.*)\)/)[1].gsub(/,/,' ').split.map do |c|
177 match = /^"(.+)"$/.match(c); match ? match[1] : c
179 ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, cols)
183 def primary_key(table_name) #:nodoc:
184 column = table_structure(table_name).find {|field| field['pk'].to_i == 1}
185 column ? column['name'] : nil
188 def recreate_database(name)
189 tables.each{ |table| drop_table(table) }
192 def _execute(sql, name = nil)
194 ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql) ? last_insert_id : result
197 def select(sql, name=nil)
198 execute(sql, name).map do |row|
200 row.each_key do |key|
202 record[key.sub(/^"?\w+"?\./, '')] = row[key]
209 def table_structure(table_name)
210 structure = @connection.execute_query("PRAGMA table_info(#{quote_table_name(table_name)})")
211 raise ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'" if structure.empty?
215 def jdbc_columns(table_name, name = nil) #:nodoc:
216 table_structure(table_name).map do |field|
217 ::ActiveRecord::ConnectionAdapters::SQLite3Column.new(@config, field['name'], field['dflt_value'], field['type'], field['notnull'] == 0)
221 def primary_key(table_name) #:nodoc:
222 column = table_structure(table_name).find { |field|
223 field['pk'].to_i == 1
225 column && column['name']
228 def remove_index!(table_name, index_name) #:nodoc:
229 execute "DROP INDEX #{quote_column_name(index_name)}"
232 def rename_table(name, new_name)
233 execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
236 # See: http://www.sqlite.org/lang_altertable.html
237 # SQLite has an additional restriction on the ALTER TABLE statement
238 def valid_alter_table_options( type, options)
239 type.to_sym != :primary_key
242 def add_column(table_name, column_name, type, options = {}) #:nodoc:
243 if supports_add_column? && valid_alter_table_options( type, options )
244 super(table_name, column_name, type, options)
246 alter_table(table_name) do |definition|
247 definition.column(column_name, type, options)
252 def remove_column(table_name, *column_names) #:nodoc:
253 raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
254 column_names.flatten.each do |column_name|
255 alter_table(table_name) do |definition|
256 definition.columns.delete(definition[column_name])
260 alias :remove_columns :remove_column
262 def change_column_default(table_name, column_name, default) #:nodoc:
263 alter_table(table_name) do |definition|
264 definition[column_name].default = default
268 def change_column_null(table_name, column_name, null, default = nil)
269 unless null || default.nil?
270 execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
272 alter_table(table_name) do |definition|
273 definition[column_name].null = null
277 def change_column(table_name, column_name, type, options = {}) #:nodoc:
278 alter_table(table_name) do |definition|
279 include_default = options_include_default?(options)
280 definition[column_name].instance_eval do
282 self.limit = options[:limit] if options.include?(:limit)
283 self.default = options[:default] if include_default
284 self.null = options[:null] if options.include?(:null)
289 def rename_column(table_name, column_name, new_column_name) #:nodoc:
290 unless columns(table_name).detect{|c| c.name == column_name.to_s }
291 raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
293 alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
296 # SELECT ... FOR UPDATE is redundant since the table is locked.
297 def add_lock!(sql, options) #:nodoc:
301 def empty_insert_statement_value
306 include ArJdbc::MissingFunctionalityHelper
308 def translate_exception(exception, message)
309 case exception.message
310 when /column(s)? .* (is|are) not unique/
311 ActiveRecord::RecordNotUnique.new(message, exception)
319 module ActiveRecord::ConnectionAdapters
320 remove_const(:SQLite3Adapter) if const_defined?(:SQLite3Adapter)
321 remove_const(:SQLiteAdapter) if const_defined?(:SQLiteAdapter)
323 class SQLite3Column < JdbcColumn
324 include ArJdbc::SQLite3::Column
326 def initialize(name, *args)
330 super(nil, name, *args)
334 def call_discovered_column_callbacks(*)
337 def self.string_to_binary(value)
338 "\000b64" + [value].pack('m*').split("\n").join('')
341 def self.binary_to_string(value)
342 if value.respond_to?(:force_encoding) && value.encoding != Encoding::ASCII_8BIT
343 value = value.force_encoding(Encoding::ASCII_8BIT)
346 if value[0..3] == "\000b64"
347 value[4..-1].unpack('m*').first
354 class SQLite3Adapter < JdbcAdapter
355 include ArJdbc::SQLite3
357 def adapter_spec(config)
358 # return nil to avoid extending ArJdbc::SQLite3, which we've already done
361 def jdbc_connection_class(spec)
362 ::ArJdbc::SQLite3.jdbc_connection_class
365 def jdbc_column_class
366 ActiveRecord::ConnectionAdapters::SQLite3Column
369 alias_chained_method :columns, :query_cache, :jdbc_columns
372 SQLiteAdapter = SQLite3Adapter
375 # Fake out sqlite3/version driver for AR tests
376 $LOADED_FEATURES << 'sqlite3/version.rb'
379 VERSION = '1.2.6' # query_cache_test.rb requires SQLite3::Version::VERSION > '1.2.5'