activerecord-oracle_enhanced-adapter 8.1.0-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 (78) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1971 -0
  3. data/License.txt +20 -0
  4. data/README.md +947 -0
  5. data/VERSION +1 -0
  6. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +359 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +325 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +629 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +57 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +739 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +886 -0
  29. data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
  30. data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
  31. data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
  32. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  33. data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
  34. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  35. data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
  36. data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
  37. data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
  38. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  39. data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
  40. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  41. data/lib/arel/visitors/oracle.rb +216 -0
  42. data/lib/arel/visitors/oracle12.rb +121 -0
  43. data/lib/arel/visitors/oracle_common.rb +51 -0
  44. data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +40 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
  51. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
  52. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
  53. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
  54. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  55. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
  56. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
  57. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
  58. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
  59. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  60. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
  61. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
  62. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  63. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  64. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
  65. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  66. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
  67. data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
  68. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  69. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  70. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
  71. data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
  72. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
  73. data/spec/spec_config.yaml.template +11 -0
  74. data/spec/spec_helper.rb +225 -0
  75. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  76. data/spec/support/alter_system_user_password.sql +2 -0
  77. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  78. metadata +181 -0
data/README.md ADDED
@@ -0,0 +1,947 @@
1
+ activerecord-oracle_enhanced-adapter
2
+ ====================================
3
+
4
+ Oracle enhanced adapter for ActiveRecord
5
+
6
+ DESCRIPTION
7
+ -----------
8
+
9
+ Oracle enhanced ActiveRecord adapter provides Oracle database access from Ruby on Rails applications. Oracle enhanced adapter can be used from Ruby on Rails versions between 2.3.x and 8.1 and it is working with Oracle database versions 10g and higher
10
+
11
+ INSTALLATION
12
+ ------------
13
+ ### Rails 8.1
14
+
15
+ Oracle enhanced adapter version 8.1 supports Rails 8.1
16
+ When using Ruby on Rails version 8.1 then in Gemfile include
17
+
18
+ ```ruby
19
+ # Use oracle as the database for Active Record
20
+ gem 'activerecord-oracle_enhanced-adapter', '~> 8.1.0'
21
+ ```
22
+
23
+ ### Rails 8.0
24
+
25
+ Oracle enhanced adapter version 8.0 supports Rails 8.0
26
+ When using Ruby on Rails version 8.0 then in Gemfile include
27
+
28
+ ```ruby
29
+ # Use oracle as the database for Active Record
30
+ gem 'activerecord-oracle_enhanced-adapter', '~> 8.0.0'
31
+ ```
32
+
33
+ ### Rails 7.2
34
+
35
+ Oracle enhanced adapter version 7.2 supports Rails 7.2
36
+ When using Ruby on Rails version 7.2 then in Gemfile include
37
+
38
+ ```ruby
39
+ # Use oracle as the database for Active Record
40
+ gem 'activerecord-oracle_enhanced-adapter', '~> 7.2.0'
41
+ ```
42
+
43
+ ### Rails 7.1
44
+
45
+ Oracle enhanced adapter version 7.1 supports Rails 7.1
46
+ When using Ruby on Rails version 7.1 then in Gemfile include
47
+
48
+ ```ruby
49
+ # Use oracle as the database for Active Record
50
+ gem 'activerecord-oracle_enhanced-adapter', '~> 7.1.0'
51
+ ```
52
+
53
+ ### Rails 7.0
54
+
55
+ Oracle enhanced adapter version 7.0 supports Rails 7.0
56
+ When using Ruby on Rails version 7.0 then in Gemfile include
57
+
58
+ ```ruby
59
+ # Use oracle as the database for Active Record
60
+ gem 'activerecord-oracle_enhanced-adapter', '~> 7.0.0'
61
+ ```
62
+
63
+ ### Rails 6.1
64
+
65
+ Oracle enhanced adapter version 6.1 supports Rails 6.1.
66
+ When using Ruby on Rails version 6.1 then in Gemfile include
67
+
68
+ ```ruby
69
+ # Use oracle as the database for Active Record
70
+ gem 'activerecord-oracle_enhanced-adapter', '~> 6.1.0'
71
+ gem 'ruby-oci8' # only for CRuby users
72
+ ```
73
+
74
+ ### Rails 6.0
75
+
76
+ Oracle enhanced adapter version 6.0 supports Rails 6.0.
77
+ When using Ruby on Rails version 6.0 then in Gemfile include
78
+
79
+ ```ruby
80
+ # Use oracle as the database for Active Record
81
+ gem 'activerecord-oracle_enhanced-adapter', '~> 6.0.0'
82
+ gem 'ruby-oci8' # only for CRuby users
83
+ ```
84
+
85
+ ### Rails 5.2
86
+
87
+ Oracle enhanced adapter version 5.2 supports Rails 5.2.
88
+ When using Ruby on Rails version 5.2 then in Gemfile include
89
+
90
+ ```ruby
91
+ # Use oracle as the database for Active Record
92
+ gem 'activerecord-oracle_enhanced-adapter', '~> 5.2.0'
93
+ gem 'ruby-oci8' # only for CRuby users
94
+ ```
95
+
96
+ ### Rails 5.1
97
+
98
+ Oracle enhanced adapter version 1.8 just supports Rails 5.1 and does not support Rails 5.0 or lower version of Rails.
99
+ When using Ruby on Rails version 5.1 then in Gemfile include
100
+
101
+ ```ruby
102
+ # Use oracle as the database for Active Record
103
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.8.0'
104
+ gem 'ruby-oci8' # only for CRuby users
105
+ ```
106
+
107
+ ### Rails 5.0
108
+
109
+ Oracle enhanced adapter version 1.7 just supports Rails 5.0 and does not support Rails 4.2 or lower version of Rails.
110
+ When using Ruby on Rails version 5.0 then in Gemfile include
111
+
112
+ ```ruby
113
+ # Use oracle as the database for Active Record
114
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.7.0'
115
+ gem 'ruby-oci8' # only for CRuby users
116
+ ```
117
+
118
+ ### Rails 4.2
119
+
120
+ Oracle enhanced adapter version 1.6 just supports Rails 4.2 and does not support Rails 4.1 or lower version of Rails.
121
+ When using Ruby on Rails version 4.2 then in Gemfile include
122
+
123
+ ```ruby
124
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.6.0'
125
+ ```
126
+
127
+ where instead of 1.6.0 you can specify any other desired version. It is recommended to specify version with `~>` which means that use specified version or later patch versions (in this example any later 1.6.x version but not 1.7.x version). Oracle enhanced adapter maintains API backwards compatibility during patch version upgrades and therefore it is safe to always upgrade to latest patch version.
128
+
129
+ ### Rails 4.0 and 4.1
130
+
131
+ Oracle enhanced adapter version 1.5 supports Rails 4.0 and 4.1 and does not support Rails 3.2 or lower version of Rails.
132
+
133
+ When using Ruby on Rails version 4.0 and 4.1 then in Gemfile include
134
+
135
+ ```ruby
136
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.5.0'
137
+ ```
138
+
139
+ where instead of 1.5.0 you can specify any other desired version. It is recommended to specify version with `~>` which means that use specified version or later patch versions (in this example any later 1.5.x version but not 1.6.x version). Oracle enhanced adapter maintains API backwards compatibility during patch version upgrades and therefore it is safe to always upgrade to latest patch version.
140
+
141
+ If you would like to use latest adapter version from github then specify
142
+
143
+ ```ruby
144
+ gem 'activerecord-oracle_enhanced-adapter', :git => 'git://github.com/rsim/oracle-enhanced.git'
145
+ ```
146
+
147
+ If you are using CRuby >= 1.9.3 then you need to install ruby-oci8 gem as well as Oracle client, e.g. [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html). Include in Gemfile also ruby-oci8:
148
+
149
+ ```ruby
150
+ gem 'ruby-oci8', '~> 2.1.0'
151
+ ```
152
+
153
+ If you are using JRuby then you need to download latest [Oracle JDBC driver](http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html) - either ojdbc7.jar or ojdbc6.jar for Java 7, ojdbc6.jar for Java 6 or ojdbc5.jar for Java 5. And copy this file to one of these locations:
154
+
155
+ * in `./lib` directory of Rails application
156
+ * in some directory which is in `PATH`
157
+ * in `JRUBY_HOME/lib` directory
158
+ * or include path to JDBC driver jar file in Java `CLASSPATH`
159
+
160
+ After specifying necessary gems in Gemfile run
161
+
162
+ ```bash
163
+ bundle install
164
+ ```
165
+
166
+ to install the adapter (or later run `bundle update` to force updating to latest version).
167
+
168
+ ### Rails 3
169
+
170
+ When using Ruby on Rails version 3 then in Gemfile include
171
+
172
+ ```ruby
173
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.4.0'
174
+ ```
175
+
176
+ where instead of 1.4.0 you can specify any other desired version. It is recommended to specify version with `~>` which means that use specified version or later patch versions (in this example any later 1.4.x version but not 1.5.x version). Oracle enhanced adapter maintains API backwards compatibility during patch version upgrades and therefore it is safe to always upgrade to latest patch version.
177
+
178
+ If you would like to use latest adapter version from github then specify
179
+
180
+ ```ruby
181
+ gem 'activerecord-oracle_enhanced-adapter', :git => 'git://github.com/rsim/oracle-enhanced.git'
182
+ ```
183
+
184
+ If you are using MRI 1.8 or 1.9 Ruby implementation then you need to install ruby-oci8 gem as well as Oracle client, e.g. [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html). Include in Gemfile also ruby-oci8:
185
+
186
+ ```ruby
187
+ gem 'ruby-oci8', '~> 2.1.0'
188
+ ```
189
+
190
+ If you are using JRuby then you need to download latest [Oracle JDBC driver](http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html) - either ojdbc6.jar for Java 6 or ojdbc5.jar for Java 5. And copy this file to one of these locations:
191
+
192
+ * in `./lib` directory of Rails application
193
+ * in some directory which is in `PATH`
194
+ * in `JRUBY_HOME/lib` directory
195
+ * or include path to JDBC driver jar file in Java `CLASSPATH`
196
+
197
+ After specifying necessary gems in Gemfile run
198
+
199
+ ```bash
200
+ bundle install
201
+ ```
202
+
203
+ to install the adapter (or later run `bundle update` to force updating to latest version).
204
+
205
+ ### Rails 2.3
206
+
207
+ If you don't use Bundler in Rails 2 application then you need to specify gems in `config/environment.rb`, e.g.
208
+
209
+ ```ruby
210
+ Rails::Initializer.run do |config|
211
+ # ...
212
+ config.gem 'activerecord-oracle_enhanced-adapter', :lib => 'active_record/connection_adapters/oracle_enhanced_adapter'
213
+ config.gem 'ruby-oci8'
214
+ # ...
215
+ end
216
+ ```
217
+
218
+ But it is recommended to use Bundler for gem version management also for Rails 2.3 applications (search for instructions in Google).
219
+
220
+ ### Without Rails and Bundler
221
+
222
+ If you want to use ActiveRecord and Oracle enhanced adapter without Rails and Bundler then install it just as a gem:
223
+
224
+ ```bash
225
+ gem install activerecord-oracle_enhanced-adapter
226
+ ```
227
+
228
+ USAGE
229
+ -----
230
+
231
+ ### Database connection
232
+
233
+ In Rails application `config/database.yml` use oracle_enhanced as adapter name, e.g.
234
+
235
+ ```yml
236
+ development:
237
+ adapter: oracle_enhanced
238
+ database: xe
239
+ username: user
240
+ password: secret
241
+ ```
242
+
243
+ If you're connecting to a service name, indicate the service with a
244
+ leading slash on the database parameter:
245
+
246
+ ```yml
247
+ development:
248
+ adapter: oracle_enhanced
249
+ database: /xe
250
+ username: user
251
+ password: secret
252
+ ```
253
+
254
+ If `TNS_ADMIN` environment variable is pointing to directory where `tnsnames.ora` file is located then you can use TNS connection name in `database` parameter. Otherwise you can directly specify database host, port (defaults to 1521) and database name in the following way:
255
+
256
+ ```yml
257
+ development:
258
+ adapter: oracle_enhanced
259
+ host: localhost
260
+ port: 1521
261
+ database: xe
262
+ username: user
263
+ password: secret
264
+ ```
265
+
266
+ or you can use Oracle specific format in `database` parameter:
267
+
268
+ ```yml
269
+ development:
270
+ adapter: oracle_enhanced
271
+ database: //localhost:1521/xe
272
+ username: user
273
+ password: secret
274
+ ```
275
+
276
+ or you can even use Oracle specific TNS connection description:
277
+
278
+ ```yml
279
+ development:
280
+ adapter: oracle_enhanced
281
+ database: "(DESCRIPTION=
282
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
283
+ (CONNECT_DATA=(SERVICE_NAME=xe))
284
+ )"
285
+ username: user
286
+ password: secret
287
+ ```
288
+
289
+
290
+ If you choose to specify your database connection via the `DATABASE_URL`
291
+ environment variable, note that the adapter name uses a dash instead of an underscore:
292
+
293
+ ```bash
294
+ DATABASE_URL=oracle-enhanced://localhost/XE
295
+ ```
296
+
297
+ You can also specify a connection string via the `DATABASE_URL`, as long as it doesn't have any whitespace:
298
+
299
+ ```bash
300
+ DATABASE_URL=oracle-enhanced://user:secret@connection-string/(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=xe)))
301
+ ```
302
+
303
+ If you deploy JRuby on Rails application in Java application server that supports JNDI connections then you can specify JNDI connection as well:
304
+
305
+ ```yml
306
+ development:
307
+ adapter: oracle_enhanced
308
+ jndi: "jdbc/jndi_connection_name"
309
+ ```
310
+
311
+ To use jndi with Tomcat you need to set the accessToUnderlyingConnectionAllowed to true property on the pool. See the [Tomcat Documentation](http://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html) for reference.
312
+
313
+ You can find other available database.yml connection parameters in [oracle_enhanced_adapter.rb](http://github.com/rsim/oracle-enhanced/blob/master/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb). There are many NLS settings as well as some other Oracle session settings.
314
+
315
+ ### Adapter settings
316
+
317
+ If you want to change Oracle enhanced adapter default settings then create initializer file e.g. `config/initializers/oracle.rb` specify there necessary defaults, e.g.:
318
+
319
+ ```ruby
320
+ # It is recommended to set time zone in TZ environment variable so that the same timezone will be used by Ruby and by Oracle session
321
+ ENV['TZ'] = 'UTC'
322
+
323
+ ActiveSupport.on_load(:active_record) do
324
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
325
+ # true and false will be stored as 'Y' and 'N'
326
+ self.emulate_booleans_from_strings = true
327
+
328
+ # start primary key sequences from 1 (and not 10000) and take just one next value in each session
329
+ self.default_sequence_start_value = "1 NOCACHE INCREMENT BY 1"
330
+
331
+ # Use old visitor for Oracle 12c database
332
+ self.use_old_oracle_visitor = true
333
+
334
+ # other settings ...
335
+ end
336
+ end
337
+ ```
338
+
339
+ In case of Rails 2 application you do not need to use `ActiveSupport.on_load(:active_record) do ... end` around settings code block.
340
+
341
+ See other adapter settings in [oracle_enhanced_adapter.rb](http://github.com/rsim/oracle-enhanced/blob/master/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb).
342
+
343
+ ### Legacy schema support
344
+
345
+ If you want to put Oracle enhanced adapter on top of existing schema tables then there are several methods how to override ActiveRecord defaults, see example:
346
+
347
+ ```ruby
348
+ class Employee < ActiveRecord::Base
349
+ # specify schema and table name
350
+ self.table_name = "hr.hr_employees"
351
+
352
+ # specify primary key name
353
+ self.primary_key = "employee_id"
354
+
355
+ # specify sequence name
356
+ self.sequence_name = "hr.hr_employee_s"
357
+
358
+ # set which DATE columns should be converted to Ruby Date using ActiveRecord Attribute API
359
+ # Starting from Oracle enhanced adapter 1.7 Oracle `DATE` columns are mapped to Ruby `Date` by default.
360
+ attribute :hired_on, :date
361
+ attribute :birth_date_on, :date
362
+
363
+ # set which DATE columns should be converted to Ruby Time using ActiveRecord Attribute API
364
+ attribute :last_login_time, :datetime
365
+
366
+ # set which VARCHAR2 columns should be converted to true and false using ActiveRecord Attribute API
367
+ attribute :manager, :boolean
368
+ attribute :active, :boolean
369
+
370
+ # set which columns should be ignored in ActiveRecord
371
+ ignore_table_columns :attribute1, :attribute2
372
+ end
373
+ ```
374
+
375
+ You can also access remote tables over database link using
376
+
377
+ ```ruby
378
+ self.table_name "hr_employees@db_link"
379
+ ```
380
+
381
+ Examples for Rails 4.x
382
+
383
+ ```ruby
384
+ class Employee < ActiveRecord::Base
385
+ # specify schema and table name
386
+ self.table_name = "hr.hr_employees"
387
+
388
+ # specify primary key name
389
+ self.primary_key = "employee_id"
390
+
391
+ # specify sequence name
392
+ self.sequence_name = "hr.hr_employee_s"
393
+
394
+ # If you're using Rails 4.2 or earlier you can do this
395
+
396
+ # set which DATE columns should be converted to Ruby Date
397
+ set_date_columns :hired_on, :birth_date_on
398
+
399
+ # set which DATE columns should be converted to Ruby Time
400
+ set_datetime_columns :last_login_time
401
+
402
+ # set which VARCHAR2 columns should be converted to true and false
403
+ set_boolean_columns :manager, :active
404
+
405
+ # set which columns should be ignored in ActiveRecord
406
+ ignore_table_columns :attribute1, :attribute2
407
+ end
408
+ ```
409
+
410
+ Examples for Rails 3.2 and lower version of Rails
411
+
412
+ ```ruby
413
+ class Employee < ActiveRecord::Base
414
+ # specify schema and table name
415
+ set_table_name "hr.hr_employees"
416
+
417
+ # specify primary key name
418
+ set_primary_key "employee_id"
419
+
420
+ # specify sequence name
421
+ set_sequence_name "hr.hr_employee_s"
422
+
423
+ # set which DATE columns should be converted to Ruby Date
424
+ set_date_columns :hired_on, :birth_date_on
425
+
426
+ # set which DATE columns should be converted to Ruby Time
427
+ set_datetime_columns :last_login_time
428
+
429
+ # set which VARCHAR2 columns should be converted to true and false
430
+ set_boolean_columns :manager, :active
431
+
432
+ # set which columns should be ignored in ActiveRecord
433
+ ignore_table_columns :attribute1, :attribute2
434
+ end
435
+ ```
436
+
437
+ You can also access remote tables over database link using
438
+
439
+ ```ruby
440
+ set_table_name "hr_employees@db_link"
441
+ ```
442
+
443
+ ### Custom create, update and delete methods
444
+
445
+ If you have legacy schema and you are not allowed to do direct INSERTs, UPDATEs and DELETEs in legacy schema tables and need to use existing PL/SQL procedures for create, updated, delete operations then you should add `ruby-plsql` gem to your application, include `ActiveRecord::OracleEnhancedProcedures` in your model and then define custom create, update and delete methods, see example:
446
+
447
+ ```ruby
448
+ class Employee < ActiveRecord::Base
449
+ include ActiveRecord::OracleEnhancedProcedures
450
+
451
+ # when defining create method then return ID of new record that will be assigned to id attribute of new object
452
+ set_create_method do
453
+ plsql.employees_pkg.create_employee(
454
+ :p_first_name => first_name,
455
+ :p_last_name => last_name,
456
+ :p_employee_id => nil
457
+ )[:p_employee_id]
458
+ end
459
+
460
+ set_update_method do
461
+ plsql.employees_pkg.update_employee(
462
+ :p_employee_id => id,
463
+ :p_first_name => first_name,
464
+ :p_last_name => last_name
465
+ )
466
+ end
467
+
468
+ set_delete_method do
469
+ plsql.employees_pkg.delete_employee(
470
+ :p_employee_id => id
471
+ )
472
+ end
473
+ end
474
+ ```
475
+
476
+ In addition in `config/initializers/oracle.rb` initializer specify that ruby-plsql should use ActiveRecord database connection:
477
+
478
+ ```ruby
479
+ plsql.activerecord_class = ActiveRecord::Base
480
+ ```
481
+
482
+ ### Oracle CONTEXT index support
483
+
484
+ Every edition of Oracle database includes [Oracle Text](http://www.oracle.com/technology/products/text/index.html) option for free which provides several full text indexing capabilities. Therefore in Oracle database case you don’t need external full text indexing and searching engines which can simplify your application deployment architecture.
485
+
486
+ To create simple single column index create migration with, e.g.
487
+
488
+ ```ruby
489
+ add_context_index :posts, :title
490
+ ```
491
+
492
+ and you can remove context index with
493
+
494
+ ```ruby
495
+ remove_context_index :posts, :title
496
+ ```
497
+
498
+ Include in class definition
499
+
500
+ ```ruby
501
+ has_context_index
502
+ ```
503
+
504
+ and then you can do full text search with
505
+
506
+ ```ruby
507
+ Post.contains(:title, 'word')
508
+ ```
509
+
510
+ You can create index on several columns (which will generate additional stored procedure for providing XML document with specified columns to indexer):
511
+
512
+ ```ruby
513
+ add_context_index :posts, [:title, :body]
514
+ ```
515
+
516
+ And you can search either in all columns or specify in which column you want to search (as first argument you need to specify first column name as this is the column which is referenced during index creation):
517
+
518
+ ```ruby
519
+ Post.contains(:title, 'word')
520
+ Post.contains(:title, 'word within title')
521
+ Post.contains(:title, 'word within body')
522
+ ```
523
+
524
+ See Oracle Text documentation for syntax that you can use in CONTAINS function in SELECT WHERE clause.
525
+
526
+ You can also specify some dummy main column name when creating multiple column index as well as specify to update index automatically after each commit (as otherwise you need to synchronize index manually or schedule periodic update):
527
+
528
+ ```ruby
529
+ add_context_index :posts, [:title, :body], :index_column => :all_text, :sync => 'ON COMMIT'
530
+
531
+ Post.contains(:all_text, 'word')
532
+ ```
533
+
534
+ Or you can specify that index should be updated when specified columns are updated (e.g. in ActiveRecord you can specify to trigger index update when created_at or updated_at columns are updated). Otherwise index is updated only when main index column is updated.
535
+
536
+ ```ruby
537
+ add_context_index :posts, [:title, :body], :index_column => :all_text,
538
+ :sync => 'ON COMMIT', :index_column_trigger_on => [:created_at, :updated_at]
539
+ ```
540
+
541
+ And you can even create index on multiple tables by providing SELECT statements which should be used to fetch necessary columns from related tables:
542
+
543
+ ```ruby
544
+ add_context_index :posts,
545
+ [:title, :body,
546
+ # specify aliases always with AS keyword
547
+ "SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id"
548
+ ],
549
+ :name => 'post_and_comments_index',
550
+ :index_column => :all_text,
551
+ :index_column_trigger_on => [:updated_at, :comments_count],
552
+ :sync => 'ON COMMIT'
553
+
554
+ # search in any table columns
555
+ Post.contains(:all_text, 'word')
556
+ # search in specified column
557
+ Post.contains(:all_text, "aaa within title")
558
+ Post.contains(:all_text, "bbb within comment_author")
559
+ ```
560
+
561
+ Please note that `index_column` must be a real column in your database and it's value will be overridden every time your `index_column_trigger_on` columns are changed. So, _do not use columns with real data as `index_column`_.
562
+
563
+ Index column can be created as:
564
+
565
+ ```ruby
566
+ add_column :posts, :all_text, :string, limit: 2, comment: 'Service column for context search index'
567
+ ```
568
+
569
+ ### Oracle virtual columns support
570
+
571
+ Since version R11G1 Oracle database allows adding computed [Virtual Columns](http://www.oracle-base.com/articles/11g/virtual-columns-11gr1.php) to the table.
572
+ They can be used as normal fields in the queries, in the foreign key contstraints and to partitioning data.
573
+
574
+ To define virtual column you can use `virtual` method in the `create_table` block, providing column expression in the `:as` option:
575
+
576
+ ```ruby
577
+ create_table :mytable do |t|
578
+ t.decimal :price, :precision => 15, :scale => 2
579
+ t.decimal :quantity, :precision => 15, :scale => 2
580
+ t.virtual :amount, :as => 'price * quantity'
581
+ end
582
+ ```
583
+
584
+ Oracle tries to predict type of the virtual column, based on its expression but sometimes it is necessary to state type explicitly.
585
+ This can be done by providing `:type` option to the `virtual` method:
586
+
587
+ ```ruby
588
+ # ...
589
+ t.virtual :amount_2, :as => 'ROUND(price * quantity,2)', :type => :decimal, :precision => 15, :scale => 2
590
+ t.virtual :amount_str, :as => "TO_CHAR(quantity) || ' x ' || TO_CHAR(price) || ' USD = ' || TO_CHAR(quantity*price) || ' USD'",
591
+ :type => :string, :limit => 100
592
+ # ...
593
+ ```
594
+
595
+ It is possible to add virtual column to existing table:
596
+
597
+ ```ruby
598
+ add_column :mytable, :amount_4, :virtual, :as => 'ROUND(price * quantity,4)', :precision => 38, :scale => 4
599
+ ```
600
+
601
+ You can use the same options here as in the `create_table` `virtual` method.
602
+
603
+ Changing virtual columns is also possible:
604
+
605
+ ```ruby
606
+ change_column :mytable, :amount, :virtual, :as => 'ROUND(price * quantity,0)', :type => :integer
607
+ ```
608
+
609
+ Virtual columns allowed in the foreign key constraints.
610
+ For example it can be used to force foreign key constraint on polymorphic association:
611
+
612
+ ```ruby
613
+ create_table :comments do |t|
614
+ t.string :subject_type
615
+ t.integer :subject_id
616
+ t.virtual :subject_photo_id, :as => "CASE subject_type WHEN 'Photo' THEN subject_id END"
617
+ t.virtual :subject_event_id, :as => "CASE subject_type WHEN 'Event' THEN subject_id END"
618
+ end
619
+
620
+ add_foreign_key :comments, :photos, :column => :subject_photo_id
621
+ add_foreign_key :comments, :events, :column => :subject_event_id
622
+ ```
623
+
624
+ For backward compatibility reasons it is possible to use `:default` option in the `create_table` instead of `:as` option.
625
+ But this is deprecated and may be removed in the future version.
626
+
627
+ ### Oracle specific schema statements and data types
628
+
629
+ There are several additional schema statements and data types available that you can use in database migrations:
630
+
631
+ * `add_foreign_key` and `remove_foreign_key` for foreign key definition (and they are also dumped in `db/schema.rb`)
632
+ * `add_synonym` and `remove_synonym` for synonym definition (and they are also dumped in `db/schema.rb`)
633
+ * You can create table with primary key trigger using `:primary_key_trigger => true` option for `create_table`
634
+ * You can define columns with `raw` type which maps to Oracle's `RAW` type
635
+ * You can add table and column comments with `:comment` option
636
+ * Default tablespaces can be specified for tables, indexes, clobs and blobs, for example:
637
+
638
+ ```ruby
639
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
640
+ {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
641
+ ```
642
+
643
+ ### Switching to another schema
644
+
645
+ There are some requirements to connect to Oracle database first and switch to another user.
646
+ Oracle enhanced adapter supports schema: option.
647
+
648
+ Note: Oracle enhanced adapter does not take care if the database user specified in username: parameter
649
+ has appropriate privilege to select, insert, update and delete database objects owned by the schema specified in schema: parameter.
650
+
651
+ ```yml
652
+ development:
653
+ adapter: oracle_enhanced
654
+ database: xe
655
+ username: user
656
+ password: secret
657
+ schema: tableowner
658
+ ```
659
+
660
+ ### Timeouts
661
+
662
+ By default, OCI libraries set a connect timeout of 60 seconds (as of v12.0), and do not set a data receive timeout.
663
+
664
+ While this may desirable if you process queries that take several minutes to complete, it may also lead to resource exhaustion if
665
+ connections are teared down improperly during a query, e.g. by misbehaving networking equipment that does not inform both peers of
666
+ connection reset. In this scenario, the OCI libraries will wait indefinitely for data to arrive, thus blocking indefinitely the application
667
+ that initiated the query.
668
+
669
+ You can set a connect timeout, in seconds, using the following TNSNAMES parameters:
670
+
671
+ * `CONNECT_TIMEOUT`
672
+ * `TCP_CONNECT_TIMEOUT`
673
+
674
+ Example setting a 5 seconds connect timeout:
675
+
676
+ ```yml
677
+ development:
678
+ database: "(DESCRIPTION=
679
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
680
+ (CONNECT_TIMEOUT=5)(TCP_CONNECT_TIMEOUT=5)
681
+ (CONNECT_DATA=(SERVICE_NAME=xe))
682
+ )"
683
+ ```
684
+ You should set a timeout value dependant on your network topology, and the time needed to establish a TCP connection with your ORACLE
685
+ server. In real-world scenarios, a value larger than 5 should be avoided.
686
+
687
+ You can set receive and send timeouts, in seconds, using the following TNSNAMES parameters:
688
+
689
+ * `RECV_TIMEOUT` - the maximum time the OCI libraries should wait for data to arrive on the TCP socket. Internally, it is implemented
690
+ through a `setsockopt(s, SOL_SOCKET, SO_RCVTIMEO)`. You should set this value to an integer larger than the server-side execution time
691
+ of your longest-running query.
692
+ * `SEND_TIMEOUT` the maximum time the OCI libraries should wait for write operations to complete on the TCP socket. Internally, it is
693
+ implemented through a `setsockopt(s, SOL_SOCKET, SO_SNDTIMEO)`. Values larger than 5 are a sign of poorly performing network, and as
694
+ such it should be avoided.
695
+
696
+ Example setting a 60 seconds receive timeout and 5 seconds send timeout:
697
+
698
+ ```yml
699
+ development:
700
+ database: "(DESCRIPTION=
701
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
702
+ (RECV_TIMEOUT=60)(SEND_TIMEOUT=5)
703
+ (CONNECT_DATA=(SERVICE_NAME=xe))
704
+ )"
705
+ ```
706
+
707
+ Example setting the above send/recv timeout plus a 5 seconds connect timeout:
708
+
709
+ ```yml
710
+ development:
711
+ database: "(DESCRIPTION=
712
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
713
+ (CONNECT_TIMEOUT=5)(TCP_CONNECT_TIMEOUT=5)
714
+ (RECV_TIMEOUT=60)(SEND_TIMEOUT=5)
715
+ (CONNECT_DATA=(SERVICE_NAME=xe))
716
+ )"
717
+ ```
718
+
719
+ ### Schema cache
720
+
721
+ `rails db:schema:cache:dump` generates `db/schema_cache.yml` to avoid queries for Oracle database dictionary, which could help your application response time if it takes time to look up database structure.
722
+
723
+ if any database structure changed by migrations, execute `rails db:schema:cache:dump` again and restart Rails server to reflect changes.
724
+
725
+ UPGRADE
726
+ ---------------
727
+ ### Upgrade Rails 5.1 or older version to Rails 5.2
728
+
729
+ * `emulate_booleans_from_strings = true` change
730
+
731
+ `VARCHAR2(1)` sql type is not registered as `Type:Boolean` even if `emulate_booleans_from_strings = true`
732
+
733
+ Configure each model attribute as follows:
734
+
735
+ ```ruby
736
+ class Post < ActiveRecord::Base
737
+ attribute :is_default, :boolean
738
+ end
739
+ ```
740
+
741
+ * Remove `OracleEnhancedAdapter.cache_columns` to use Rails `db:schema:cache:dump`
742
+
743
+ Refer https://github.com/rsim/oracle-enhanced#schema-cache
744
+
745
+ ### Upgrade Rails 5.0 or older version to Rails 5.1
746
+
747
+ If your application gets `ORA-01000: maximum open cursors exceeded`
748
+ after upgrading to Rails 5.1,
749
+ check these two values and configure `open_cursors` parameter value
750
+ at Oracle database instance is larger than `:statement_limit` value at database.yml.
751
+
752
+ * `open_cursors` value at Oracle database instance
753
+
754
+ ```sql
755
+ SQL> select name,value from v$parameter where name = 'open_cursors';
756
+
757
+ NAME
758
+ --------------------------------------------------------------------------------
759
+ VALUE
760
+ --------------------------------------------------------------------------------
761
+ open_cursors
762
+ 1200
763
+
764
+ ```
765
+
766
+ * `:statement_limit` value at database.yml
767
+
768
+ Since Oracle enhanced adapter 1.8.0 this default value changed from 250 to 1000.
769
+
770
+ ### Upgrade Rails 4.2 or older version to Rails 5
771
+
772
+ If your Oracle table columns have been created for Rails `:datetime` attributes in Rails 4.2 or earlier,
773
+ they need to migrate to `:datetime` in Rails 5 using one of two following ways:
774
+
775
+ * Rails migration code example:
776
+ ```ruby
777
+ change_column :posts, :created_at, :datetime
778
+ change_column :posts, :updated_at, :datetime
779
+ ```
780
+
781
+ or
782
+
783
+ * SQL statement example
784
+ ```sql
785
+ ALTER TABLE "POSTS" MODIFY "CREATED_AT" TIMESTAMP
786
+ ALTER TABLE "POSTS" MODIFY "UPDATED_AT" TIMESTAMP
787
+ ```
788
+
789
+ In Rails 5 without running this migration or sql statement,
790
+ these attributes will be handled as Rails `:date` type.
791
+
792
+ TROUBLESHOOTING
793
+ ---------------
794
+
795
+ ### What to do if Oracle enhanced adapter is not working?
796
+
797
+ Please verify that
798
+
799
+ 1. Oracle Instant Client is installed correctly
800
+ Can you connect to database using sqlnet?
801
+
802
+ 2. ruby-oci8 is installed correctly
803
+ Try something like:
804
+
805
+ ruby -rubygems -e "require 'oci8'; OCI8.new('username','password','database').exec('select * from dual') do |r| puts r.join(','); end"
806
+
807
+ to verify that ruby-oci8 is working
808
+
809
+ 3. Verify that activerecord-oracle_enhanced-adapter is working from irb
810
+
811
+ ```ruby
812
+ require 'rubygems'
813
+ gem 'activerecord'
814
+ gem 'activerecord-oracle_enhanced-adapter'
815
+ require 'active_record'
816
+ ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced", :database => "database",:username => "user",:password => "password")
817
+ ```
818
+
819
+ and see if it is successful (use your correct database, username and password)
820
+
821
+ ### What to do if Oracle enhanced adapter is not working with Phusion Passenger?
822
+
823
+ Oracle Instant Client and ruby-oci8 requires that several environment variables are set:
824
+
825
+ * `LD_LIBRARY_PATH` (on Linux) or `DYLD_LIBRARY_PATH` (on Mac) should point to Oracle Instant Client directory (where Oracle client shared libraries are located)
826
+ * `TNS_ADMIN` should point to directory where `tnsnames.ora` file is located
827
+ * `NLS_LANG` should specify which territory and language NLS settings to use and which character set to use (e.g. `"AMERICAN_AMERICA.UTF8"`)
828
+
829
+ If this continues to throw "OCI Library Initialization Error (OCIError)", you might also need
830
+
831
+ * `ORACLE_HOME` set to full Oracle client installation directory
832
+
833
+ When Apache with Phusion Passenger (mod_passenger or previously mod_rails) is used for Rails application deployment then by default Ruby is launched without environment variables that you have set in shell profile scripts (e.g. .profile). Therefore it is necessary to set environment variables in one of the following ways:
834
+
835
+ * Create wrapper script as described in [Phusion blog](http://blog.phusion.nl/2008/12/16/passing-environment-variables-to-ruby-from-phusion-passenger) or [RayApps::Blog](http://blog.rayapps.com/2008/05/21/using-mod_rails-with-rails-applications-on-oracle)
836
+ * Set environment variables in the file which is used by Apache before launching Apache worker processes - on Linux it typically is envvars file (look in apachectl or apache2ctl script where it is looking for envvars file) or /System/Library/LaunchDaemons/org.apache.httpd.plist on Mac OS X. See the following [discussion thread](http://groups.google.com/group/oracle-enhanced/browse_thread/thread/c5f64106569fadd0) for more hints.
837
+
838
+ ### What to do if my application is stuck?
839
+
840
+ If you see established TCP connections that do not exchange data, and you are unable to terminate your application using a TERM or an INT
841
+ signal, and you are forced to use the KILL signal, then the OCI libraries may be waiting indefinitely for a network read operation to
842
+ complete.
843
+
844
+ See the **Timeouts** section above.
845
+
846
+ Development with Devcontainer
847
+ ------------------------------
848
+
849
+ This project includes a devcontainer configuration that provides a complete development environment with Oracle Database and all necessary dependencies pre-configured. The devcontainer supports both x64 and ARM64 architectures.
850
+
851
+ ### Prerequisites
852
+
853
+ - [Docker](https://www.docker.com/get-started) installed and running
854
+ - [VS Code](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
855
+
856
+ ### Getting Started
857
+
858
+ 1. Clone the repository:
859
+ ```bash
860
+ git clone https://github.com/rsim/oracle-enhanced.git
861
+ cd oracle-enhanced
862
+ ```
863
+
864
+ 2. Open the project in VS Code:
865
+ ```bash
866
+ code .
867
+ ```
868
+
869
+ 3. When prompted, click "Reopen in Container" or use the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and select "Dev Containers: Reopen in Container"
870
+
871
+ 4. VS Code will build and start the development environment automatically. This includes:
872
+ - Ruby 3.4
873
+ - Oracle Database Free
874
+ - Oracle Instant Client 23.8
875
+ - All required gems installed via `bundle install`
876
+
877
+ ### What's Included
878
+
879
+ The devcontainer provides:
880
+
881
+ - **Ruby**: 3.4
882
+ - **Oracle Database**: Oracle Database Free (23c)
883
+ - **Oracle Instant Client**: Version 23.8
884
+ - **Database Configuration**:
885
+ - Database: `FREEPDB1`
886
+ - System password: `Oracle18`
887
+ - TNS configuration in `ci/network/admin`
888
+
889
+ ### Database Access
890
+
891
+ The Oracle database is automatically started and configured with:
892
+ - Port: `1521` (forwarded from container)
893
+ - Service Name: `FREEPDB1`
894
+ - System Password: `Oracle18`
895
+ - Test users are created automatically from `spec/support/create_oracle_enhanced_users.sql`
896
+
897
+
898
+ ### Running Tests
899
+
900
+ Once the devcontainer is running, you can run tests directly:
901
+
902
+ ```bash
903
+ # Run all tests
904
+ bundle exec rspec
905
+
906
+ # Run specific test files
907
+ bundle exec rspec spec/test_file_spec.rb
908
+ ```
909
+
910
+ RUNNING TESTS
911
+ -------------
912
+
913
+ See [RUNNING_TESTS.md](https://github.com/rsim/oracle-enhanced/blob/master/RUNNING_TESTS.md) for information how to set up environment and run Oracle enhanced adapter unit tests.
914
+
915
+ LINKS
916
+ -----
917
+
918
+ * Source code: http://github.com/rsim/oracle-enhanced
919
+ * Bug reports / Feature requests / Pull requests: http://github.com/rsim/oracle-enhanced/issues
920
+ * Discuss at Oracle enhanced adapter group: http://groups.google.com/group/oracle-enhanced
921
+ * Blog posts about Oracle enhanced adapter can be found at http://blog.rayapps.com/category/oracle_enhanced
922
+
923
+ LICENSE
924
+ -------
925
+
926
+ (The MIT License)
927
+
928
+ Copyright (c) 2008-2011 Graham Jenkins, Michael Schoen, Raimonds Simanovskis
929
+
930
+ Permission is hereby granted, free of charge, to any person obtaining
931
+ a copy of this software and associated documentation files (the
932
+ 'Software'), to deal in the Software without restriction, including
933
+ without limitation the rights to use, copy, modify, merge, publish,
934
+ distribute, sublicense, and/or sell copies of the Software, and to
935
+ permit persons to whom the Software is furnished to do so, subject to
936
+ the following conditions:
937
+
938
+ The above copyright notice and this permission notice shall be
939
+ included in all copies or substantial portions of the Software.
940
+
941
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
942
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
943
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
944
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
945
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
946
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
947
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.