activerecord-jdbc-adapter 0.9.3-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +248 -0
- data/LICENSE.txt +21 -0
- data/Manifest.txt +125 -0
- data/README.txt +218 -0
- data/Rakefile +10 -0
- data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +640 -0
- data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +26 -0
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
- data/lib/generators/jdbc/jdbc_generator.rb +9 -0
- data/lib/jdbc_adapter.rb +27 -0
- data/lib/jdbc_adapter/jdbc.rake +121 -0
- data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
- data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
- data/lib/jdbc_adapter/jdbc_db2.rb +203 -0
- data/lib/jdbc_adapter/jdbc_derby.rb +430 -0
- data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +218 -0
- data/lib/jdbc_adapter/jdbc_informix.rb +147 -0
- data/lib/jdbc_adapter/jdbc_mimer.rb +141 -0
- data/lib/jdbc_adapter/jdbc_mssql.rb +337 -0
- data/lib/jdbc_adapter/jdbc_mysql.rb +236 -0
- data/lib/jdbc_adapter/jdbc_oracle.rb +377 -0
- data/lib/jdbc_adapter/jdbc_postgre.rb +498 -0
- data/lib/jdbc_adapter/jdbc_sqlite3.rb +384 -0
- data/lib/jdbc_adapter/jdbc_sybase.rb +50 -0
- data/lib/jdbc_adapter/missing_functionality_helper.rb +87 -0
- data/lib/jdbc_adapter/rake_tasks.rb +10 -0
- data/lib/jdbc_adapter/tsql_helper.rb +60 -0
- data/lib/jdbc_adapter/version.rb +5 -0
- data/lib/pg.rb +4 -0
- data/rails_generators/jdbc_generator.rb +15 -0
- data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
- data/rakelib/compile.rake +23 -0
- data/rakelib/package.rake +90 -0
- data/rakelib/rails.rake +41 -0
- data/rakelib/test.rake +76 -0
- data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +53 -0
- data/src/java/jdbc_adapter/JdbcConnectionFactory.java +36 -0
- data/src/java/jdbc_adapter/JdbcDerbySpec.java +293 -0
- data/src/java/jdbc_adapter/JdbcMySQLSpec.java +134 -0
- data/src/java/jdbc_adapter/MssqlRubyJdbcConnection.java +71 -0
- data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +55 -0
- data/src/java/jdbc_adapter/RubyJdbcConnection.java +1162 -0
- data/src/java/jdbc_adapter/SQLBlock.java +27 -0
- data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
- data/test/abstract_db_create.rb +107 -0
- data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
- data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
- data/test/cachedb_simple_test.rb +6 -0
- data/test/db/cachedb.rb +9 -0
- data/test/db/db2.rb +9 -0
- data/test/db/derby.rb +14 -0
- data/test/db/h2.rb +11 -0
- data/test/db/hsqldb.rb +12 -0
- data/test/db/informix.rb +11 -0
- data/test/db/jdbc.rb +11 -0
- data/test/db/jndi_config.rb +30 -0
- data/test/db/logger.rb +3 -0
- data/test/db/mssql.rb +9 -0
- data/test/db/mysql.rb +10 -0
- data/test/db/oracle.rb +34 -0
- data/test/db/postgres.rb +9 -0
- data/test/db/sqlite3.rb +15 -0
- data/test/db2_simple_test.rb +10 -0
- data/test/derby_migration_test.rb +21 -0
- data/test/derby_multibyte_test.rb +12 -0
- data/test/derby_simple_test.rb +21 -0
- data/test/generic_jdbc_connection_test.rb +9 -0
- data/test/h2_simple_test.rb +6 -0
- data/test/has_many_through.rb +79 -0
- data/test/helper.rb +5 -0
- data/test/hsqldb_simple_test.rb +6 -0
- data/test/informix_simple_test.rb +48 -0
- data/test/jdbc_adapter/jdbc_db2_test.rb +26 -0
- data/test/jdbc_adapter/jdbc_sybase_test.rb +33 -0
- data/test/jdbc_common.rb +25 -0
- data/test/jndi_callbacks_test.rb +38 -0
- data/test/jndi_test.rb +35 -0
- data/test/manualTestDatabase.rb +191 -0
- data/test/minirunit.rb +109 -0
- data/test/minirunit/testConnect.rb +14 -0
- data/test/minirunit/testH2.rb +73 -0
- data/test/minirunit/testHsqldb.rb +73 -0
- data/test/minirunit/testLoadActiveRecord.rb +3 -0
- data/test/minirunit/testMysql.rb +83 -0
- data/test/minirunit/testRawSelect.rb +24 -0
- data/test/models/add_not_null_column_to_table.rb +12 -0
- data/test/models/auto_id.rb +18 -0
- data/test/models/data_types.rb +28 -0
- data/test/models/entry.rb +23 -0
- data/test/models/mixed_case.rb +20 -0
- data/test/models/reserved_word.rb +18 -0
- data/test/models/string_id.rb +18 -0
- data/test/models/validates_uniqueness_of_string.rb +19 -0
- data/test/mssql_simple_test.rb +6 -0
- data/test/mysql_db_create_test.rb +25 -0
- data/test/mysql_multibyte_test.rb +10 -0
- data/test/mysql_nonstandard_primary_key_test.rb +42 -0
- data/test/mysql_simple_test.rb +32 -0
- data/test/oracle_simple_test.rb +29 -0
- data/test/pick_rails_version.rb +3 -0
- data/test/postgres_db_create_test.rb +21 -0
- data/test/postgres_mixed_case_test.rb +19 -0
- data/test/postgres_nonseq_pkey_test.rb +40 -0
- data/test/postgres_reserved_test.rb +22 -0
- data/test/postgres_schema_search_path_test.rb +46 -0
- data/test/postgres_simple_test.rb +13 -0
- data/test/simple.rb +475 -0
- data/test/sqlite3_simple_test.rb +233 -0
- data/test/sybase_jtds_simple_test.rb +6 -0
- metadata +188 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
require 'jdbc_adapter/missing_functionality_helper'
|
|
2
|
+
|
|
3
|
+
module ::JdbcSpec
|
|
4
|
+
module ActiveRecordExtensions
|
|
5
|
+
def derby_connection(config)
|
|
6
|
+
require File.dirname(__FILE__) + "/../active_record/connection_adapters/derby_adapter"
|
|
7
|
+
config[:url] ||= "jdbc:derby:#{config[:database]};create=true"
|
|
8
|
+
config[:driver] ||= "org.apache.derby.jdbc.EmbeddedDriver"
|
|
9
|
+
check_version(embedded_driver(config))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def check_version(conn)
|
|
13
|
+
md = conn.raw_connection.connection.meta_data
|
|
14
|
+
if md.database_major_version < 10 || md.database_minor_version < 5
|
|
15
|
+
raise ::ActiveRecord::ConnectionFailed, "Derby adapter requires Derby 10.5 or later"
|
|
16
|
+
end
|
|
17
|
+
conn
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module Derby
|
|
22
|
+
def self.adapter_matcher(name, *)
|
|
23
|
+
name =~ /derby/i ? self : false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.column_selector
|
|
27
|
+
[/derby/i, lambda {|cfg,col| col.extend(::JdbcSpec::Derby::Column)}]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.monkey_rails
|
|
31
|
+
unless @already_monkeyd
|
|
32
|
+
# Needed because Rails is broken wrt to quoting of
|
|
33
|
+
# some values. Most databases are nice about it,
|
|
34
|
+
# but not Derby. The real issue is that you can't
|
|
35
|
+
# compare a CHAR value to a NUMBER column.
|
|
36
|
+
::ActiveRecord::Associations::ClassMethods.module_eval do
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def select_limited_ids_list(options, join_dependency)
|
|
40
|
+
connection.select_all(
|
|
41
|
+
construct_finder_sql_for_association_limiting(options, join_dependency),
|
|
42
|
+
"#{name} Load IDs For Limited Eager Loading"
|
|
43
|
+
).collect { |row| connection.quote(row[primary_key], columns_hash[primary_key]) }.join(", ")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@already_monkeyd = true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.extended(*args)
|
|
52
|
+
monkey_rails
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.included(*args)
|
|
56
|
+
monkey_rails
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
module Column
|
|
60
|
+
def simplified_type(field_type)
|
|
61
|
+
return :boolean if field_type =~ /smallint/i
|
|
62
|
+
return :float if field_type =~ /real/i
|
|
63
|
+
super
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
|
67
|
+
def default_value(value)
|
|
68
|
+
# jdbc returns column default strings with actual single quotes around the value.
|
|
69
|
+
return $1 if value =~ /^'(.*)'$/
|
|
70
|
+
|
|
71
|
+
value
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def adapter_name #:nodoc:
|
|
76
|
+
'Derby'
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
include JdbcSpec::MissingFunctionalityHelper
|
|
80
|
+
|
|
81
|
+
# Convert the speficied column type to a SQL string. In Derby, :integers cannot specify
|
|
82
|
+
# a limit.
|
|
83
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
|
84
|
+
return super unless type == :integer
|
|
85
|
+
|
|
86
|
+
native = native_database_types[type.to_s.downcase.to_sym]
|
|
87
|
+
native.is_a?(Hash) ? native[:name] : native
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def modify_types(tp)
|
|
91
|
+
tp[:primary_key] = "int generated by default as identity NOT NULL PRIMARY KEY"
|
|
92
|
+
tp[:integer][:limit] = nil
|
|
93
|
+
tp[:string][:limit] = 256
|
|
94
|
+
tp[:boolean] = {:name => "smallint"}
|
|
95
|
+
tp
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Override default -- fix case where ActiveRecord passes :default => nil, :null => true
|
|
99
|
+
def add_column_options!(sql, options)
|
|
100
|
+
options.delete(:default) if options.has_key?(:default) && options[:default].nil?
|
|
101
|
+
options.delete(:null) if options.has_key?(:null) && (options[:null].nil? || options[:null] == true)
|
|
102
|
+
super
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def classes_for_table_name(table)
|
|
106
|
+
ActiveRecord::Base.send(:subclasses).select {|klass| klass.table_name == table}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Set the sequence to the max value of the table's column.
|
|
110
|
+
def reset_sequence!(table, column, sequence = nil)
|
|
111
|
+
mpk = select_value("SELECT MAX(#{quote_column_name(column)}) FROM #{quote_table_name(table)}")
|
|
112
|
+
execute("ALTER TABLE #{quote_table_name(table)} ALTER COLUMN #{quote_column_name(column)} RESTART WITH #{mpk.to_i + 1}")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def reset_pk_sequence!(table, pk = nil, sequence = nil)
|
|
116
|
+
klasses = classes_for_table_name(table)
|
|
117
|
+
klass = klasses.nil? ? nil : klasses.first
|
|
118
|
+
pk = klass.primary_key unless klass.nil?
|
|
119
|
+
if pk && klass.columns_hash[pk].type == :integer
|
|
120
|
+
reset_sequence!(klass.table_name, pk)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def primary_key(table_name) #:nodoc:
|
|
125
|
+
primary_keys(table_name).first
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def remove_index(table_name, options) #:nodoc:
|
|
129
|
+
execute "DROP INDEX #{index_name(table_name, options)}"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def rename_table(name, new_name)
|
|
133
|
+
execute "RENAME TABLE #{name} TO #{new_name}"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
COLUMN_INFO_STMT = "SELECT C.COLUMNNAME, C.REFERENCEID, C.COLUMNNUMBER FROM SYS.SYSCOLUMNS C, SYS.SYSTABLES T WHERE T.TABLEID = '%s' AND T.TABLEID = C.REFERENCEID ORDER BY C.COLUMNNUMBER"
|
|
137
|
+
|
|
138
|
+
COLUMN_TYPE_STMT = "SELECT COLUMNDATATYPE, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
|
|
139
|
+
|
|
140
|
+
AUTO_INC_STMT = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
|
|
141
|
+
AUTO_INC_STMT2 = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = (SELECT T.TABLEID FROM SYS.SYSTABLES T WHERE T.TABLENAME = '%s') AND COLUMNNAME = '%s'"
|
|
142
|
+
|
|
143
|
+
def add_quotes(name)
|
|
144
|
+
return name unless name
|
|
145
|
+
%Q{"#{name}"}
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def strip_quotes(str)
|
|
149
|
+
return str unless str
|
|
150
|
+
return str unless /^(["']).*\1$/ =~ str
|
|
151
|
+
str[1..-2]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def expand_double_quotes(name)
|
|
155
|
+
return name unless name && name['"']
|
|
156
|
+
name.gsub(/"/,'""')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def reinstate_auto_increment(name, refid, coldef)
|
|
160
|
+
stmt = AUTO_INC_STMT % [refid, strip_quotes(name)]
|
|
161
|
+
data = execute(stmt).first
|
|
162
|
+
if data
|
|
163
|
+
start = data['autoincrementstart']
|
|
164
|
+
if start
|
|
165
|
+
coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
|
|
166
|
+
coldef << "AS IDENTITY (START WITH "
|
|
167
|
+
coldef << start
|
|
168
|
+
coldef << ", INCREMENT BY "
|
|
169
|
+
coldef << data['autoincrementinc']
|
|
170
|
+
coldef << ")"
|
|
171
|
+
return true
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
false
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def reinstate_auto_increment(name, refid, coldef)
|
|
178
|
+
stmt = AUTO_INC_STMT % [refid, strip_quotes(name)]
|
|
179
|
+
data = execute(stmt).first
|
|
180
|
+
if data
|
|
181
|
+
start = data['autoincrementstart']
|
|
182
|
+
if start
|
|
183
|
+
coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
|
|
184
|
+
coldef << "AS IDENTITY (START WITH "
|
|
185
|
+
coldef << start
|
|
186
|
+
coldef << ", INCREMENT BY "
|
|
187
|
+
coldef << data['autoincrementinc']
|
|
188
|
+
coldef << ")"
|
|
189
|
+
return true
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
false
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def auto_increment_stmt(tname, cname)
|
|
196
|
+
stmt = AUTO_INC_STMT2 % [tname, strip_quotes(cname)]
|
|
197
|
+
data = execute(stmt).first
|
|
198
|
+
if data
|
|
199
|
+
start = data['autoincrementstart']
|
|
200
|
+
if start
|
|
201
|
+
coldef = ""
|
|
202
|
+
coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
|
|
203
|
+
coldef << "AS IDENTITY (START WITH "
|
|
204
|
+
coldef << start
|
|
205
|
+
coldef << ", INCREMENT BY "
|
|
206
|
+
coldef << data['autoincrementinc']
|
|
207
|
+
coldef << ")"
|
|
208
|
+
return coldef
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
""
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def add_column(table_name, column_name, type, options = {})
|
|
216
|
+
if option_not_null = options[:null] == false
|
|
217
|
+
option_not_null = options.delete(:null)
|
|
218
|
+
end
|
|
219
|
+
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])}"
|
|
220
|
+
add_column_options!(add_column_sql, options)
|
|
221
|
+
execute(add_column_sql)
|
|
222
|
+
if option_not_null
|
|
223
|
+
alter_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} NOT NULL"
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def execute(sql, name = nil)
|
|
228
|
+
if sql =~ /^\s*(UPDATE|INSERT)/i
|
|
229
|
+
i = sql =~ /\swhere\s/im
|
|
230
|
+
if i
|
|
231
|
+
sql[i..-1] = sql[i..-1].gsub(/!=\s*NULL/, 'IS NOT NULL').gsub(/=\sNULL/i, 'IS NULL')
|
|
232
|
+
end
|
|
233
|
+
else
|
|
234
|
+
sql.gsub!(/= NULL/i, 'IS NULL')
|
|
235
|
+
end
|
|
236
|
+
super
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# I don't think this method is ever called ??? (stepheneb)
|
|
241
|
+
def create_column(name, refid, colno)
|
|
242
|
+
stmt = COLUMN_TYPE_STMT % [refid, strip_quotes(name)]
|
|
243
|
+
coldef = ""
|
|
244
|
+
data = execute(stmt).first
|
|
245
|
+
if data
|
|
246
|
+
coldef << add_quotes(expand_double_quotes(strip_quotes(name)))
|
|
247
|
+
coldef << " "
|
|
248
|
+
coldef << data['columndatatype']
|
|
249
|
+
if !reinstate_auto_increment(name, refid, coldef) && data['columndefault']
|
|
250
|
+
coldef << " DEFAULT " << data['columndefault']
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
coldef
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
SIZEABLE = %w(VARCHAR CLOB BLOB)
|
|
257
|
+
|
|
258
|
+
def structure_dump #:nodoc:
|
|
259
|
+
definition=""
|
|
260
|
+
rs = @connection.connection.meta_data.getTables(nil,nil,nil,["TABLE"].to_java(:string))
|
|
261
|
+
while rs.next
|
|
262
|
+
tname = rs.getString(3)
|
|
263
|
+
definition << "CREATE TABLE #{tname} (\n"
|
|
264
|
+
rs2 = @connection.connection.meta_data.getColumns(nil,nil,tname,nil)
|
|
265
|
+
first_col = true
|
|
266
|
+
while rs2.next
|
|
267
|
+
col_name = add_quotes(rs2.getString(4));
|
|
268
|
+
default = ""
|
|
269
|
+
d1 = rs2.getString(13)
|
|
270
|
+
if d1 =~ /^GENERATED_/
|
|
271
|
+
default = auto_increment_stmt(tname, col_name)
|
|
272
|
+
elsif d1
|
|
273
|
+
default = " DEFAULT #{d1}"
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
type = rs2.getString(6)
|
|
277
|
+
col_size = rs2.getString(7)
|
|
278
|
+
nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
|
|
279
|
+
create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
|
|
280
|
+
" " +
|
|
281
|
+
type +
|
|
282
|
+
(SIZEABLE.include?(type) ? "(#{col_size})" : "") +
|
|
283
|
+
nulling +
|
|
284
|
+
default
|
|
285
|
+
if !first_col
|
|
286
|
+
create_col_string = ",\n #{create_col_string}"
|
|
287
|
+
else
|
|
288
|
+
create_col_string = " #{create_col_string}"
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
definition << create_col_string
|
|
292
|
+
|
|
293
|
+
first_col = false
|
|
294
|
+
end
|
|
295
|
+
definition << ");\n\n"
|
|
296
|
+
end
|
|
297
|
+
definition
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Support for removing columns added via derby bug issue:
|
|
301
|
+
# https://issues.apache.org/jira/browse/DERBY-1489
|
|
302
|
+
#
|
|
303
|
+
# This feature has not made it into a formal release and is not in Java 6.
|
|
304
|
+
# If the normal strategy fails we fall back on a strategy by creating a new
|
|
305
|
+
# table without the new column and there after moving the data to the new
|
|
306
|
+
#
|
|
307
|
+
def remove_column(table_name, column_name)
|
|
308
|
+
begin
|
|
309
|
+
execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name} RESTRICT"
|
|
310
|
+
rescue
|
|
311
|
+
alter_table(table_name) do |definition|
|
|
312
|
+
definition.columns.delete(definition[column_name])
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Notes about changing in Derby:
|
|
318
|
+
# http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
|
|
319
|
+
#
|
|
320
|
+
# We support changing columns using the strategy outlined in:
|
|
321
|
+
# https://issues.apache.org/jira/browse/DERBY-1515
|
|
322
|
+
#
|
|
323
|
+
# This feature has not made it into a formal release and is not in Java 6. We will
|
|
324
|
+
# need to conditionally support this somehow (supposed to arrive for 10.3.0.0)
|
|
325
|
+
def change_column(table_name, column_name, type, options = {})
|
|
326
|
+
# null/not nulling is easy, handle that separately
|
|
327
|
+
if options.include?(:null)
|
|
328
|
+
# This seems to only work with 10.2 of Derby
|
|
329
|
+
if options.delete(:null) == false
|
|
330
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NOT NULL"
|
|
331
|
+
else
|
|
332
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NULL"
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# anything left to do?
|
|
337
|
+
unless options.empty?
|
|
338
|
+
begin
|
|
339
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
|
|
340
|
+
rescue
|
|
341
|
+
transaction do
|
|
342
|
+
temp_new_column_name = "#{column_name}_newtype"
|
|
343
|
+
# 1) ALTER TABLE t ADD COLUMN c1_newtype NEWTYPE;
|
|
344
|
+
add_column table_name, temp_new_column_name, type, options
|
|
345
|
+
# 2) UPDATE t SET c1_newtype = c1;
|
|
346
|
+
execute "UPDATE #{table_name} SET #{temp_new_column_name} = CAST(#{column_name} AS #{type_to_sql(type, options[:limit])})"
|
|
347
|
+
# 3) ALTER TABLE t DROP COLUMN c1;
|
|
348
|
+
remove_column table_name, column_name
|
|
349
|
+
# 4) ALTER TABLE t RENAME COLUMN c1_newtype to c1;
|
|
350
|
+
rename_column table_name, temp_new_column_name, column_name
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Support for renaming columns:
|
|
357
|
+
# https://issues.apache.org/jira/browse/DERBY-1490
|
|
358
|
+
#
|
|
359
|
+
# This feature is expect to arrive in version 10.3.0.0:
|
|
360
|
+
# http://wiki.apache.org/db-derby/DerbyTenThreeRelease)
|
|
361
|
+
#
|
|
362
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
|
363
|
+
begin
|
|
364
|
+
execute "ALTER TABLE #{table_name} ALTER RENAME COLUMN #{column_name} TO #{new_column_name}"
|
|
365
|
+
rescue
|
|
366
|
+
alter_table(table_name, :rename => {column_name => new_column_name})
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def primary_keys(table_name)
|
|
371
|
+
@connection.primary_keys table_name.to_s.upcase
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def columns(table_name, name=nil)
|
|
375
|
+
@connection.columns_internal(table_name.to_s, name, derby_schema)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def tables
|
|
379
|
+
@connection.tables(nil, derby_schema)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def recreate_database(db_name)
|
|
383
|
+
tables.each do |t|
|
|
384
|
+
drop_table t
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# For DDL it appears you can quote "" column names, but in queries (like insert it errors out?)
|
|
389
|
+
def quote_column_name(name) #:nodoc:
|
|
390
|
+
name = name.to_s
|
|
391
|
+
if /^(references|integer|key|group|year)$/i =~ name
|
|
392
|
+
%Q{"#{name.upcase}"}
|
|
393
|
+
elsif /[A-Z]/ =~ name && /[a-z]/ =~ name
|
|
394
|
+
%Q{"#{name}"}
|
|
395
|
+
elsif name =~ /[\s-]/
|
|
396
|
+
%Q{"#{name.upcase}"}
|
|
397
|
+
elsif name =~ /^[_\d]/
|
|
398
|
+
%Q{"#{name.upcase}"}
|
|
399
|
+
else
|
|
400
|
+
name
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def quoted_true
|
|
405
|
+
'1'
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def quoted_false
|
|
409
|
+
'0'
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def add_limit_offset!(sql, options) #:nodoc:
|
|
413
|
+
if options[:offset]
|
|
414
|
+
sql << " OFFSET #{options[:offset]} ROWS"
|
|
415
|
+
end
|
|
416
|
+
if options[:limit]
|
|
417
|
+
#ROWS/ROW and FIRST/NEXT mean the same
|
|
418
|
+
sql << " FETCH FIRST #{options[:limit]} ROWS ONLY"
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
private
|
|
423
|
+
# Derby appears to define schemas using the username
|
|
424
|
+
def derby_schema
|
|
425
|
+
@config[:username].to_s
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module ::JdbcSpec
|
|
2
|
+
module FireBird
|
|
3
|
+
def self.adapter_matcher(name, *)
|
|
4
|
+
name =~ /firebird/i ? self : false
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def modify_types(tp)
|
|
8
|
+
tp[:primary_key] = 'INTEGER NOT NULL PRIMARY KEY'
|
|
9
|
+
tp[:string][:limit] = 252
|
|
10
|
+
tp[:integer][:limit] = nil
|
|
11
|
+
tp
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) # :nodoc:
|
|
15
|
+
execute(sql, name)
|
|
16
|
+
id_value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def add_limit_offset!(sql, options) # :nodoc:
|
|
20
|
+
if options[:limit]
|
|
21
|
+
limit_string = "FIRST #{options[:limit]}"
|
|
22
|
+
limit_string << " SKIP #{options[:offset]}" if options[:offset]
|
|
23
|
+
sql.sub!(/\A(\s*SELECT\s)/i, '\&' + limit_string + ' ')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def prefetch_primary_key?(table_name = nil)
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def default_sequence_name(table_name, primary_key) # :nodoc:
|
|
32
|
+
"#{table_name}_seq"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def next_sequence_value(sequence_name)
|
|
36
|
+
select_one("SELECT GEN_ID(#{sequence_name}, 1 ) FROM RDB$DATABASE;")["gen_id"]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_table(name, options = {}) #:nodoc:
|
|
40
|
+
super(name, options)
|
|
41
|
+
execute "CREATE GENERATOR #{name}_seq"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def rename_table(name, new_name) #:nodoc:
|
|
45
|
+
execute "RENAME #{name} TO #{new_name}"
|
|
46
|
+
execute "UPDATE RDB$GENERATORS SET RDB$GENERATOR_NAME='#{new_name}_seq' WHERE RDB$GENERATOR_NAME='#{name}_seq'" rescue nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def drop_table(name, options = {}) #:nodoc:
|
|
50
|
+
super(name)
|
|
51
|
+
execute "DROP GENERATOR #{name}_seq" rescue nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
|
55
|
+
execute "ALTER TABLE #{table_name} ALTER #{column_name} TYPE #{type_to_sql(type, options[:limit])}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def rename_column(table_name, column_name, new_column_name)
|
|
59
|
+
execute "ALTER TABLE #{table_name} ALTER #{column_name} TO #{new_column_name}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def remove_index(table_name, options) #:nodoc:
|
|
63
|
+
execute "DROP INDEX #{index_name(table_name, options)}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def quote(value, column = nil) # :nodoc:
|
|
67
|
+
return value.quoted_id if value.respond_to?(:quoted_id)
|
|
68
|
+
|
|
69
|
+
if [Time, DateTime].include?(value.class)
|
|
70
|
+
"CAST('#{value.strftime("%Y-%m-%d %H:%M:%S")}' AS TIMESTAMP)"
|
|
71
|
+
else
|
|
72
|
+
if column && column.type == :primary_key
|
|
73
|
+
return value.to_s
|
|
74
|
+
end
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def quote_string(string) # :nodoc:
|
|
80
|
+
string.gsub(/'/, "''")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def quote_column_name(column_name) # :nodoc:
|
|
84
|
+
%Q("#{ar_to_fb_case(column_name)}")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def quoted_true # :nodoc:
|
|
88
|
+
quote(1)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def quoted_false # :nodoc:
|
|
92
|
+
quote(0)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
# Maps uppercase Firebird column names to lowercase for ActiveRecord;
|
|
98
|
+
# mixed-case columns retain their original case.
|
|
99
|
+
def fb_to_ar_case(column_name)
|
|
100
|
+
column_name =~ /[[:lower:]]/ ? column_name : column_name.to_s.downcase
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Maps lowercase ActiveRecord column names to uppercase for Fierbird;
|
|
104
|
+
# mixed-case columns retain their original case.
|
|
105
|
+
def ar_to_fb_case(column_name)
|
|
106
|
+
column_name =~ /[[:upper:]]/ ? column_name : column_name.to_s.upcase
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|