]> source.dussan.org Git - sonarqube.git/blob
3ddf75589171fc9983529078d5228e1dbebd1311
[sonarqube.git] /
1 module ::JdbcSpec
2   module ActiveRecordExtensions
3     def sqlite3_connection(config)
4       config[:url] ||= "jdbc:sqlite:#{config[:database]}"
5       config[:driver] ||= "org.sqlite.JDBC"
6       jdbc_connection(config)
7     end
8   end
9
10   module SQLite3
11     def self.column_selector
12       [/sqlite/i, lambda {|cfg,col| col.extend(::JdbcSpec::SQLite3::Column)}]
13     end
14
15     def self.adapter_selector
16       [/sqlite/i, lambda {|cfg,adapt| adapt.extend(::JdbcSpec::SQLite3)}]
17     end
18
19     module Column
20
21       private
22       def simplified_type(field_type)
23         case field_type
24         when /^integer\(1\)$/i                  then :boolean
25         when /text/i                           then :string
26         when /int/i                            then :integer
27         when /real/i                   then @scale == 0 ? :integer : :decimal
28         when /date|time/i                      then :datetime
29         when /blob/i                           then :binary
30         end
31       end
32
33       def self.cast_to_date_or_time(value)
34         return value if value.is_a? Date
35         return nil if value.blank?
36         guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
37       end
38
39       def self.cast_to_time(value)
40         return value if value.is_a? Time
41         Time.at(value) rescue nil
42       end
43
44       def self.guess_date_or_time(value)
45         (value.hour == 0 and value.min == 0 and value.sec == 0) ?
46         Date.new(value.year, value.month, value.day) : value
47       end
48     end
49
50     def type_cast(value)
51       return nil if value.nil?
52       case type
53       when :string   then value
54       when :integer  then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
55       when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
56       when :float    then value.to_f
57       when :datetime then JdbcSpec::SQLite3::Column.cast_to_date_or_time(value)
58       when :time     then JdbcSpec::SQLite3::Column.cast_to_time(value)
59       when :decimal   then self.class.value_to_decimal(value)
60       when :boolean   then self.class.value_to_boolean(value)
61       else value
62       end
63     end
64
65     def modify_types(tp)
66       tp[:primary_key] = "INTEGER PRIMARY KEY AUTOINCREMENT"
67       tp[:float] = { :name => "REAL" }
68       tp[:decimal] = { :name => "REAL" }
69       tp[:datetime] = { :name => "INTEGER" }
70       tp[:timestamp] = { :name => "INTEGER" }
71       tp[:time] = { :name => "INTEGER" }
72       tp[:date] = { :name => "INTEGER" }
73       tp[:boolean] = { :name => "INTEGER", :limit => 1}
74       tp
75     end
76
77     def quote(value, column = nil) # :nodoc:
78       return value.quoted_id if value.respond_to?(:quoted_id)
79
80       case value
81       when String
82         if column && column.type == :binary
83           "'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}'"
84         else
85           "'#{quote_string(value)}'"
86         end
87       else super
88       end
89     end
90
91     def quote_string(str)
92       str.gsub(/'/, "''")
93     end
94
95     def quoted_true
96       '1'
97     end
98
99     def quoted_false
100       '0'
101     end
102
103     def add_column(table_name, column_name, type, options = {})
104       if option_not_null = options[:null] == false
105         option_not_null = options.delete(:null)
106       end
107       add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
108       add_column_options!(add_column_sql, options)
109       execute(add_column_sql)
110       if option_not_null
111         alter_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} NOT NULL"
112       end
113     end
114
115     def remove_column(table_name, column_name) #:nodoc:
116       cols = columns(table_name).collect {|col| col.name}
117       cols.delete(column_name)
118       cols = cols.join(', ')
119       table_backup = table_name + "_backup"
120
121       @connection.begin
122
123       execute "CREATE TEMPORARY TABLE #{table_backup}(#{cols})"
124       insert "INSERT INTO #{table_backup} SELECT #{cols} FROM #{table_name}"
125       execute "DROP TABLE #{table_name}"
126       execute "CREATE TABLE #{table_name}(#{cols})"
127       insert "INSERT INTO #{table_name} SELECT #{cols} FROM #{table_backup}"
128       execute "DROP TABLE #{table_backup}"
129
130       @connection.commit
131     end
132
133     def change_column(table_name, column_name, type, options = {}) #:nodoc:
134       execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"
135     end
136
137     def change_column_default(table_name, column_name, default) #:nodoc:
138       execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT #{quote(default)}"
139     end
140
141     def rename_column(table_name, column_name, new_column_name) #:nodoc:
142       execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} RENAME TO #{new_column_name}"
143     end
144
145     def rename_table(name, new_name)
146       execute "ALTER TABLE #{name} RENAME TO #{new_name}"
147     end
148
149     def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
150       log(sql,name) do
151         @connection.execute_update(sql)
152       end
153       table = sql.split(" ", 4)[2]
154       id_value || last_insert_id(table, nil)
155     end
156
157     def last_insert_id(table, sequence_name)
158       Integer(select_value("SELECT SEQ FROM SQLITE_SEQUENCE WHERE NAME = '#{table}'"))
159     end
160
161     def add_limit_offset!(sql, options) #:nodoc:
162       if options[:limit]
163         sql << " LIMIT #{options[:limit]}"
164         sql << " OFFSET #{options[:offset]}" if options[:offset]
165       end
166     end
167
168     def tables
169       @connection.tables.select {|row| row.to_s !~ /^sqlite_/i }
170     end
171
172     def remove_index(table_name, options = {})
173       execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
174     end
175
176     def indexes(table_name, name = nil)
177       result = select_rows("SELECT name, sql FROM sqlite_master WHERE tbl_name = '#{table_name}' AND type = 'index'", name)
178
179       result.collect do |row|
180         name = row[0]
181         index_sql = row[1]
182         unique = (index_sql =~ /unique/i)
183         cols = index_sql.match(/\((.*)\)/)[1].gsub(/,/,' ').split
184         ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, cols)
185       end
186     end
187   end
188 end