Module: ArJdbc::SQLite3

Includes:
MissingFunctionalityHelper
Included in:
ActiveRecord::ConnectionAdapters::SQLite3Adapter
Defined in:
lib/arjdbc/sqlite3/adapter.rb,
lib/arjdbc/sqlite3/explain_support.rb

Defined Under Namespace

Modules: Column, ExplainSupport

Constant Summary collapse

ADAPTER_NAME =
'SQLite'
NATIVE_DATABASE_TYPES =
{
  :primary_key => nil,
  :string => { :name => "varchar", :limit => 255 },
  :text => { :name => "text" },
  :integer => { :name => "integer" },
  :float => { :name => "float" },
  :decimal => { :name => "decimal" },
  :datetime => { :name => "datetime" },
  :timestamp => { :name => "datetime" },
  :time => { :name => "time" },
  :date => { :name => "date" },
  :binary => { :name => "blob" },
  :boolean => { :name => "boolean" }
}
IndexDefinition =

:nodoc:

::ActiveRecord::ConnectionAdapters::IndexDefinition

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MissingFunctionalityHelper

#alter_table, #copy_table, #copy_table_contents, #copy_table_indexes, #move_table

Class Method Details

.arel2_visitors(config) ⇒ Object



89
90
91
92
93
94
# File 'lib/arjdbc/sqlite3/adapter.rb', line 89

def self.arel2_visitors(config)
  {
    'sqlite3' => ::Arel::Visitors::SQLite,
    'jdbcsqlite3' => ::Arel::Visitors::SQLite
  }
end

.column_selectorObject



7
8
9
# File 'lib/arjdbc/sqlite3/adapter.rb', line 7

def self.column_selector
  [ /sqlite/i, lambda { |cfg,col| col.extend(::ArJdbc::SQLite3::Column) } ]
end

.jdbc_connection_classObject



11
12
13
# File 'lib/arjdbc/sqlite3/adapter.rb', line 11

def self.jdbc_connection_class
  ::ActiveRecord::ConnectionAdapters::SQLite3JdbcConnection
end

Instance Method Details

#adapter_nameObject

:nodoc:



98
99
100
# File 'lib/arjdbc/sqlite3/adapter.rb', line 98

def adapter_name # :nodoc:
  ADAPTER_NAME
end

#add_column(table_name, column_name, type, options = {}) ⇒ Object

:nodoc:



296
297
298
299
300
301
302
303
304
# File 'lib/arjdbc/sqlite3/adapter.rb', line 296

def add_column(table_name, column_name, type, options = {}) #:nodoc:
  if supports_add_column? && valid_alter_table_options( type, options )
    super(table_name, column_name, type, options)
  else
    alter_table(table_name) do |definition|
      definition.column(column_name, type, options)
    end
  end
end

#add_lock!(sql, options) ⇒ Object

SELECT … FOR UPDATE is redundant since the table is locked.



358
359
360
# File 'lib/arjdbc/sqlite3/adapter.rb', line 358

def add_lock!(sql, options) #:nodoc:
  sql
end

#change_column(table_name, column_name, type, options = {}) ⇒ Object

:nodoc:



336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/arjdbc/sqlite3/adapter.rb', line 336

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)
    end
  end
end

#change_column_default(table_name, column_name, default) ⇒ Object

:nodoc:



321
322
323
324
325
# File 'lib/arjdbc/sqlite3/adapter.rb', line 321

def change_column_default(table_name, column_name, default) #:nodoc:
  alter_table(table_name) do |definition|
    definition[column_name].default = default
  end
end

#change_column_null(table_name, column_name, null, default = nil) ⇒ Object



327
328
329
330
331
332
333
334
# File 'lib/arjdbc/sqlite3/adapter.rb', line 327

def change_column_null(table_name, column_name, null, default = nil)
  unless null || default.nil?
    execute("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

#create_savepointObject



230
231
232
# File 'lib/arjdbc/sqlite3/adapter.rb', line 230

def create_savepoint
  execute("SAVEPOINT #{current_savepoint_name}")
end

#default_primary_key_typeObject



129
130
131
132
133
134
135
# File 'lib/arjdbc/sqlite3/adapter.rb', line 129

def default_primary_key_type
  if supports_autoincrement?
    'integer PRIMARY KEY AUTOINCREMENT NOT NULL'
  else
    'integer PRIMARY KEY NOT NULL'
  end
end

#empty_insert_statement_valueObject



362
363
364
# File 'lib/arjdbc/sqlite3/adapter.rb', line 362

def empty_insert_statement_value
  "VALUES(NULL)"
end

#indexes(table_name, name = nil) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/arjdbc/sqlite3/adapter.rb', line 216

def indexes(table_name, name = nil)
  result = select_rows("SELECT name, sql FROM sqlite_master" <<
  " WHERE tbl_name = #{quote_table_name(table_name)} AND type = 'index'", name)

  result.map do |row|
    name, index_sql = row[0], row[1]
    unique = !! (index_sql =~ /unique/i)
    columns = index_sql.match(/\((.*)\)/)[1].gsub(/,/,' ').split.map do |col|
      match = /^"(.+)"$/.match(col); match ? match[1] : col
    end
    IndexDefinition.new(table_name, name, unique, columns)
  end
end

#insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) ⇒ Object

NOTE: we have an extra binds argument at the end due 2.3 support.



194
195
196
197
# File 'lib/arjdbc/sqlite3/adapter.rb', line 194

def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) # :nodoc:
  execute(sql, name, binds)
  id_value || last_insert_id
end

#jdbc_columns(table_name, name = nil) ⇒ Object

:nodoc:



267
268
269
270
271
272
273
# File 'lib/arjdbc/sqlite3/adapter.rb', line 267

def jdbc_columns(table_name, name = nil) #:nodoc:
  table_structure(table_name).map do |field|
    ::ActiveRecord::ConnectionAdapters::SQLite3Column.new(
      @config, field['name'], field['dflt_value'], field['type'], field['notnull'] == 0
    )
  end
end

#modify_types(types) ⇒ Object



123
124
125
126
127
# File 'lib/arjdbc/sqlite3/adapter.rb', line 123

def modify_types(types)
  super(types)
  types.merge! NATIVE_DATABASE_TYPES
  types
end

#native_database_typesObject



117
118
119
120
121
# File 'lib/arjdbc/sqlite3/adapter.rb', line 117

def native_database_types
  types = super.merge(NATIVE_DATABASE_TYPES)
  types[:primary_key] = default_primary_key_type
  types
end

#primary_key(table_name) ⇒ Object

:nodoc:



275
276
277
278
279
280
# File 'lib/arjdbc/sqlite3/adapter.rb', line 275

def primary_key(table_name) #:nodoc:
  column = table_structure(table_name).find { |field|
    field['pk'].to_i == 1
  }
  column && column['name']
end

#quote(value, column = nil) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/arjdbc/sqlite3/adapter.rb', line 166

def quote(value, column = nil)
  if value.kind_of?(String)
    column_type = column && column.type
    if column_type == :binary && column.class.respond_to?(:string_to_binary)
      "x'#{column.class.string_to_binary(value).unpack("H*")[0]}'"
    else
      super
    end
  else
    super
  end
end

#quote_column_name(name) ⇒ Object

:nodoc:



179
180
181
# File 'lib/arjdbc/sqlite3/adapter.rb', line 179

def quote_column_name(name) # :nodoc:
  %Q("#{name.to_s.gsub('"', '""')}") # "' kludge for emacs font-lock
end

#quoted_date(value) ⇒ Object

Quote date/time values for use in SQL input. Includes microseconds if the value is a Time responding to usec.



185
186
187
188
189
190
191
# File 'lib/arjdbc/sqlite3/adapter.rb', line 185

def quoted_date(value) # :nodoc:
  if value.respond_to?(:usec)
    "#{super}.#{sprintf("%06d", value.usec)}"
  else
    super
  end
end

#recreate_database(name, options = {}) ⇒ Object



242
243
244
# File 'lib/arjdbc/sqlite3/adapter.rb', line 242

def recreate_database(name, options = {})
  tables.each { |table| drop_table(table) }
end

#release_savepointObject



238
239
240
# File 'lib/arjdbc/sqlite3/adapter.rb', line 238

def release_savepoint
  execute("RELEASE SAVEPOINT #{current_savepoint_name}")
end

#remove_column(table_name, *column_names) ⇒ Object Also known as: remove_columns

:nodoc:



306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/arjdbc/sqlite3/adapter.rb', line 306

def remove_column(table_name, *column_names) #:nodoc:
  if column_names.empty?
    raise ArgumentError.new(
      "You must specify at least one column name." + 
      "  Example: remove_column(:people, :first_name)"
    )
  end
  column_names.flatten.each do |column_name|
    alter_table(table_name) do |definition|
      definition.columns.delete(definition[column_name])
    end
  end
end

#remove_index!(table_name, index_name) ⇒ Object

:nodoc:



282
283
284
# File 'lib/arjdbc/sqlite3/adapter.rb', line 282

def remove_index!(table_name, index_name) #:nodoc:
  execute "DROP INDEX #{quote_column_name(index_name)}"
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:



350
351
352
353
354
355
# File 'lib/arjdbc/sqlite3/adapter.rb', line 350

def rename_column(table_name, column_name, new_column_name) #:nodoc:
  unless columns(table_name).detect{|c| c.name == column_name.to_s }
    raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
  end
  alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
end

#rename_table(name, new_name) ⇒ Object



286
287
288
# File 'lib/arjdbc/sqlite3/adapter.rb', line 286

def rename_table(name, new_name)
  execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
end

#rollback_to_savepointObject



234
235
236
# File 'lib/arjdbc/sqlite3/adapter.rb', line 234

def rollback_to_savepoint
  execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
end

#select(sql, name = nil, binds = []) ⇒ Object



246
247
248
249
250
251
252
253
254
255
256
# File 'lib/arjdbc/sqlite3/adapter.rb', line 246

def select(sql, name = nil, binds = [])
  execute(sql, name, binds).map do |row|
    record = {}
    row.each_key do |key|
      if key.is_a?(String)
        record[key.sub(/^"?\w+"?\./, '')] = row[key]
      end
    end
    record
  end
end

#supports_add_column?Boolean

:nodoc:

Returns:

  • (Boolean)


145
146
147
# File 'lib/arjdbc/sqlite3/adapter.rb', line 145

def supports_add_column? # :nodoc:
  sqlite_version >= '3.1.6'
end

#supports_autoincrement?Boolean

:nodoc:

Returns:

  • (Boolean)


153
154
155
# File 'lib/arjdbc/sqlite3/adapter.rb', line 153

def supports_autoincrement? # :nodoc:
  sqlite_version >= '3.1.0'
end

#supports_count_distinct?Boolean

:nodoc:

Returns:

  • (Boolean)


149
150
151
# File 'lib/arjdbc/sqlite3/adapter.rb', line 149

def supports_count_distinct? # :nodoc:
  sqlite_version >= '3.2.6'
end

#supports_ddl_transactions?Boolean

:nodoc:

Returns:

  • (Boolean)


137
138
139
# File 'lib/arjdbc/sqlite3/adapter.rb', line 137

def supports_ddl_transactions? # :nodoc:
  true # sqlite_version >= '2.0.0'
end

#supports_index_sort_order?Boolean

:nodoc:

Returns:

  • (Boolean)


157
158
159
# File 'lib/arjdbc/sqlite3/adapter.rb', line 157

def supports_index_sort_order? # :nodoc:
  sqlite_version >= '3.3.0'
end

#supports_savepoints?Boolean

:nodoc:

Returns:

  • (Boolean)


141
142
143
# File 'lib/arjdbc/sqlite3/adapter.rb', line 141

def supports_savepoints? # :nodoc:
  sqlite_version >= '3.6.8'
end

#table_exists?(table_name) ⇒ Boolean

Returns:

  • (Boolean)


210
211
212
# File 'lib/arjdbc/sqlite3/adapter.rb', line 210

def table_exists?(table_name)
  table_name && tables(nil, table_name).any?
end

#table_structure(table_name) ⇒ Object



258
259
260
261
262
263
264
265
# File 'lib/arjdbc/sqlite3/adapter.rb', line 258

def table_structure(table_name)
  sql = "PRAGMA table_info(#{quote_table_name(table_name)})"
  log(sql, 'SCHEMA') { @connection.execute_query(sql) }
rescue ActiveRecord::JDBCError => error
  e = ActiveRecord::StatementInvalid.new("Could not find table '#{table_name}'")
  e.set_backtrace error.backtrace
  raise e
end

#tables(name = nil, table_name = nil) ⇒ Object

:nodoc:



199
200
201
202
203
204
205
206
207
208
# File 'lib/arjdbc/sqlite3/adapter.rb', line 199

def tables(name = nil, table_name = nil) # :nodoc:
  sql = "SELECT name FROM sqlite_master WHERE type = 'table'"
  if table_name
    sql << " AND name = #{quote_table_name(table_name)}"
  else
    sql << " AND NOT name = 'sqlite_sequence'"
  end

  select_rows(sql, name).map { |row| row[0] }
end

#valid_alter_table_options(type, options) ⇒ Object

See: www.sqlite.org/lang_altertable.html SQLite has an additional restriction on the ALTER TABLE statement



292
293
294
# File 'lib/arjdbc/sqlite3/adapter.rb', line 292

def valid_alter_table_options( type, options)
  type.to_sym != :primary_key
end