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.
Files changed (121) hide show
  1. data/History.txt +248 -0
  2. data/LICENSE.txt +21 -0
  3. data/Manifest.txt +125 -0
  4. data/README.txt +218 -0
  5. data/Rakefile +10 -0
  6. data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
  7. data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
  8. data/lib/active_record/connection_adapters/h2_adapter.rb +13 -0
  9. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
  10. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  11. data/lib/active_record/connection_adapters/jdbc_adapter.rb +640 -0
  12. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +26 -0
  13. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  14. data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
  15. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
  17. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
  18. data/lib/generators/jdbc/jdbc_generator.rb +9 -0
  19. data/lib/jdbc_adapter.rb +27 -0
  20. data/lib/jdbc_adapter/jdbc.rake +121 -0
  21. data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
  22. data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
  23. data/lib/jdbc_adapter/jdbc_db2.rb +203 -0
  24. data/lib/jdbc_adapter/jdbc_derby.rb +430 -0
  25. data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
  26. data/lib/jdbc_adapter/jdbc_hsqldb.rb +218 -0
  27. data/lib/jdbc_adapter/jdbc_informix.rb +147 -0
  28. data/lib/jdbc_adapter/jdbc_mimer.rb +141 -0
  29. data/lib/jdbc_adapter/jdbc_mssql.rb +337 -0
  30. data/lib/jdbc_adapter/jdbc_mysql.rb +236 -0
  31. data/lib/jdbc_adapter/jdbc_oracle.rb +377 -0
  32. data/lib/jdbc_adapter/jdbc_postgre.rb +498 -0
  33. data/lib/jdbc_adapter/jdbc_sqlite3.rb +384 -0
  34. data/lib/jdbc_adapter/jdbc_sybase.rb +50 -0
  35. data/lib/jdbc_adapter/missing_functionality_helper.rb +87 -0
  36. data/lib/jdbc_adapter/rake_tasks.rb +10 -0
  37. data/lib/jdbc_adapter/tsql_helper.rb +60 -0
  38. data/lib/jdbc_adapter/version.rb +5 -0
  39. data/lib/pg.rb +4 -0
  40. data/rails_generators/jdbc_generator.rb +15 -0
  41. data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
  42. data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
  43. data/rakelib/compile.rake +23 -0
  44. data/rakelib/package.rake +90 -0
  45. data/rakelib/rails.rake +41 -0
  46. data/rakelib/test.rake +76 -0
  47. data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +53 -0
  48. data/src/java/jdbc_adapter/JdbcConnectionFactory.java +36 -0
  49. data/src/java/jdbc_adapter/JdbcDerbySpec.java +293 -0
  50. data/src/java/jdbc_adapter/JdbcMySQLSpec.java +134 -0
  51. data/src/java/jdbc_adapter/MssqlRubyJdbcConnection.java +71 -0
  52. data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +55 -0
  53. data/src/java/jdbc_adapter/RubyJdbcConnection.java +1162 -0
  54. data/src/java/jdbc_adapter/SQLBlock.java +27 -0
  55. data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
  56. data/test/abstract_db_create.rb +107 -0
  57. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  58. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  59. data/test/cachedb_simple_test.rb +6 -0
  60. data/test/db/cachedb.rb +9 -0
  61. data/test/db/db2.rb +9 -0
  62. data/test/db/derby.rb +14 -0
  63. data/test/db/h2.rb +11 -0
  64. data/test/db/hsqldb.rb +12 -0
  65. data/test/db/informix.rb +11 -0
  66. data/test/db/jdbc.rb +11 -0
  67. data/test/db/jndi_config.rb +30 -0
  68. data/test/db/logger.rb +3 -0
  69. data/test/db/mssql.rb +9 -0
  70. data/test/db/mysql.rb +10 -0
  71. data/test/db/oracle.rb +34 -0
  72. data/test/db/postgres.rb +9 -0
  73. data/test/db/sqlite3.rb +15 -0
  74. data/test/db2_simple_test.rb +10 -0
  75. data/test/derby_migration_test.rb +21 -0
  76. data/test/derby_multibyte_test.rb +12 -0
  77. data/test/derby_simple_test.rb +21 -0
  78. data/test/generic_jdbc_connection_test.rb +9 -0
  79. data/test/h2_simple_test.rb +6 -0
  80. data/test/has_many_through.rb +79 -0
  81. data/test/helper.rb +5 -0
  82. data/test/hsqldb_simple_test.rb +6 -0
  83. data/test/informix_simple_test.rb +48 -0
  84. data/test/jdbc_adapter/jdbc_db2_test.rb +26 -0
  85. data/test/jdbc_adapter/jdbc_sybase_test.rb +33 -0
  86. data/test/jdbc_common.rb +25 -0
  87. data/test/jndi_callbacks_test.rb +38 -0
  88. data/test/jndi_test.rb +35 -0
  89. data/test/manualTestDatabase.rb +191 -0
  90. data/test/minirunit.rb +109 -0
  91. data/test/minirunit/testConnect.rb +14 -0
  92. data/test/minirunit/testH2.rb +73 -0
  93. data/test/minirunit/testHsqldb.rb +73 -0
  94. data/test/minirunit/testLoadActiveRecord.rb +3 -0
  95. data/test/minirunit/testMysql.rb +83 -0
  96. data/test/minirunit/testRawSelect.rb +24 -0
  97. data/test/models/add_not_null_column_to_table.rb +12 -0
  98. data/test/models/auto_id.rb +18 -0
  99. data/test/models/data_types.rb +28 -0
  100. data/test/models/entry.rb +23 -0
  101. data/test/models/mixed_case.rb +20 -0
  102. data/test/models/reserved_word.rb +18 -0
  103. data/test/models/string_id.rb +18 -0
  104. data/test/models/validates_uniqueness_of_string.rb +19 -0
  105. data/test/mssql_simple_test.rb +6 -0
  106. data/test/mysql_db_create_test.rb +25 -0
  107. data/test/mysql_multibyte_test.rb +10 -0
  108. data/test/mysql_nonstandard_primary_key_test.rb +42 -0
  109. data/test/mysql_simple_test.rb +32 -0
  110. data/test/oracle_simple_test.rb +29 -0
  111. data/test/pick_rails_version.rb +3 -0
  112. data/test/postgres_db_create_test.rb +21 -0
  113. data/test/postgres_mixed_case_test.rb +19 -0
  114. data/test/postgres_nonseq_pkey_test.rb +40 -0
  115. data/test/postgres_reserved_test.rb +22 -0
  116. data/test/postgres_schema_search_path_test.rb +46 -0
  117. data/test/postgres_simple_test.rb +13 -0
  118. data/test/simple.rb +475 -0
  119. data/test/sqlite3_simple_test.rb +233 -0
  120. data/test/sybase_jtds_simple_test.rb +6 -0
  121. 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