]> source.dussan.org Git - sonarqube.git/blob
40e20c65b94839fccfa96f749ac2be2c44bc8f29
[sonarqube.git] /
1 module ::JdbcSpec
2   module ActiveRecordExtensions
3     def hsqldb_connection(config)
4       config[:url] ||= "jdbc:hsqldb:#{config[:database]}"
5       config[:driver] ||= "org.hsqldb.jdbcDriver"
6       embedded_driver(config)
7     end
8
9     def h2_connection(config)
10       config[:url] ||= "jdbc:h2:#{config[:database]}"
11       config[:driver] ||= "org.h2.Driver"
12       embedded_driver(config)
13     end
14   end
15
16   module HSQLDB
17     def self.column_selector
18       [/hsqldb|\.h2\./i, lambda {|cfg,col| col.extend(::JdbcSpec::HSQLDB::Column)}]
19     end
20
21     def self.adapter_selector
22       [/hsqldb|\.h2\./i, lambda do |cfg,adapt|
23          adapt.extend(::JdbcSpec::HSQLDB)
24          def adapt.h2_adapter; true; end if cfg[:driver] =~ /\.h2\./
25        end]
26     end
27
28     module Column
29       def type_cast(value)
30         return nil if value.nil? || value =~ /^\s*null\s*$/i
31         case type
32         when :string    then value
33         when :integer   then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
34         when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
35         when :float     then value.to_f
36         when :datetime  then cast_to_date_or_time(value)
37         when :timestamp then cast_to_time(value)
38         when :binary    then value.scan(/[0-9A-Fa-f]{2}/).collect {|v| v.to_i(16)}.pack("C*")
39         when :time      then cast_to_time(value)
40         else value
41         end
42       end
43       def cast_to_date_or_time(value)
44         return value if value.is_a? Date
45         return nil if value.blank?
46         guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
47       end
48
49       def cast_to_time(value)
50         return value if value.is_a? Time
51         time_array = ParseDate.parsedate value
52         time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
53         Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
54       end
55
56       def guess_date_or_time(value)
57         (value.hour == 0 and value.min == 0 and value.sec == 0) ?
58         Date.new(value.year, value.month, value.day) : value
59       end
60
61
62       private
63       def simplified_type(field_type)
64         case field_type
65         when /longvarchar/i
66           :text
67         else
68           super(field_type)
69         end
70       end
71
72       # Override of ActiveRecord::ConnectionAdapters::Column
73       def extract_limit(sql_type)
74         # HSQLDB appears to return "LONGVARCHAR(0)" for :text columns, which
75         # for AR purposes should be interpreted as "no limit"
76         return nil if sql_type =~ /\(0\)/
77         super
78       end
79     end
80
81     def modify_types(tp)
82       tp[:primary_key] = "INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) PRIMARY KEY"
83       tp[:integer][:limit] = nil
84       tp[:boolean][:limit] = nil
85       # set text and float limits so we don't see odd scales tacked on
86       # in migrations
87       tp[:text][:limit] = nil
88       tp[:float][:limit] = 17
89       tp[:string][:limit] = 255
90       tp[:datetime] = { :name => "DATETIME" }
91       tp[:timestamp] = { :name => "DATETIME" }
92       tp[:time] = { :name => "DATETIME" }
93       tp[:date] = { :name => "DATETIME" }
94       tp
95     end
96
97     def quote(value, column = nil) # :nodoc:
98       return value.quoted_id if value.respond_to?(:quoted_id)
99
100       case value
101       when String
102         if respond_to?(:h2_adapter) && value.empty?
103           "NULL"
104         elsif column && column.type == :binary
105           "'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}'"
106         else
107           "'#{quote_string(value)}'"
108         end
109       else super
110       end
111     end
112
113     def quote_string(str)
114       str.gsub(/'/, "''")
115     end
116
117     def quoted_true
118       '1'
119     end
120
121     def quoted_false
122       '0'
123     end
124
125     def add_column(table_name, column_name, type, options = {})
126       if option_not_null = options[:null] == false
127         option_not_null = options.delete(:null)
128       end
129       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])}"
130       add_column_options!(add_column_sql, options)
131       execute(add_column_sql)
132       if option_not_null
133         alter_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} NOT NULL"
134       end
135     end
136
137     def change_column(table_name, column_name, type, options = {}) #:nodoc:
138       execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"
139     end
140
141     def change_column_default(table_name, column_name, default) #:nodoc:
142       execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT #{quote(default)}"
143     end
144
145     def rename_column(table_name, column_name, new_column_name) #:nodoc:
146       execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} RENAME TO #{new_column_name}"
147     end
148
149     def rename_table(name, new_name)
150       execute "ALTER TABLE #{name} RENAME TO #{new_name}"
151     end
152
153     def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
154       log(sql,name) do
155         @connection.execute_update(sql)
156       end
157       table = sql.split(" ", 4)[2]
158       id_value || last_insert_id(table, nil)
159     end
160
161     def last_insert_id(table, sequence_name)
162       Integer(select_value("SELECT IDENTITY() FROM #{table}"))
163     end
164
165     # Override normal #_execute: See Rubyforge #11567
166     def _execute(sql, name = nil)
167       if ::ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
168         @connection.execute_query(sql)
169       elsif ::ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
170         insert(sql, name)
171       else
172         @connection.execute_update(sql)
173       end
174     end
175
176     def add_limit_offset!(sql, options) #:nodoc:
177       offset = options[:offset] || 0
178       bef = sql[7..-1]
179       if limit = options[:limit]
180         sql.replace "select limit #{offset} #{limit} #{bef}"
181       elsif offset > 0
182         sql.replace "select limit #{offset} 0 #{bef}"
183       end
184     end
185
186     # override to filter out system tables that otherwise end
187     # up in db/schema.rb during migrations.  JdbcConnection#tables
188     # now takes an optional block filter so we can screen out
189     # rows corresponding to system tables.  HSQLDB names its
190     # system tables SYSTEM.*, but H2 seems to name them without
191     # any kind of convention
192     def tables
193       @connection.tables.select {|row| row.to_s !~ /^system_/i }
194     end
195
196     def remove_index(table_name, options = {})
197       execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
198     end
199   end
200 end