No matter how you connect to SQLite, the following Database options can be used to set PRAGMAs on connections in a thread-safe manner: :auto_vacuum, :foreign_keys, :synchronous, and :temp_store.
Override the default setting for whether to use timezones in timestamps. For backwards compatibility, it is set to true by default. Anyone wanting to use SQLite’s datetime functions should set it to false using this method. It’s possible that the default will change in a future version, so anyone relying on timezones in timestamps should set this to true.
A symbol signifying the value of the auto_vacuum PRAGMA.
# File lib/sequel/adapters/shared/sqlite.rb, line 19 19: def auto_vacuum 20: AUTO_VACUUM[pragma_get(:auto_vacuum).to_i] 21: end
Set the auto_vacuum PRAGMA using the given symbol (:none, :full, or :incremental). See pragma_set. Consider using the :auto_vacuum Database option instead.
# File lib/sequel/adapters/shared/sqlite.rb, line 26 26: def auto_vacuum=(value) 27: value = AUTO_VACUUM.index(value) || (raise Error, "Invalid value for auto_vacuum option. Please specify one of :none, :full, :incremental.") 28: pragma_set(:auto_vacuum, value) 29: end
Set the case_sensitive_like PRAGMA using the given boolean value, if using SQLite 3.2.3+. If not using 3.2.3+, no error is raised. See pragma_set. Consider using the :case_sensitive_like Database option instead.
# File lib/sequel/adapters/shared/sqlite.rb, line 34 34: def case_sensitive_like=(value) 35: pragma_set(:case_sensitive_like, !!value ? 'on' : 'off') if sqlite_version >= 30203 36: end
SQLite uses the :sqlite database type.
# File lib/sequel/adapters/shared/sqlite.rb, line 39 39: def database_type 40: :sqlite 41: end
Return the array of foreign key info hashes using the foreign_key_list PRAGMA, including information for the :on_update and :on_delete entries.
# File lib/sequel/adapters/shared/sqlite.rb, line 58 58: def foreign_key_list(table, opts={}) 59: m = output_identifier_meth 60: h = {} 61: metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table)).each do |row| 62: if r = h[row[:id]] 63: r[:columns] << m.call(row[:from]) 64: r[:key] << m.call(row[:to]) if r[:key] 65: else 66: h[row[:id]] = {:columns=>[m.call(row[:from])], :table=>m.call(row[:table]), :key=>([m.call(row[:to])] if row[:to]), :on_update=>on_delete_sql_to_sym(row[:on_update]), :on_delete=>on_delete_sql_to_sym(row[:on_delete])} 67: end 68: end 69: h.values 70: end
Boolean signifying the value of the foreign_keys PRAGMA, or nil if not using SQLite 3.6.19+.
# File lib/sequel/adapters/shared/sqlite.rb, line 45 45: def foreign_keys 46: pragma_get(:foreign_keys).to_i == 1 if sqlite_version >= 30619 47: end
Set the foreign_keys PRAGMA using the given boolean value, if using SQLite 3.6.19+. If not using 3.6.19+, no error is raised. See pragma_set. Consider using the :foreign_keys Database option instead.
# File lib/sequel/adapters/shared/sqlite.rb, line 52 52: def foreign_keys=(value) 53: pragma_set(:foreign_keys, !!value ? 'on' : 'off') if sqlite_version >= 30619 54: end
Use the index_list and index_info PRAGMAs to determine the indexes on the table.
# File lib/sequel/adapters/shared/sqlite.rb, line 73 73: def indexes(table, opts={}) 74: m = output_identifier_meth 75: im = input_identifier_meth 76: indexes = {} 77: metadata_dataset.with_sql("PRAGMA index_list(?)", im.call(table)).each do |r| 78: next if r[:name] =~ PRIMARY_KEY_INDEX_RE 79: indexes[m.call(r[:name])] = {:unique=>r[:unique].to_i==1} 80: end 81: indexes.each do |k, v| 82: v[:columns] = metadata_dataset.with_sql("PRAGMA index_info(?)", im.call(k)).map(:name).map{|x| m.call(x)} 83: end 84: indexes 85: end
Get the value of the given PRAGMA.
# File lib/sequel/adapters/shared/sqlite.rb, line 88 88: def pragma_get(name) 89: self["PRAGMA #{name}"].single_value 90: end
Set the value of the given PRAGMA to value.
This method is not thread safe, and will not work correctly if there are multiple connections in the Database’s connection pool. PRAGMA modifications should be done when the connection is created, using an option provided when creating the Database object.
# File lib/sequel/adapters/shared/sqlite.rb, line 98 98: def pragma_set(name, value) 99: execute_ddl("PRAGMA #{name} = #{value}") 100: end
Set the integer_booleans option using the passed in :integer_boolean option.
# File lib/sequel/adapters/shared/sqlite.rb, line 103 103: def set_integer_booleans 104: @integer_booleans = typecast_value_boolean(@opts[:integer_booleans]) 105: end
The version of the server as an integer, where 3.6.19 = 30619. If the server version can’t be determined, 0 is used.
# File lib/sequel/adapters/shared/sqlite.rb, line 109 109: def sqlite_version 110: return @sqlite_version if defined?(@sqlite_version) 111: @sqlite_version = begin 112: v = get{sqlite_version{}} 113: [10000, 100, 1].zip(v.split('.')).inject(0){|a, m| a + m[0] * Integer(m[1])} 114: rescue 115: 0 116: end 117: end
SQLite supports CREATE TABLE IF NOT EXISTS syntax since 3.3.0.
# File lib/sequel/adapters/shared/sqlite.rb, line 120 120: def supports_create_table_if_not_exists? 121: sqlite_version >= 30300 122: end
SQLite 3.6.8+ supports savepoints.
# File lib/sequel/adapters/shared/sqlite.rb, line 125 125: def supports_savepoints? 126: sqlite_version >= 30608 127: end
A symbol signifying the value of the synchronous PRAGMA.
# File lib/sequel/adapters/shared/sqlite.rb, line 143 143: def synchronous 144: SYNCHRONOUS[pragma_get(:synchronous).to_i] 145: end
Set the synchronous PRAGMA using the given symbol (:off, :normal, or :full). See pragma_set. Consider using the :synchronous Database option instead.
# File lib/sequel/adapters/shared/sqlite.rb, line 149 149: def synchronous=(value) 150: value = SYNCHRONOUS.index(value) || (raise Error, "Invalid value for synchronous option. Please specify one of :off, :normal, :full.") 151: pragma_set(:synchronous, value) 152: end
Array of symbols specifying the table names in the current database.
Options:
:server - Set the server to use.
# File lib/sequel/adapters/shared/sqlite.rb, line 158 158: def tables(opts={}) 159: tables_and_views(TABLES_FILTER, opts) 160: end
A symbol signifying the value of the temp_store PRAGMA.
# File lib/sequel/adapters/shared/sqlite.rb, line 163 163: def temp_store 164: TEMP_STORE[pragma_get(:temp_store).to_i] 165: end
Set the temp_store PRAGMA using the given symbol (:default, :file, or :memory). See pragma_set. Consider using the :temp_store Database option instead.
# File lib/sequel/adapters/shared/sqlite.rb, line 169 169: def temp_store=(value) 170: value = TEMP_STORE.index(value) || (raise Error, "Invalid value for temp_store option. Please specify one of :default, :file, :memory.") 171: pragma_set(:temp_store, value) 172: end
SQLite supports timezones in timestamps, since it just stores them as strings, but it breaks the usage of SQLite’s datetime functions.
# File lib/sequel/adapters/shared/sqlite.rb, line 138 138: def use_timestamp_timezones? 139: defined?(@use_timestamp_timezones) ? @use_timestamp_timezones : (@use_timestamp_timezones = true) 140: end
Array of symbols specifying the view names in the current database.
Options:
:server - Set the server to use.
# File lib/sequel/adapters/shared/sqlite.rb, line 178 178: def views(opts={}) 179: tables_and_views(VIEWS_FILTER, opts) 180: end
SQLite supports limited table modification. You can add a column or an index. Dropping columns is supported by copying the table into a temporary table, dropping the table, and creating a new table without the column inside of a transaction.
# File lib/sequel/adapters/shared/sqlite.rb, line 207 207: def alter_table_sql(table, op) 208: case op[:op] 209: when :add_index, :drop_index 210: super 211: when :add_column 212: if op[:unique] || op[:primary_key] 213: duplicate_table(table){|columns| columns.push(op)} 214: else 215: super 216: end 217: when :drop_column 218: ocp = lambda{|oc| oc.delete_if{|c| c.to_s == op[:name].to_s}} 219: duplicate_table(table, :old_columns_proc=>ocp){|columns| columns.delete_if{|s| s[:name].to_s == op[:name].to_s}} 220: when :rename_column 221: ncp = lambda{|nc| nc.map!{|c| c.to_s == op[:name].to_s ? op[:new_name] : c}} 222: duplicate_table(table, :new_columns_proc=>ncp){|columns| columns.each{|s| s[:name] = op[:new_name] if s[:name].to_s == op[:name].to_s}} 223: when :set_column_default 224: duplicate_table(table){|columns| columns.each{|s| s[:default] = op[:default] if s[:name].to_s == op[:name].to_s}} 225: when :set_column_null 226: duplicate_table(table){|columns| columns.each{|s| s[:null] = op[:null] if s[:name].to_s == op[:name].to_s}} 227: when :set_column_type 228: duplicate_table(table){|columns| columns.each{|s| s.merge!(op) if s[:name].to_s == op[:name].to_s}} 229: when :drop_constraint 230: case op[:type] 231: when :primary_key 232: duplicate_table(table){|columns| columns.each{|s| s[:primary_key] = nil}} 233: when :foreign_key 234: duplicate_table(table, :no_foreign_keys=>true) 235: when :unique 236: duplicate_table(table) 237: else 238: raise Error, "Unsupported :type option for drop_constraint: #{op[:type].inspect}" 239: end 240: when :add_constraint 241: duplicate_table(table, :constraints=>[op]) 242: when :add_constraints 243: duplicate_table(table, :constraints=>op[:ops]) 244: else 245: raise Error, "Unsupported ALTER TABLE operation: #{op[:op].inspect}" 246: end 247: end
Run all alter_table commands in a transaction. This is technically only needed for drop column.
# File lib/sequel/adapters/shared/sqlite.rb, line 186 186: def apply_alter_table(table, ops) 187: fks = foreign_keys 188: self.foreign_keys = false if fks 189: transaction do 190: if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint} 191: # If you are just doing constraints, apply all of them at the same time, 192: # as otherwise all but the last one get lost. 193: alter_table_sql_list(table, [{:op=>:add_constraints, :ops=>ops}]).flatten.each{|sql| execute_ddl(sql)} 194: else 195: # Run each operation separately, as later operations may depend on the 196: # results of earlier operations. 197: ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}} 198: end 199: end 200: self.foreign_keys = true if fks 201: end
A name to use for the backup table
# File lib/sequel/adapters/shared/sqlite.rb, line 250 250: def backup_table_name(table, opts={}) 251: table = table.gsub('`', '') 252: (opts[:times]||1000).times do |i| 253: table_name = "#{table}_backup#{i}" 254: return table_name unless table_exists?(table_name) 255: end 256: end
Surround default with parens to appease SQLite
# File lib/sequel/adapters/shared/sqlite.rb, line 259 259: def column_definition_default_sql(sql, column) 260: sql << " DEFAULT (#{literal(column[:default])})" if column.include?(:default) 261: end
Array of PRAGMA SQL statements based on the Database options that should be applied to new connections.
# File lib/sequel/adapters/shared/sqlite.rb, line 265 265: def connection_pragmas 266: ps = [] 267: v = typecast_value_boolean(opts.fetch(:foreign_keys, 1)) 268: ps << "PRAGMA foreign_keys = #{v ? 1 : 0}" 269: v = typecast_value_boolean(opts.fetch(:case_sensitive_like, 1)) 270: ps << "PRAGMA case_sensitive_like = #{v ? 1 : 0}" 271: [[:auto_vacuum, AUTO_VACUUM], [:synchronous, SYNCHRONOUS], [:temp_store, TEMP_STORE]].each do |prag, con| 272: if v = opts[prag] 273: raise(Error, "Value for PRAGMA #{prag} not supported, should be one of #{con.join(', ')}") unless v = con.index(v.to_sym) 274: ps << "PRAGMA #{prag} = #{v}" 275: end 276: end 277: ps 278: end
The array of column schema hashes for the current columns in the table
# File lib/sequel/adapters/shared/sqlite.rb, line 281 281: def defined_columns_for(table) 282: cols = parse_pragma(table, {}) 283: cols.each do |c| 284: c[:default] = LiteralString.new(c[:default]) if c[:default] 285: c[:type] = c[:db_type] 286: end 287: cols 288: end
Duplicate an existing table by creating a new table, copying all records from the existing table into the new table, deleting the existing table and renaming the new table to the existing table’s name.
# File lib/sequel/adapters/shared/sqlite.rb, line 293 293: def duplicate_table(table, opts={}) 294: remove_cached_schema(table) 295: def_columns = defined_columns_for(table) 296: old_columns = def_columns.map{|c| c[:name]} 297: opts[:old_columns_proc].call(old_columns) if opts[:old_columns_proc] 298: 299: yield def_columns if block_given? 300: 301: constraints = (opts[:constraints] || []).dup 302: pks = [] 303: def_columns.each{|c| pks << c[:name] if c[:primary_key]} 304: if pks.length > 1 305: constraints << {:type=>:primary_key, :columns=>pks} 306: def_columns.each{|c| c[:primary_key] = false if c[:primary_key]} 307: end 308: 309: # If dropping a foreign key constraint, drop all foreign key constraints, 310: # as there is no way to determine which one to drop. 311: unless opts[:no_foreign_keys] 312: fks = foreign_key_list(table) 313: 314: # If dropping a column, if there is a foreign key with that 315: # column, don't include it when building a copy of the table. 316: if ocp = opts[:old_columns_proc] 317: fks.delete_if{|c| ocp.call(c[:columns].dup) != c[:columns]} 318: end 319: 320: constraints.concat(fks.each{|h| h[:type] = :foreign_key}) 321: end 322: 323: def_columns_str = (def_columns.map{|c| column_definition_sql(c)} + constraints.map{|c| constraint_definition_sql(c)}).join(', ') 324: new_columns = old_columns.dup 325: opts[:new_columns_proc].call(new_columns) if opts[:new_columns_proc] 326: 327: qt = quote_schema_table(table) 328: bt = quote_identifier(backup_table_name(qt)) 329: a = [ 330: "ALTER TABLE #{qt} RENAME TO #{bt}", 331: "CREATE TABLE #{qt}(#{def_columns_str})", 332: "INSERT INTO #{qt}(#{dataset.send(:identifier_list, new_columns)}) SELECT #{dataset.send(:identifier_list, old_columns)} FROM #{bt}", 333: "DROP TABLE #{bt}" 334: ] 335: indexes(table).each do |name, h| 336: if (h[:columns].map{|x| x.to_s} - new_columns).empty? 337: a << alter_table_sql(table, h.merge(:op=>:add_index, :name=>name)) 338: end 339: end 340: a 341: end
SQLite folds unquoted identifiers to lowercase, so it shouldn’t need to upcase identifiers on input.
# File lib/sequel/adapters/shared/sqlite.rb, line 344 344: def identifier_input_method_default 345: nil 346: end
SQLite folds unquoted identifiers to lowercase, so it shouldn’t need to upcase identifiers on output.
# File lib/sequel/adapters/shared/sqlite.rb, line 349 349: def identifier_output_method_default 350: nil 351: end
Does the reverse of on_delete_clause, eg. converts strings like +’SET NULL’+ to symbols :set_null.
# File lib/sequel/adapters/shared/sqlite.rb, line 355 355: def on_delete_sql_to_sym str 356: case str 357: when 'RESTRICT' 358: :restrict 359: when 'CASCADE' 360: :cascade 361: when 'SET NULL' 362: :set_null 363: when 'SET DEFAULT' 364: :set_default 365: when 'NO ACTION' 366: :no_action 367: end 368: end
Parse the output of the table_info pragma
# File lib/sequel/adapters/shared/sqlite.rb, line 371 371: def parse_pragma(table_name, opts) 372: metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth(opts[:dataset]).call(table_name)).map do |row| 373: row.delete(:cid) 374: row[:allow_null] = row.delete(:notnull).to_i == 0 375: row[:default] = row.delete(:dflt_value) 376: row[:primary_key] = row.delete(:pk).to_i == 1 377: row[:default] = nil if blank_object?(row[:default]) || row[:default] == 'NULL' 378: row[:db_type] = row.delete(:type) 379: row[:type] = schema_column_type(row[:db_type]) 380: row 381: end 382: end
SQLite treats integer primary keys as autoincrementing (alias of rowid).
# File lib/sequel/adapters/shared/sqlite.rb, line 385 385: def schema_autoincrementing_primary_key?(schema) 386: super and schema[:db_type].downcase == 'integer' 387: end
SQLite supports schema parsing using the table_info PRAGMA, so parse the output of that into the format Sequel expects.
# File lib/sequel/adapters/shared/sqlite.rb, line 391 391: def schema_parse_table(table_name, opts) 392: m = output_identifier_meth(opts[:dataset]) 393: parse_pragma(table_name, opts).map do |row| 394: [m.call(row.delete(:name)), row] 395: end 396: end
Backbone of the tables and views support.
# File lib/sequel/adapters/shared/sqlite.rb, line 399 399: def tables_and_views(filter, opts) 400: m = output_identifier_meth 401: metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(filter).map{|r| m.call(r[:name])} 402: end
SQLite only supports AUTOINCREMENT on integer columns, not bigint columns, so use integer instead of bigint for those columns.
# File lib/sequel/adapters/shared/sqlite.rb, line 407 407: def type_literal_generic_bignum(column) 408: column[:auto_increment] ? :integer : super 409: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.