activerecord-oracle_enhanced-adapter 1.5.6 → 1.6.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.travis/oracle/download.sh +14 -0
  3. data/.travis/oracle/install.sh +31 -0
  4. data/.travis/setup_accounts.sh +9 -0
  5. data/.travis.yml +39 -0
  6. data/Gemfile +8 -8
  7. data/History.md +189 -0
  8. data/README.md +388 -178
  9. data/RUNNING_TESTS.md +11 -6
  10. data/VERSION +1 -1
  11. data/activerecord-oracle_enhanced-adapter.gemspec +29 -26
  12. data/lib/active_record/connection_adapters/{oracle_enhanced_column.rb → oracle_enhanced/column.rb} +14 -63
  13. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +66 -0
  14. data/lib/active_record/connection_adapters/{oracle_enhanced_connection.rb → oracle_enhanced/connection.rb} +2 -2
  15. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +347 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +260 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/dirty.rb +40 -0
  18. data/lib/active_record/connection_adapters/{oracle_enhanced_jdbc_connection.rb → oracle_enhanced/jdbc_connection.rb} +13 -4
  19. data/lib/active_record/connection_adapters/{oracle_enhanced_oci_connection.rb → oracle_enhanced/oci_connection.rb} +11 -5
  20. data/lib/active_record/connection_adapters/{oracle_enhanced_procedures.rb → oracle_enhanced/procedures.rb} +1 -1
  21. data/lib/active_record/connection_adapters/{oracle_enhanced_schema_creation.rb → oracle_enhanced/schema_creation.rb} +34 -35
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +95 -0
  23. data/lib/active_record/connection_adapters/{oracle_enhanced_schema_dumper.rb → oracle_enhanced/schema_dumper.rb} +14 -37
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +562 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +65 -0
  26. data/lib/active_record/connection_adapters/{oracle_enhanced_structure_dump.rb → oracle_enhanced/structure_dump.rb} +63 -14
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +171 -73
  29. data/lib/active_record/oracle_enhanced/type/integer.rb +13 -0
  30. data/lib/active_record/oracle_enhanced/type/raw.rb +13 -0
  31. data/lib/active_record/oracle_enhanced/type/timestamp.rb +11 -0
  32. data/lib/activerecord-oracle_enhanced-adapter.rb +1 -1
  33. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +127 -49
  34. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +46 -5
  35. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +11 -3
  36. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +3 -3
  37. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +151 -78
  38. data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +4 -4
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +10 -16
  40. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -1
  41. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +5 -5
  42. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +65 -181
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +114 -11
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +17 -1
  45. data/spec/spec_config.yaml.template +11 -0
  46. data/spec/spec_helper.rb +31 -12
  47. data/spec/support/alter_system_user_password.sql +2 -0
  48. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  49. metadata +37 -27
  50. data/lib/active_record/connection_adapters/oracle_enhanced_column_dumper.rb +0 -77
  51. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +0 -350
  52. data/lib/active_record/connection_adapters/oracle_enhanced_database_statements.rb +0 -262
  53. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +0 -45
  54. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +0 -197
  55. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +0 -450
  56. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +0 -258
  57. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +0 -1
  58. /data/lib/active_record/connection_adapters/{oracle_enhanced_cpk.rb → oracle_enhanced/cpk.rb} +0 -0
  59. /data/lib/active_record/connection_adapters/{oracle_enhanced_database_tasks.rb → oracle_enhanced/database_tasks.rb} +0 -0
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build Status](https://travis-ci.org/rsim/oracle-enhanced.svg?branch=master)](https://travis-ci.org/rsim/oracle-enhanced)
2
+
1
3
  activerecord-oracle_enhanced-adapter
2
4
  ====================================
3
5
 
@@ -10,24 +12,40 @@ Oracle enhanced ActiveRecord adapter provides Oracle database access from Ruby o
10
12
 
11
13
  INSTALLATION
12
14
  ------------
15
+ ### Rails 4.2
16
+
17
+ Oracle enhanced adapter version 1.6 just supports Rails 4.2 and does not support Rails 4.1 or lower version of Rails.
18
+ When using Ruby on Rails version 4.2 then in Gemfile include
19
+
20
+ ```ruby
21
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.6.0'
22
+ ```
23
+
24
+ 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.
13
25
 
14
- ### Rails 4
26
+ ### Rails 4.0 and 4.1
15
27
 
16
- Oracle enhanced adapter version 1.5 just supports Rails 4 and does not support Rails 3.2 or lower version of Rails.
28
+ 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.
17
29
 
18
- When using Ruby on Rails version 4 then in Gemfile include
30
+ When using Ruby on Rails version 4.0 and 4.1 then in Gemfile include
19
31
 
20
- gem "activerecord-oracle_enhanced-adapter", "~> 1.5.0"
32
+ ```ruby
33
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.5.0'
34
+ ```
21
35
 
22
36
  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.
23
37
 
24
38
  If you would like to use latest adapter version from github then specify
25
39
 
26
- gem 'activerecord-oracle_enhanced-adapter', :git => 'git://github.com/rsim/oracle-enhanced.git'
40
+ ```ruby
41
+ gem 'activerecord-oracle_enhanced-adapter', :git => 'git://github.com/rsim/oracle-enhanced.git'
42
+ ```
27
43
 
28
- If you are using CRuby 1.9.3 or 2.0 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:
44
+ 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:
29
45
 
30
- gem 'ruby-oci8', '~> 2.1.0'
46
+ ```ruby
47
+ gem 'ruby-oci8', '~> 2.1.0'
48
+ ```
31
49
 
32
50
  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:
33
51
 
@@ -38,7 +56,9 @@ If you are using JRuby then you need to download latest [Oracle JDBC driver](htt
38
56
 
39
57
  After specifying necessary gems in Gemfile run
40
58
 
41
- bundle install
59
+ ```bash
60
+ bundle install
61
+ ```
42
62
 
43
63
  to install the adapter (or later run `bundle update` to force updating to latest version).
44
64
 
@@ -46,17 +66,23 @@ to install the adapter (or later run `bundle update` to force updating to latest
46
66
 
47
67
  When using Ruby on Rails version 3 then in Gemfile include
48
68
 
49
- gem 'activerecord-oracle_enhanced-adapter', '~> 1.4.0'
69
+ ```ruby
70
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.4.0'
71
+ ```
50
72
 
51
73
  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.
52
74
 
53
75
  If you would like to use latest adapter version from github then specify
54
76
 
55
- gem 'activerecord-oracle_enhanced-adapter', :git => 'git://github.com/rsim/oracle-enhanced.git'
77
+ ```ruby
78
+ gem 'activerecord-oracle_enhanced-adapter', :git => 'git://github.com/rsim/oracle-enhanced.git'
79
+ ```
56
80
 
57
81
  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:
58
82
 
59
- gem 'ruby-oci8', '~> 2.1.0'
83
+ ```ruby
84
+ gem 'ruby-oci8', '~> 2.1.0'
85
+ ```
60
86
 
61
87
  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:
62
88
 
@@ -67,7 +93,9 @@ If you are using JRuby then you need to download latest [Oracle JDBC driver](htt
67
93
 
68
94
  After specifying necessary gems in Gemfile run
69
95
 
70
- bundle install
96
+ ```bash
97
+ bundle install
98
+ ```
71
99
 
72
100
  to install the adapter (or later run `bundle update` to force updating to latest version).
73
101
 
@@ -75,12 +103,14 @@ to install the adapter (or later run `bundle update` to force updating to latest
75
103
 
76
104
  If you don't use Bundler in Rails 2 application then you need to specify gems in `config/environment.rb`, e.g.
77
105
 
78
- Rails::Initializer.run do |config|
79
- #...
80
- config.gem 'activerecord-oracle_enhanced-adapter', :lib => "active_record/connection_adapters/oracle_enhanced_adapter"
81
- config.gem 'ruby-oci8'
82
- #...
83
- end
106
+ ```ruby
107
+ Rails::Initializer.run do |config|
108
+ # ...
109
+ config.gem 'activerecord-oracle_enhanced-adapter', :lib => 'active_record/connection_adapters/oracle_enhanced_adapter'
110
+ config.gem 'ruby-oci8'
111
+ # ...
112
+ end
113
+ ```
84
114
 
85
115
  But it is recommended to use Bundler for gem version management also for Rails 2.3 applications (search for instructions in Google).
86
116
 
@@ -88,7 +118,9 @@ But it is recommended to use Bundler for gem version management also for Rails 2
88
118
 
89
119
  If you want to use ActiveRecord and Oracle enhanced adapter without Rails and Bundler then install it just as a gem:
90
120
 
91
- gem install activerecord-oracle_enhanced-adapter
121
+ ```bash
122
+ gem install activerecord-oracle_enhanced-adapter
123
+ ```
92
124
 
93
125
  USAGE
94
126
  -----
@@ -97,52 +129,81 @@ USAGE
97
129
 
98
130
  In Rails application `config/database.yml` use oracle_enhanced as adapter name, e.g.
99
131
 
100
- development:
101
- adapter: oracle_enhanced
102
- database: xe
103
- username: user
104
- password: secret
132
+ ```yml
133
+ development:
134
+ adapter: oracle_enhanced
135
+ database: xe
136
+ username: user
137
+ password: secret
138
+ ```
105
139
 
106
140
  If you're connecting to a service name, indicate the service with a
107
141
  leading slash on the database parameter:
108
142
 
109
- development:
110
- adapter: oracle_enhanced
111
- database: /xe
112
- username: user
113
- password: secret
143
+ ```yml
144
+ development:
145
+ adapter: oracle_enhanced
146
+ database: /xe
147
+ username: user
148
+ password: secret
149
+ ```
114
150
 
115
151
  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:
116
152
 
117
- development:
118
- adapter: oracle_enhanced
119
- host: localhost
120
- port: 1521
121
- database: xe
122
- username: user
123
- password: secret
153
+ ```yml
154
+ development:
155
+ adapter: oracle_enhanced
156
+ host: localhost
157
+ port: 1521
158
+ database: xe
159
+ username: user
160
+ password: secret
161
+ ```
124
162
 
125
163
  or you can use Oracle specific format in `database` parameter:
126
164
 
127
- development:
128
- adapter: oracle_enhanced
129
- database: //localhost:1521/xe
130
- username: user
131
- password: secret
165
+ ```yml
166
+ development:
167
+ adapter: oracle_enhanced
168
+ database: //localhost:1521/xe
169
+ username: user
170
+ password: secret
171
+ ```
132
172
 
133
173
  or you can even use Oracle specific TNS connection description:
134
174
 
135
- development:
136
- adapter: oracle_enhanced
137
- database: "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=xe)))"
138
- username: user
139
- password: secret
175
+ ```yml
176
+ development:
177
+ adapter: oracle_enhanced
178
+ database: "(DESCRIPTION=
179
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
180
+ (CONNECT_DATA=(SERVICE_NAME=xe))
181
+ )"
182
+ username: user
183
+ password: secret
184
+ ```
185
+
186
+
187
+ If you choose to specify your database connection via the `DATABASE_URL`
188
+ environment variable, note that the adapter name uses a dash instead of an underscore:
189
+
190
+ ```bash
191
+ DATABASE_URL=oracle-enhanced://localhost/XE
192
+ ```
193
+
194
+ You can also specify a connection string via the `DATABASE_URL`, as long as it doesn't have any whitespace:
195
+
196
+ ```bash
197
+ DATABASE_URL=oracle-enhanced://user:secret@connection-string/(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=xe)))
198
+ ```
140
199
 
141
200
  If you deploy JRuby on Rails application in Java application server that supports JNDI connections then you can specify JNDI connection as well:
142
201
 
143
- development:
144
- adapter: oracle_enhanced
145
- jndi: "jdbc/jndi_connection_name"
202
+ ```yml
203
+ development:
204
+ adapter: oracle_enhanced
205
+ jndi: "jdbc/jndi_connection_name"
206
+ ```
146
207
 
147
208
  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.
148
209
 
@@ -152,22 +213,28 @@ You can find other available database.yml connection parameters in [oracle_enhan
152
213
 
153
214
  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.:
154
215
 
155
- # 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
156
- ENV['TZ'] = 'UTC'
157
-
158
- ActiveSupport.on_load(:active_record) do
159
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
160
- # id columns and columns which end with _id will always be converted to integers
161
- self.emulate_integers_by_column_name = true
162
- # DATE columns which include "date" in name will be converted to Date, otherwise to Time
163
- self.emulate_dates_by_column_name = true
164
- # true and false will be stored as 'Y' and 'N'
165
- self.emulate_booleans_from_strings = true
166
- # start primary key sequences from 1 (and not 10000) and take just one next value in each session
167
- self.default_sequence_start_value = "1 NOCACHE INCREMENT BY 1"
168
- # other settings ...
169
- end
170
- end
216
+ ```ruby
217
+ # 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
218
+ ENV['TZ'] = 'UTC'
219
+
220
+ ActiveSupport.on_load(:active_record) do
221
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
222
+ # id columns and columns which end with _id will always be converted to integers
223
+ self.emulate_integers_by_column_name = true
224
+
225
+ # DATE columns which include "date" in name will be converted to Date, otherwise to Time
226
+ self.emulate_dates_by_column_name = true
227
+
228
+ # true and false will be stored as 'Y' and 'N'
229
+ self.emulate_booleans_from_strings = true
230
+
231
+ # start primary key sequences from 1 (and not 10000) and take just one next value in each session
232
+ self.default_sequence_start_value = "1 NOCACHE INCREMENT BY 1"
233
+
234
+ # other settings ...
235
+ end
236
+ end
237
+ ```
171
238
 
172
239
  In case of Rails 2 application you do not need to use `ActiveSupport.on_load(:active_record) do ... end` around settings code block.
173
240
 
@@ -177,81 +244,108 @@ See other adapter settings in [oracle_enhanced_adapter.rb](http://github.com/rsi
177
244
 
178
245
  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:
179
246
 
180
- class Employee < ActiveRecord::Base
181
- # specify schema and table name
182
- self.table_name = "hr.hr_employees"
183
- # specify primary key name
184
- self.primary_key = "employee_id"
185
- # specify sequence name
186
- self.sequence_name = "hr.hr_employee_s"
187
- # set which DATE columns should be converted to Ruby Date
188
- set_date_columns :hired_on, :birth_date_on
189
- # set which DATE columns should be converted to Ruby Time
190
- set_datetime_columns :last_login_time
191
- # set which VARCHAR2 columns should be converted to true and false
192
- set_boolean_columns :manager, :active
193
- # set which columns should be ignored in ActiveRecord
194
- ignore_table_columns :attribute1, :attribute2
195
- end
247
+ ```ruby
248
+ class Employee < ActiveRecord::Base
249
+ # specify schema and table name
250
+ self.table_name = "hr.hr_employees"
251
+
252
+ # specify primary key name
253
+ self.primary_key = "employee_id"
254
+
255
+ # specify sequence name
256
+ self.sequence_name = "hr.hr_employee_s"
257
+
258
+ # set which DATE columns should be converted to Ruby Date
259
+ set_date_columns :hired_on, :birth_date_on
260
+
261
+ # set which DATE columns should be converted to Ruby Time
262
+ set_datetime_columns :last_login_time
263
+
264
+ # set which VARCHAR2 columns should be converted to true and false
265
+ set_boolean_columns :manager, :active
266
+
267
+ # set which columns should be ignored in ActiveRecord
268
+ ignore_table_columns :attribute1, :attribute2
269
+ end
270
+ ```
196
271
 
197
272
  You can also access remote tables over database link using
198
273
 
199
- self.table_name "hr_employees@db_link"
274
+ ```ruby
275
+ self.table_name "hr_employees@db_link"
276
+ ```
200
277
 
201
278
  Examples for Rails 3.2 and lower version of Rails
202
279
 
203
- class Employee < ActiveRecord::Base
204
- # specify schema and table name
205
- set_table_name "hr.hr_employees"
206
- # specify primary key name
207
- set_primary_key "employee_id"
208
- # specify sequence name
209
- set_sequence_name "hr.hr_employee_s"
210
- # set which DATE columns should be converted to Ruby Date
211
- set_date_columns :hired_on, :birth_date_on
212
- # set which DATE columns should be converted to Ruby Time
213
- set_datetime_columns :last_login_time
214
- # set which VARCHAR2 columns should be converted to true and false
215
- set_boolean_columns :manager, :active
216
- # set which columns should be ignored in ActiveRecord
217
- ignore_table_columns :attribute1, :attribute2
218
- end
280
+ ```ruby
281
+ class Employee < ActiveRecord::Base
282
+ # specify schema and table name
283
+ set_table_name "hr.hr_employees"
284
+
285
+ # specify primary key name
286
+ set_primary_key "employee_id"
287
+
288
+ # specify sequence name
289
+ set_sequence_name "hr.hr_employee_s"
290
+
291
+ # set which DATE columns should be converted to Ruby Date
292
+ set_date_columns :hired_on, :birth_date_on
293
+
294
+ # set which DATE columns should be converted to Ruby Time
295
+ set_datetime_columns :last_login_time
296
+
297
+ # set which VARCHAR2 columns should be converted to true and false
298
+ set_boolean_columns :manager, :active
299
+
300
+ # set which columns should be ignored in ActiveRecord
301
+ ignore_table_columns :attribute1, :attribute2
302
+ end
303
+ ```
219
304
 
220
305
  You can also access remote tables over database link using
221
306
 
222
- set_table_name "hr_employees@db_link"
307
+ ```ruby
308
+ set_table_name "hr_employees@db_link"
309
+ ```
223
310
 
224
311
  ### Custom create, update and delete methods
225
312
 
226
313
  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:
227
314
 
228
- class Employee < ActiveRecord::Base
229
- include ActiveRecord::OracleEnhancedProcedures
230
- # when defining create method then return ID of new record that will be assigned to id attribute of new object
231
- set_create_method do
232
- plsql.employees_pkg.create_employee(
233
- :p_first_name => first_name,
234
- :p_last_name => last_name,
235
- :p_employee_id => nil
236
- )[:p_employee_id]
237
- end
238
- set_update_method do
239
- plsql.employees_pkg.update_employee(
240
- :p_employee_id => id,
241
- :p_first_name => first_name,
242
- :p_last_name => last_name
243
- )
244
- end
245
- set_delete_method do
246
- plsql.employees_pkg.delete_employee(
247
- :p_employee_id => id
248
- )
249
- end
250
- end
315
+ ```ruby
316
+ class Employee < ActiveRecord::Base
317
+ include ActiveRecord::OracleEnhancedProcedures
318
+
319
+ # when defining create method then return ID of new record that will be assigned to id attribute of new object
320
+ set_create_method do
321
+ plsql.employees_pkg.create_employee(
322
+ :p_first_name => first_name,
323
+ :p_last_name => last_name,
324
+ :p_employee_id => nil
325
+ )[:p_employee_id]
326
+ end
327
+
328
+ set_update_method do
329
+ plsql.employees_pkg.update_employee(
330
+ :p_employee_id => id,
331
+ :p_first_name => first_name,
332
+ :p_last_name => last_name
333
+ )
334
+ end
335
+
336
+ set_delete_method do
337
+ plsql.employees_pkg.delete_employee(
338
+ :p_employee_id => id
339
+ )
340
+ end
341
+ end
342
+ ```
251
343
 
252
344
  In addition in `config/initializers/oracle.rb` initializer specify that ruby-plsql should use ActiveRecord database connection:
253
345
 
254
- plsql.activerecord_class = ActiveRecord::Base
346
+ ```ruby
347
+ plsql.activerecord_class = ActiveRecord::Base
348
+ ```
255
349
 
256
350
  ### Oracle CONTEXT index support
257
351
 
@@ -259,60 +353,78 @@ Every edition of Oracle database includes [Oracle Text](http://www.oracle.com/te
259
353
 
260
354
  To create simple single column index create migration with, e.g.
261
355
 
262
- add_context_index :posts, :title
356
+ ```ruby
357
+ add_context_index :posts, :title
358
+ ```
263
359
 
264
360
  and you can remove context index with
265
361
 
266
- remove_context_index :posts, :title
362
+ ```ruby
363
+ remove_context_index :posts, :title
364
+ ```
267
365
 
268
366
  Include in class definition
269
367
 
270
- has_context_index
368
+ ```ruby
369
+ has_context_index
370
+ ```
271
371
 
272
372
  and then you can do full text search with
273
373
 
274
- Post.contains(:title, 'word')
374
+ ```ruby
375
+ Post.contains(:title, 'word')
376
+ ```
275
377
 
276
378
  You can create index on several columns (which will generate additional stored procedure for providing XML document with specified columns to indexer):
277
379
 
278
- add_context_index :posts, [:title, :body]
380
+ ```ruby
381
+ add_context_index :posts, [:title, :body]
382
+ ```
279
383
 
280
384
  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):
281
385
 
282
- Post.contains(:title, 'word')
283
- Post.contains(:title, 'word within title')
284
- Post.contains(:title, 'word within body')
386
+ ```ruby
387
+ Post.contains(:title, 'word')
388
+ Post.contains(:title, 'word within title')
389
+ Post.contains(:title, 'word within body')
390
+ ```
285
391
 
286
392
  See Oracle Text documentation for syntax that you can use in CONTAINS function in SELECT WHERE clause.
287
393
 
288
394
  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):
289
395
 
290
- add_context_index :posts, [:title, :body], :index_column => :all_text, :sync => 'ON COMMIT'
396
+ ```ruby
397
+ add_context_index :posts, [:title, :body], :index_column => :all_text, :sync => 'ON COMMIT'
291
398
 
292
- Post.contains(:all_text, 'word')
399
+ Post.contains(:all_text, 'word')
400
+ ```
293
401
 
294
402
  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.
295
403
 
296
- add_context_index :posts, [:title, :body], :index_column => :all_text,
297
- :sync => 'ON COMMIT', :index_column_trigger_on => [:created_at, :updated_at]
404
+ ```ruby
405
+ add_context_index :posts, [:title, :body], :index_column => :all_text,
406
+ :sync => 'ON COMMIT', :index_column_trigger_on => [:created_at, :updated_at]
407
+ ```
298
408
 
299
409
  And you can even create index on multiple tables by providing SELECT statements which should be used to fetch necessary columns from related tables:
300
410
 
301
- add_context_index :posts,
302
- [:title, :body,
303
- # specify aliases always with AS keyword
304
- "SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id"
305
- ],
306
- :name => 'post_and_comments_index',
307
- :index_column => :all_text,
308
- :index_column_trigger_on => [:updated_at, :comments_count],
309
- :sync => 'ON COMMIT'
310
-
311
- # search in any table columns
312
- Post.contains(:all_text, 'word')
313
- # search in specified column
314
- Post.contains(:all_text, "aaa within title")
315
- Post.contains(:all_text, "bbb within comment_author")
411
+ ```ruby
412
+ add_context_index :posts,
413
+ [:title, :body,
414
+ # specify aliases always with AS keyword
415
+ "SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id"
416
+ ],
417
+ :name => 'post_and_comments_index',
418
+ :index_column => :all_text,
419
+ :index_column_trigger_on => [:updated_at, :comments_count],
420
+ :sync => 'ON COMMIT'
421
+
422
+ # search in any table columns
423
+ Post.contains(:all_text, 'word')
424
+ # search in specified column
425
+ Post.contains(:all_text, "aaa within title")
426
+ Post.contains(:all_text, "bbb within comment_author")
427
+ ```
316
428
 
317
429
  ### Oracle virtual columns support
318
430
 
@@ -321,43 +433,53 @@ They can be used as normal fields in the queries, in the foreign key contstraint
321
433
 
322
434
  To define virtual column you can use `virtual` method in the `create_table` block, providing column expression in the `:as` option:
323
435
 
324
- create_table :mytable do |t|
325
- t.decimal :price, :precision => 15, :scale => 2
326
- t.decimal :quantity, :precision => 15, :scale => 2
327
- t.virtual :amount, :as => 'price * quantity'
328
- end
436
+ ```ruby
437
+ create_table :mytable do |t|
438
+ t.decimal :price, :precision => 15, :scale => 2
439
+ t.decimal :quantity, :precision => 15, :scale => 2
440
+ t.virtual :amount, :as => 'price * quantity'
441
+ end
442
+ ```
329
443
 
330
444
  Oracle tries to predict type of the virtual column, based on its expression but sometimes it is necessary to state type explicitly.
331
445
  This can be done by providing `:type` option to the `virtual` method:
332
446
 
333
- ...
334
- t.virtual :amount_2, :as => 'ROUND(price * quantity,2)', :type => :decimal, :precision => 15, :scale => 2
335
- t.virtual :amount_str, :as => "TO_CHAR(quantity) || ' x ' || TO_CHAR(price) || ' USD = ' || TO_CHAR(quantity*price) || ' USD'",
336
- :type => :string, :limit => 100
337
- ...
447
+ ```ruby
448
+ # ...
449
+ t.virtual :amount_2, :as => 'ROUND(price * quantity,2)', :type => :decimal, :precision => 15, :scale => 2
450
+ t.virtual :amount_str, :as => "TO_CHAR(quantity) || ' x ' || TO_CHAR(price) || ' USD = ' || TO_CHAR(quantity*price) || ' USD'",
451
+ :type => :string, :limit => 100
452
+ # ...
453
+ ```
338
454
 
339
455
  It is possible to add virtual column to existing table:
340
456
 
341
- add_column :mytable, :amount_4, :virtual, :as => 'ROUND(price * quantity,4)', :precision => 38, :scale => 4
457
+ ```ruby
458
+ add_column :mytable, :amount_4, :virtual, :as => 'ROUND(price * quantity,4)', :precision => 38, :scale => 4
459
+ ```
342
460
 
343
461
  You can use the same options here as in the `create_table` `virtual` method.
344
462
 
345
463
  Changing virtual columns is also possible:
346
464
 
347
- change_column :mytable, :amount, :virtual, :as => 'ROUND(price * quantity,0)', :type => :integer
465
+ ```ruby
466
+ change_column :mytable, :amount, :virtual, :as => 'ROUND(price * quantity,0)', :type => :integer
467
+ ```
348
468
 
349
469
  Virtual columns allowed in the foreign key constraints.
350
470
  For example it can be used to force foreign key constraint on polymorphic association:
351
471
 
352
- create_table :comments do |t|
353
- t.string :subject_type
354
- t.integer :subject_id
355
- t.virtual :subject_photo_id, :as => "CASE subject_type WHEN 'Photo' THEN subject_id END"
356
- t.virtual :subject_event_id, :as => "CASE subject_type WHEN 'Event' THEN subject_id END"
357
- end
472
+ ```ruby
473
+ create_table :comments do |t|
474
+ t.string :subject_type
475
+ t.integer :subject_id
476
+ t.virtual :subject_photo_id, :as => "CASE subject_type WHEN 'Photo' THEN subject_id END"
477
+ t.virtual :subject_event_id, :as => "CASE subject_type WHEN 'Event' THEN subject_id END"
478
+ end
358
479
 
359
- add_foreign_key :comments, :photos, :column => :subject_photo_id
360
- add_foreign_key :comments, :events, :column => :subject_event_id
480
+ add_foreign_key :comments, :photos, :column => :subject_photo_id
481
+ add_foreign_key :comments, :events, :column => :subject_event_id
482
+ ```
361
483
 
362
484
  For backward compatibility reasons it is possible to use `:default` option in the `create_table` instead of `:as` option.
363
485
  But this is deprecated and may be removed in the future version.
@@ -373,8 +495,86 @@ There are several additional schema statements and data types available that you
373
495
  * You can add table and column comments with `:comment` option
374
496
  * Default tablespaces can be specified for tables, indexes, clobs and blobs, for example:
375
497
 
376
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
377
- {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
498
+ ```ruby
499
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
500
+ {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
501
+ ```
502
+
503
+ ### Switching to another schema
504
+
505
+ There are some requirements to connect to Oracle database first and switch to another user.
506
+ Oracle enhanced adapter supports schema: option.
507
+
508
+ Note: Oracle enhanced adapter does not take care if the database user specified in username: parameter
509
+ has appropriate privilege to select, insert, update and delete database objects owned by the schema specified in schema: parameter.
510
+
511
+ ```yml
512
+ development:
513
+ adapter: oracle_enhanced
514
+ database: xe
515
+ username: user
516
+ password: secret
517
+ schema: tableowner
518
+ ```
519
+
520
+ ### Timeouts
521
+
522
+ By default, OCI libraries set a connect timeout of 60 seconds (as of v12.0), and do not set a data receive timeout.
523
+
524
+ While this may desirable if you process queries that take several minutes to complete, it may also lead to resource exhaustion if
525
+ connections are teared down improperly during a query, e.g. by misbehaving networking equipment that does not inform both peers of
526
+ connection reset. In this scenario, the OCI libraries will wait indefinitely for data to arrive, thus blocking indefinitely the application
527
+ that initiated the query.
528
+
529
+ You can set a connect timeout, in seconds, using the following TNSNAMES parameters:
530
+
531
+ * `CONNECT_TIMEOUT`
532
+ * `TCP_CONNECT_TIMEOUT`
533
+
534
+ Example setting a 5 seconds connect timeout:
535
+
536
+ ```yml
537
+ development:
538
+ database: "(DESCRIPTION=
539
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
540
+ (CONNECT_TIMEOUT=5)(TCP_CONNECT_TIMEOUT=5)
541
+ (CONNECT_DATA=(SERVICE_NAME=xe))
542
+ )"
543
+ ```
544
+ You should set a timeout value dependant on your network topology, and the time needed to establish a TCP connection with your ORACLE
545
+ server. In real-world scenarios, a value larger than 5 should be avoided.
546
+
547
+ You can set receive and send timeouts, in seconds, using the following TNSNAMES parameters:
548
+
549
+ * `RECV_TIMEOUT` - the maximum time the OCI libraries should wait for data to arrive on the TCP socket. Internally, it is implemented
550
+ through a `setsockopt(s, SOL_SOCKET, SO_RCVTIMEO)`. You should set this value to an integer larger than the server-side execution time
551
+ of your longest-running query.
552
+ * `SEND_TIMEOUT` the maximum time the OCI libraries should wait for write operations to complete on the TCP socket. Internally, it is
553
+ implemented through a `setsockopt(s, SOL_SOCKET, SO_SNDTIMEO)`. Values larger than 5 are a sign of poorly performing network, and as
554
+ such it should be avoided.
555
+
556
+ Example setting a 60 seconds receive timeout and 5 seconds send timeout:
557
+
558
+ ```yml
559
+ development:
560
+ database: "(DESCRIPTION=
561
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
562
+ (RECV_TIMEOUT=60)(SEND_TIMEOUT=5)
563
+ (CONNECT_DATA=(SERVICE_NAME=xe))
564
+ )"
565
+ ```
566
+
567
+ Example setting the above send/recv timeout plus a 5 seconds connect timeout:
568
+
569
+ ```yml
570
+ development:
571
+ database: "(DESCRIPTION=
572
+ (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
573
+ (CONNECT_TIMEOUT=5)(TCP_CONNECT_TIMEOUT=5)
574
+ (RECV_TIMEOUT=60)(SEND_TIMEOUT=5)
575
+ (CONNECT_DATA=(SERVICE_NAME=xe))
576
+ )"
577
+ ```
378
578
 
379
579
  TROUBLESHOOTING
380
580
  ---------------
@@ -395,13 +595,15 @@ Please verify that
395
595
 
396
596
  3. Verify that activerecord-oracle_enhanced-adapter is working from irb
397
597
 
398
- require 'rubygems'
399
- gem 'activerecord'
400
- gem 'activerecord-oracle_enhanced-adapter'
401
- require 'active_record'
402
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced", :database => "database",:username => "user",:password => "password")
598
+ ```ruby
599
+ require 'rubygems'
600
+ gem 'activerecord'
601
+ gem 'activerecord-oracle_enhanced-adapter'
602
+ require 'active_record'
603
+ ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced", :database => "database",:username => "user",:password => "password")
604
+ ```
403
605
 
404
- and see if it is successful (use your correct database, username and password)
606
+ and see if it is successful (use your correct database, username and password)
405
607
 
406
608
  ### What to do if Oracle enhanced adapter is not working with Phusion Passenger?
407
609
 
@@ -420,6 +622,14 @@ When Apache with Phusion Passenger (mod_passenger or previously mod_rails) is us
420
622
  * 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)
421
623
  * 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.
422
624
 
625
+ ### What to do if my application is stuck?
626
+
627
+ 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
628
+ signal, and you are forced to use the KILL signal, then the OCI libraries may be waiting indefinitely for a network read operation to
629
+ complete.
630
+
631
+ See the **Timeouts** section above.
632
+
423
633
  RUNNING TESTS
424
634
  -------------
425
635