]> source.dussan.org Git - sonarqube.git/blob
c3556060388e15107d5eb23fdf9634b82c58d033
[sonarqube.git] /
1 require 'arjdbc/jdbc/missing_functionality_helper'
2
3 module ActiveRecord::ConnectionAdapters
4   Sqlite3Adapter = Class.new(AbstractAdapter) unless const_defined?(:Sqlite3Adapter)
5 end
6
7 module ::ArJdbc
8   module SQLite3
9     def self.column_selector
10       [/sqlite/i, lambda {|cfg,col| col.extend(::ArJdbc::SQLite3::Column)}]
11     end
12
13     def self.jdbc_connection_class
14       ::ActiveRecord::ConnectionAdapters::Sqlite3JdbcConnection
15     end
16
17     module Column
18       def init_column(name, default, *args)
19         @default = '' if default =~ /NULL/
20       end
21
22       def type_cast(value)
23         return nil if value.nil?
24         case type
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)
30         else super
31         end
32       end
33
34       private
35       def simplified_type(field_type)
36         case 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
47         end
48       end
49
50       def extract_limit(sql_type)
51         return nil if sql_type =~ /^(real)\(\d+/i
52         super
53       end
54
55       def extract_precision(sql_type)
56         case sql_type
57           when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
58           else super
59         end
60       end
61
62       def extract_scale(sql_type)
63         case sql_type
64           when /^(real)\((\d+)\)/i then 0
65           when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
66           else super
67         end
68       end
69
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 =~ /^'(.*)'$/
74
75         value
76       end
77     end
78
79     def adapter_name #:nodoc:
80       'SQLite'
81     end
82
83     def arel2_visitors
84       {'jdbcsqlite3' => ::Arel::Visitors::SQLite}
85     end
86
87     def supports_ddl_transactions?
88       true # sqlite_version >= '2.0.0'
89     end
90
91     def supports_add_column?
92       sqlite_version >= '3.1.6'
93     end
94
95     def supports_count_distinct? #:nodoc:
96       sqlite_version >= '3.2.6'
97     end
98
99     def supports_autoincrement? #:nodoc:
100       sqlite_version >= '3.1.0'
101     end
102
103     def sqlite_version
104       @sqlite_version ||= select_value('select sqlite_version(*)')
105     end
106
107     def modify_types(tp)
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" }
119       tp
120     end
121
122     def quote_column_name(name) #:nodoc:
123       %Q("#{name}")
124     end
125
126     def quote_string(str)
127       str.gsub(/'/, "''")
128     end
129
130     def quoted_true
131       %Q{'t'}
132     end
133
134     def quoted_false
135       %Q{'f'}
136     end
137
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)}"
143       else
144         super
145       end
146     end
147
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
151     end
152
153     def last_insert_id
154       Integer(select_value("SELECT last_insert_rowid()"))
155     end
156
157     def tables(name = nil) #:nodoc:
158       sql = <<-SQL
159         SELECT name
160         FROM sqlite_master
161         WHERE type = 'table' AND NOT name = 'sqlite_sequence'
162       SQL
163
164       select_rows(sql, name).map do |row|
165         row[0]
166       end
167     end
168
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)
171
172       result.collect do |row|
173         name = row[0]
174         index_sql = row[1]
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
178         end
179         ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, cols)
180       end
181     end
182
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
186     end
187
188     def recreate_database(name)
189       tables.each{ |table| drop_table(table) }
190     end
191
192     def _execute(sql, name = nil)
193       result = super
194       ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql) ? last_insert_id : result
195     end
196
197     def select(sql, name=nil)
198       execute(sql, name).map do |row|
199         record = {}
200         row.each_key do |key|
201           if key.is_a?(String)
202             record[key.sub(/^"?\w+"?\./, '')] = row[key]
203           end
204         end
205         record
206       end
207     end
208
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?
212       structure
213     end
214
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)
218       end
219     end
220
221     def primary_key(table_name) #:nodoc:
222       column = table_structure(table_name).find { |field|
223         field['pk'].to_i == 1
224       }
225       column && column['name']
226     end
227
228     def remove_index!(table_name, index_name) #:nodoc:
229       execute "DROP INDEX #{quote_column_name(index_name)}"
230     end
231
232     def rename_table(name, new_name)
233       execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
234     end
235
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
240     end
241
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)
245       else
246         alter_table(table_name) do |definition|
247           definition.column(column_name, type, options)
248         end
249       end
250     end
251
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])
257         end
258       end
259     end
260     alias :remove_columns :remove_column
261
262     def change_column_default(table_name, column_name, default) #:nodoc:
263       alter_table(table_name) do |definition|
264         definition[column_name].default = default
265       end
266     end
267
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")
271       end
272       alter_table(table_name) do |definition|
273         definition[column_name].null = null
274       end
275     end
276
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
281           self.type    = type
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)
285         end
286       end
287     end
288
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}"
292       end
293       alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
294     end
295
296      # SELECT ... FOR UPDATE is redundant since the table is locked.
297     def add_lock!(sql, options) #:nodoc:
298       sql
299     end
300
301     def empty_insert_statement_value
302       "VALUES(NULL)"
303     end
304
305     protected
306     include ArJdbc::MissingFunctionalityHelper
307
308     def translate_exception(exception, message)
309       case exception.message
310       when /column(s)? .* (is|are) not unique/
311         ActiveRecord::RecordNotUnique.new(message, exception)
312       else
313         super
314       end
315     end
316   end
317 end
318
319 module ActiveRecord::ConnectionAdapters
320   remove_const(:SQLite3Adapter) if const_defined?(:SQLite3Adapter)
321   remove_const(:SQLiteAdapter) if const_defined?(:SQLiteAdapter)
322
323   class SQLite3Column < JdbcColumn
324     include ArJdbc::SQLite3::Column
325
326     def initialize(name, *args)
327       if Hash === name
328         super
329       else
330         super(nil, name, *args)
331       end
332     end
333
334     def call_discovered_column_callbacks(*)
335     end
336
337     def self.string_to_binary(value)
338       "\000b64" + [value].pack('m*').split("\n").join('')
339     end
340
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)
344       end
345
346       if value[0..3] == "\000b64"
347         value[4..-1].unpack('m*').first
348       else
349         value
350       end
351     end
352   end
353
354   class SQLite3Adapter < JdbcAdapter
355     include ArJdbc::SQLite3
356
357     def adapter_spec(config)
358       # return nil to avoid extending ArJdbc::SQLite3, which we've already done
359     end
360
361     def jdbc_connection_class(spec)
362       ::ArJdbc::SQLite3.jdbc_connection_class
363     end
364
365     def jdbc_column_class
366       ActiveRecord::ConnectionAdapters::SQLite3Column
367     end
368
369     alias_chained_method :columns, :query_cache, :jdbc_columns
370   end
371
372   SQLiteAdapter = SQLite3Adapter
373 end
374
375 # Fake out sqlite3/version driver for AR tests
376 $LOADED_FEATURES << 'sqlite3/version.rb'
377 module SQLite3
378   module Version
379     VERSION = '1.2.6' # query_cache_test.rb requires SQLite3::Version::VERSION > '1.2.5'
380   end
381 end