PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb

https://github.com/ghar/rails
Ruby | 544 lines | 428 code | 84 blank | 32 comment | 41 complexity | 271b1831130a0b73b8376fc4a3da8e3c MD5 | raw file
  1. require 'active_record/connection_adapters/abstract_adapter'
  2. require 'active_record/connection_adapters/statement_pool'
  3. require 'active_support/core_ext/string/encoding'
  4. module ActiveRecord
  5. module ConnectionAdapters #:nodoc:
  6. class SQLiteColumn < Column #:nodoc:
  7. class << self
  8. def string_to_binary(value)
  9. value.gsub(/\0|\%/n) do |b|
  10. case b
  11. when "\0" then "%00"
  12. when "%" then "%25"
  13. end
  14. end
  15. end
  16. def binary_to_string(value)
  17. if value.respond_to?(:force_encoding) && value.encoding != Encoding::ASCII_8BIT
  18. value = value.force_encoding(Encoding::ASCII_8BIT)
  19. end
  20. value.gsub(/%00|%25/n) do |b|
  21. case b
  22. when "%00" then "\0"
  23. when "%25" then "%"
  24. end
  25. end
  26. end
  27. end
  28. end
  29. # The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby
  30. # drivers (available both as gems and from http://rubyforge.org/projects/sqlite-ruby/).
  31. #
  32. # Options:
  33. #
  34. # * <tt>:database</tt> - Path to the database file.
  35. class SQLiteAdapter < AbstractAdapter
  36. class Version
  37. include Comparable
  38. def initialize(version_string)
  39. @version = version_string.split('.').map { |v| v.to_i }
  40. end
  41. def <=>(version_string)
  42. @version <=> version_string.split('.').map { |v| v.to_i }
  43. end
  44. end
  45. class StatementPool < ConnectionAdapters::StatementPool
  46. def initialize(connection, max)
  47. super
  48. @cache = Hash.new { |h,pid| h[pid] = {} }
  49. end
  50. def each(&block); cache.each(&block); end
  51. def key?(key); cache.key?(key); end
  52. def [](key); cache[key]; end
  53. def length; cache.length; end
  54. def []=(sql, key)
  55. while @max <= cache.size
  56. dealloc(cache.shift.last[:stmt])
  57. end
  58. cache[sql] = key
  59. end
  60. def clear
  61. cache.values.each do |hash|
  62. dealloc hash[:stmt]
  63. end
  64. cache.clear
  65. end
  66. private
  67. def cache
  68. @cache[$$]
  69. end
  70. def dealloc(stmt)
  71. stmt.close unless stmt.closed?
  72. end
  73. end
  74. def initialize(connection, logger, config)
  75. super(connection, logger)
  76. @statements = StatementPool.new(@connection,
  77. config.fetch(:statement_limit) { 1000 })
  78. @config = config
  79. end
  80. def self.visitor_for(pool) # :nodoc:
  81. Arel::Visitors::SQLite.new(pool)
  82. end
  83. def adapter_name #:nodoc:
  84. 'SQLite'
  85. end
  86. # Returns true if SQLite version is '2.0.0' or greater, false otherwise.
  87. def supports_ddl_transactions?
  88. sqlite_version >= '2.0.0'
  89. end
  90. # Returns true if SQLite version is '3.6.8' or greater, false otherwise.
  91. def supports_savepoints?
  92. sqlite_version >= '3.6.8'
  93. end
  94. # Returns true, since this connection adapter supports prepared statement
  95. # caching.
  96. def supports_statement_cache?
  97. true
  98. end
  99. # Returns true, since this connection adapter supports migrations.
  100. def supports_migrations? #:nodoc:
  101. true
  102. end
  103. # Returns true.
  104. def supports_primary_key? #:nodoc:
  105. true
  106. end
  107. def requires_reloading?
  108. true
  109. end
  110. # Returns true if SQLite version is '3.1.6' or greater, false otherwise.
  111. def supports_add_column?
  112. sqlite_version >= '3.1.6'
  113. end
  114. # Disconnects from the database if already connected. Otherwise, this
  115. # method does nothing.
  116. def disconnect!
  117. super
  118. clear_cache!
  119. @connection.close rescue nil
  120. end
  121. # Clears the prepared statements cache.
  122. def clear_cache!
  123. @statements.clear
  124. end
  125. # Returns true if SQLite version is '3.2.6' or greater, false otherwise.
  126. def supports_count_distinct? #:nodoc:
  127. sqlite_version >= '3.2.6'
  128. end
  129. # Returns true if SQLite version is '3.1.0' or greater, false otherwise.
  130. def supports_autoincrement? #:nodoc:
  131. sqlite_version >= '3.1.0'
  132. end
  133. def native_database_types #:nodoc:
  134. {
  135. :primary_key => default_primary_key_type,
  136. :string => { :name => "varchar", :limit => 255 },
  137. :text => { :name => "text" },
  138. :integer => { :name => "integer" },
  139. :float => { :name => "float" },
  140. :decimal => { :name => "decimal" },
  141. :datetime => { :name => "datetime" },
  142. :timestamp => { :name => "datetime" },
  143. :time => { :name => "time" },
  144. :date => { :name => "date" },
  145. :binary => { :name => "blob" },
  146. :boolean => { :name => "boolean" }
  147. }
  148. end
  149. # QUOTING ==================================================
  150. def quote_string(s) #:nodoc:
  151. @connection.class.quote(s)
  152. end
  153. def quote_column_name(name) #:nodoc:
  154. %Q("#{name.to_s.gsub('"', '""')}")
  155. end
  156. # Quote date/time values for use in SQL input. Includes microseconds
  157. # if the value is a Time responding to usec.
  158. def quoted_date(value) #:nodoc:
  159. if value.respond_to?(:usec)
  160. "#{super}.#{sprintf("%06d", value.usec)}"
  161. else
  162. super
  163. end
  164. end
  165. if "<3".encoding_aware?
  166. def type_cast(value, column) # :nodoc:
  167. return value.to_f if BigDecimal === value
  168. return super unless String === value
  169. return super unless column && value
  170. value = super
  171. if column.type == :string && value.encoding == Encoding::ASCII_8BIT
  172. @logger.error "Binary data inserted for `string` type on column `#{column.name}`"
  173. value.encode! 'utf-8'
  174. end
  175. value
  176. end
  177. else
  178. def type_cast(value, column) # :nodoc:
  179. return super unless BigDecimal === value
  180. value.to_f
  181. end
  182. end
  183. # DATABASE STATEMENTS ======================================
  184. def exec_query(sql, name = nil, binds = [])
  185. log(sql, name, binds) do
  186. # Don't cache statements without bind values
  187. if binds.empty?
  188. stmt = @connection.prepare(sql)
  189. cols = stmt.columns
  190. records = stmt.to_a
  191. stmt.close
  192. stmt = records
  193. else
  194. cache = @statements[sql] ||= {
  195. :stmt => @connection.prepare(sql)
  196. }
  197. stmt = cache[:stmt]
  198. cols = cache[:cols] ||= stmt.columns
  199. stmt.reset!
  200. stmt.bind_params binds.map { |col, val|
  201. type_cast(val, col)
  202. }
  203. end
  204. ActiveRecord::Result.new(cols, stmt.to_a)
  205. end
  206. end
  207. def exec_delete(sql, name = 'SQL', binds = [])
  208. exec_query(sql, name, binds)
  209. @connection.changes
  210. end
  211. alias :exec_update :exec_delete
  212. def last_inserted_id(result)
  213. @connection.last_insert_row_id
  214. end
  215. def execute(sql, name = nil) #:nodoc:
  216. log(sql, name) { @connection.execute(sql) }
  217. end
  218. def update_sql(sql, name = nil) #:nodoc:
  219. super
  220. @connection.changes
  221. end
  222. def delete_sql(sql, name = nil) #:nodoc:
  223. sql += " WHERE 1=1" unless sql =~ /WHERE/i
  224. super sql, name
  225. end
  226. def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
  227. super
  228. id_value || @connection.last_insert_row_id
  229. end
  230. alias :create :insert_sql
  231. def select_rows(sql, name = nil)
  232. exec_query(sql, name).rows
  233. end
  234. def create_savepoint
  235. execute("SAVEPOINT #{current_savepoint_name}")
  236. end
  237. def rollback_to_savepoint
  238. execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
  239. end
  240. def release_savepoint
  241. execute("RELEASE SAVEPOINT #{current_savepoint_name}")
  242. end
  243. def begin_db_transaction #:nodoc:
  244. log('begin transaction',nil) { @connection.transaction }
  245. end
  246. def commit_db_transaction #:nodoc:
  247. log('commit transaction',nil) { @connection.commit }
  248. end
  249. def rollback_db_transaction #:nodoc:
  250. log('rollback transaction',nil) { @connection.rollback }
  251. end
  252. # SCHEMA STATEMENTS ========================================
  253. def tables(name = 'SCHEMA') #:nodoc:
  254. sql = <<-SQL
  255. SELECT name
  256. FROM sqlite_master
  257. WHERE type = 'table' AND NOT name = 'sqlite_sequence'
  258. SQL
  259. exec_query(sql, name).map do |row|
  260. row['name']
  261. end
  262. end
  263. # Returns an array of +SQLiteColumn+ objects for the table specified by +table_name+.
  264. def columns(table_name, name = nil) #:nodoc:
  265. table_structure(table_name).map do |field|
  266. case field["dflt_value"]
  267. when /^null$/i
  268. field["dflt_value"] = nil
  269. when /^'(.*)'$/
  270. field["dflt_value"] = $1.gsub(/''/, "'")
  271. when /^"(.*)"$/
  272. field["dflt_value"] = $1.gsub(/""/, '"')
  273. end
  274. SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
  275. end
  276. end
  277. # Returns an array of indexes for the given table.
  278. def indexes(table_name, name = nil) #:nodoc:
  279. exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
  280. IndexDefinition.new(
  281. table_name,
  282. row['name'],
  283. row['unique'] != 0,
  284. exec_query("PRAGMA index_info('#{row['name']}')").map { |col|
  285. col['name']
  286. })
  287. end
  288. end
  289. def primary_key(table_name) #:nodoc:
  290. column = table_structure(table_name).find { |field|
  291. field['pk'] == 1
  292. }
  293. column && column['name']
  294. end
  295. def remove_index!(table_name, index_name) #:nodoc:
  296. exec_query "DROP INDEX #{quote_column_name(index_name)}"
  297. end
  298. # Renames a table.
  299. #
  300. # Example:
  301. # rename_table('octopuses', 'octopi')
  302. def rename_table(name, new_name)
  303. exec_query "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
  304. end
  305. # See: http://www.sqlite.org/lang_altertable.html
  306. # SQLite has an additional restriction on the ALTER TABLE statement
  307. def valid_alter_table_options( type, options)
  308. type.to_sym != :primary_key
  309. end
  310. def add_column(table_name, column_name, type, options = {}) #:nodoc:
  311. if supports_add_column? && valid_alter_table_options( type, options )
  312. super(table_name, column_name, type, options)
  313. else
  314. alter_table(table_name) do |definition|
  315. definition.column(column_name, type, options)
  316. end
  317. end
  318. end
  319. def remove_column(table_name, *column_names) #:nodoc:
  320. raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
  321. column_names.flatten.each do |column_name|
  322. alter_table(table_name) do |definition|
  323. definition.columns.delete(definition[column_name])
  324. end
  325. end
  326. end
  327. alias :remove_columns :remove_column
  328. def change_column_default(table_name, column_name, default) #:nodoc:
  329. alter_table(table_name) do |definition|
  330. definition[column_name].default = default
  331. end
  332. end
  333. def change_column_null(table_name, column_name, null, default = nil)
  334. unless null || default.nil?
  335. exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
  336. end
  337. alter_table(table_name) do |definition|
  338. definition[column_name].null = null
  339. end
  340. end
  341. def change_column(table_name, column_name, type, options = {}) #:nodoc:
  342. alter_table(table_name) do |definition|
  343. include_default = options_include_default?(options)
  344. definition[column_name].instance_eval do
  345. self.type = type
  346. self.limit = options[:limit] if options.include?(:limit)
  347. self.default = options[:default] if include_default
  348. self.null = options[:null] if options.include?(:null)
  349. end
  350. end
  351. end
  352. def rename_column(table_name, column_name, new_column_name) #:nodoc:
  353. unless columns(table_name).detect{|c| c.name == column_name.to_s }
  354. raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
  355. end
  356. alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
  357. end
  358. def empty_insert_statement_value
  359. "VALUES(NULL)"
  360. end
  361. protected
  362. def select(sql, name = nil, binds = []) #:nodoc:
  363. exec_query(sql, name, binds).to_a
  364. end
  365. def table_structure(table_name)
  366. structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash
  367. raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
  368. structure
  369. end
  370. def alter_table(table_name, options = {}) #:nodoc:
  371. altered_table_name = "altered_#{table_name}"
  372. caller = lambda {|definition| yield definition if block_given?}
  373. transaction do
  374. move_table(table_name, altered_table_name,
  375. options.merge(:temporary => true))
  376. move_table(altered_table_name, table_name, &caller)
  377. end
  378. end
  379. def move_table(from, to, options = {}, &block) #:nodoc:
  380. copy_table(from, to, options, &block)
  381. drop_table(from)
  382. end
  383. def copy_table(from, to, options = {}) #:nodoc:
  384. options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
  385. create_table(to, options) do |definition|
  386. @definition = definition
  387. columns(from).each do |column|
  388. column_name = options[:rename] ?
  389. (options[:rename][column.name] ||
  390. options[:rename][column.name.to_sym] ||
  391. column.name) : column.name
  392. @definition.column(column_name, column.type,
  393. :limit => column.limit, :default => column.default,
  394. :null => column.null)
  395. end
  396. @definition.primary_key(primary_key(from)) if primary_key(from)
  397. yield @definition if block_given?
  398. end
  399. copy_table_indexes(from, to, options[:rename] || {})
  400. copy_table_contents(from, to,
  401. @definition.columns.map {|column| column.name},
  402. options[:rename] || {})
  403. end
  404. def copy_table_indexes(from, to, rename = {}) #:nodoc:
  405. indexes(from).each do |index|
  406. name = index.name
  407. if to == "altered_#{from}"
  408. name = "temp_#{name}"
  409. elsif from == "altered_#{to}"
  410. name = name[5..-1]
  411. end
  412. to_column_names = columns(to).map { |c| c.name }
  413. columns = index.columns.map {|c| rename[c] || c }.select do |column|
  414. to_column_names.include?(column)
  415. end
  416. unless columns.empty?
  417. # index name can't be the same
  418. opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
  419. opts[:unique] = true if index.unique
  420. add_index(to, columns, opts)
  421. end
  422. end
  423. end
  424. def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
  425. column_mappings = Hash[columns.map {|name| [name, name]}]
  426. rename.each { |a| column_mappings[a.last] = a.first }
  427. from_columns = columns(from).collect {|col| col.name}
  428. columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
  429. quoted_columns = columns.map { |col| quote_column_name(col) } * ','
  430. quoted_to = quote_table_name(to)
  431. exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row|
  432. sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
  433. sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
  434. sql << ')'
  435. exec_query sql
  436. end
  437. end
  438. def sqlite_version
  439. @sqlite_version ||= SQLiteAdapter::Version.new(select_value('select sqlite_version(*)'))
  440. end
  441. def default_primary_key_type
  442. if supports_autoincrement?
  443. 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'
  444. else
  445. 'INTEGER PRIMARY KEY NOT NULL'
  446. end
  447. end
  448. def translate_exception(exception, message)
  449. case exception.message
  450. when /column(s)? .* (is|are) not unique/
  451. RecordNotUnique.new(message, exception)
  452. else
  453. super
  454. end
  455. end
  456. end
  457. end
  458. end