ruby-plsql 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,14 +1,14 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'jeweler'
4
- gem 'rspec', "~> 1.3.0"
3
+ group :development do
4
+ gem 'jeweler', '~> 1.8.3'
5
+ gem 'rspec', '~> 2.9'
5
6
 
6
- unless ENV['NO_ACTIVERECORD']
7
- # avoid loading activerecord 3.0 beta
8
- gem 'activerecord', '=2.3.8'
9
- gem 'activerecord-oracle_enhanced-adapter', '=1.3.1'
10
- end
7
+ unless ENV['NO_ACTIVERECORD']
8
+ gem 'activerecord', '~> 3.2.3'
9
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.4.1'
10
+ end
11
11
 
12
- if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
13
- gem 'ruby-oci8', '>=2.0.4'
12
+ # gem 'ruby-oci8', '~> 2.1.0'
13
+ gem 'ruby-oci8', :git => 'git://github.com/kubo/ruby-oci8.git', :platforms => :mri
14
14
  end
data/History.txt CHANGED
@@ -1,3 +1,17 @@
1
+ == 0.5.0 2012-04-16
2
+
3
+ * Improvements
4
+ * Support for ruby-oci8 2.1.0 and ActiveRecord 3.2
5
+ * Tested with Ruby 1.9.3
6
+ * Tests migrated to RSpec 2
7
+ * Use ojdbc6.jar or ojdbc5.jar JDBC drivers when using JRuby
8
+ * Bug fixes
9
+ * Fixed clearing of global temp tables before procedure calls
10
+ * Fixed passing NULL value for CLOB type arguments
11
+ * Fixed procedure call that returns array of records
12
+ * Fixed support for NCHAR and NVARCHAR argument types
13
+ * Accept any ActiveRecord inherited model class for activerecord_class= method
14
+
1
15
  == 0.4.4 2010-10-06
2
16
 
3
17
  * Improvements
data/License.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008-2010 Raimonds Simanovskis
1
+ Copyright (c) 2008-2012 Raimonds Simanovskis
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md ADDED
@@ -0,0 +1,182 @@
1
+ ruby-plsql
2
+ ==========
3
+
4
+ Ruby API for calling Oracle PL/SQL procedures.
5
+
6
+ DESCRIPTION
7
+ -----------
8
+
9
+ ruby-plsql gem provides simple Ruby API for calling Oracle PL/SQL procedures. It could be used both for accessing Oracle PL/SQL API procedures in legacy applications as well as it could be used to create PL/SQL unit tests using Ruby testing libraries.
10
+
11
+ NUMBER, BINARY_INTEGER, PLS_INTEGER, VARCHAR2, NVARCHAR2, CHAR, NCHAR, DATE, TIMESTAMP, CLOB, BLOB, BOOLEAN, PL/SQL RECORD, TABLE, VARRAY, OBJECT and CURSOR types are supported for input and output parameters and return values of PL/SQL procedures and functions.
12
+
13
+ ruby-plsql supports Ruby 1.8.7, 1.9.3 and JRuby 1.6.7 implementations.
14
+
15
+ USAGE
16
+ -----
17
+
18
+ ### Calling PL/SQL functions and procedures:
19
+
20
+ ```ruby
21
+ require "rubygems"
22
+ require "ruby-plsql"
23
+
24
+ plsql.connection = OCI8.new("hr","hr","xe")
25
+
26
+ plsql.test_uppercase('xxx') # => "XXX"
27
+ plsql.test_uppercase(:p_string => 'xxx') # => "XXX"
28
+ plsql.test_copy("abc", nil, nil) # => { :p_to => "abc", :p_to_double => "abcabc" }
29
+ plsql.test_copy(:p_from => "abc", :p_to => nil, :p_to_double => nil)
30
+ # => { :p_to => "abc", :p_to_double => "abcabc" }
31
+ plsql.hr.test_uppercase('xxx') # => "XXX"
32
+ plsql.test_package.test_uppercase('xxx') # => 'XXX'
33
+
34
+ # PL/SQL records or object type parameters should be passed as Hash
35
+ p_employee = { :employee_id => 1, :first_name => 'First', :last_name => 'Last', :hire_date => Time.local(2000,01,31) }
36
+ plsql.test_full_name(p_employee)
37
+
38
+ # TABLE or VARRAY parameters should be passed as Array
39
+ plsql.test_sum([1,2,3,4])
40
+
41
+ # Nested objects or arrays are also supported
42
+ p_employee = { :employee_id => 1, :first_name => 'First', :last_name => 'Last', :hire_date => Time.local(2000,01,31),
43
+ :address => {:street => 'Street', :city => 'City', :country => 'Country'},
44
+ :phones => [{:type => 'mobile', :phone_number => '123456'}, {:type => 'fixed', :phone_number => '654321'}]}
45
+ plsql.test_store_employee(p_employee)
46
+
47
+ # Returned cursor can be fetched
48
+ plsql.test_cursor do |cursor|
49
+ cursor.fetch # => one row from cursor
50
+ cursor.fetch_all # => all rows from cursor
51
+ end
52
+
53
+ plsql.connection.autocommit = false
54
+ plsql.commit
55
+ plsql.rollback
56
+
57
+ plsql.logoff
58
+ ```
59
+
60
+ Look at RSpec tests under spec directory for more usage examples.
61
+
62
+
63
+ ### Table operations:
64
+
65
+ ruby-plsql also provides simple API for select/insert/update/delete table operations (with Sequel-like syntax). This could be useful if ruby-plsql is used without ActiveRecord (e.g. for writing PL/SQL unit tests):
66
+
67
+ ```ruby
68
+ # insert record in table
69
+ employee = { :employee_id => 1, :first_name => 'First', :last_name => 'Last', :hire_date => Time.local(2000,01,31) }
70
+ plsql.employees.insert employee # INSERT INTO employees VALUES (1, 'First', 'Last', ...)
71
+
72
+ # insert many records
73
+ employees = [employee1, employee2, ... ] # array of many Hashes
74
+ plsql.employees.insert employees
75
+
76
+ # insert many records as list of values
77
+ plsql.employees.insert_values [:employee_id, :first_name, :last_name],
78
+ [1, 'First 1', 'Last 1'],
79
+ [2, 'First 2', 'Last 2']
80
+
81
+ # select one record
82
+ plsql.employees.first # SELECT * FROM employees
83
+ # fetch first row => {:employee_id => ..., :first_name => '...', ...}
84
+ plsql.employees.first(:employee_id => 1) # SELECT * FROM employees WHERE employee_id = 1
85
+ plsql.employees.first("WHERE employee_id = 1")
86
+ plsql.employees.first("WHERE employee_id = :employee_id", 1)
87
+
88
+ # select many records
89
+ plsql.employees.all # => [{...}, {...}, ...]
90
+ plsql.employees.all(:order_by => :employee_id)
91
+ plsql.employees.all("WHERE employee_id > :employee_id", 5)
92
+
93
+ # count records
94
+ plsql.employees.count # SELECT COUNT(*) FROM employees
95
+ plsql.employees.count("WHERE employee_id > :employee_id", 5)
96
+
97
+ # update records
98
+ plsql.employees.update(:first_name => 'Second', :where => {:employee_id => 1})
99
+ # UPDATE employees SET first_name = 'Second' WHERE employee_id = 1
100
+
101
+ # delete records
102
+ plsql.employees.delete(:employee_id => 1) # DELETE FROM employees WHERE employee_id = 1
103
+
104
+ # select from sequences
105
+ plsql.employees_seq.nextval # SELECT employees_seq.NEXTVAL FROM dual
106
+ plsql.employees_seq.currval # SELECT employees_seq.CURRVAL FROM dual
107
+
108
+
109
+ ### Usage with Rails:
110
+
111
+ If using with Rails then include in initializer file:
112
+
113
+ ```ruby
114
+ plsql.activerecord_class = ActiveRecord::Base
115
+ ```
116
+
117
+ and then you do not need to specify plsql.connection (this is also safer when ActiveRecord reestablishes connection to database).
118
+
119
+ INSTALLATION
120
+ ------------
121
+
122
+ Install as gem with
123
+
124
+ gem install ruby-plsql
125
+
126
+ or include gem in Gemfile if using bundler.
127
+
128
+ In addition install either ruby-oci8 (for MRI/YARV) or copy Oracle JDBC driver to $JRUBY_HOME/lib (for JRuby).
129
+
130
+ If you are using MRI 1.8 or 1.9 Ruby implementation then you need to install ruby-oci8 gem (version 2.0.x or 2.1.x)
131
+ as well as Oracle client, e.g. [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html).
132
+
133
+ 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:
134
+
135
+ * in `./lib` directory of Rails application and require it manually
136
+ * in some directory which is in `PATH`
137
+ * in `JRUBY_HOME/lib` directory
138
+ * or include path to JDBC driver jar file in Java `CLASSPATH`
139
+
140
+
141
+ LINKS
142
+ -----
143
+
144
+ * Source code: http://github.com/rsim/ruby-plsql
145
+ * Bug reports / Feature requests: http://github.com/rsim/ruby-plsql/issues
146
+ * Discuss at oracle_enhanced adapter group: http://groups.google.com/group/oracle-enhanced
147
+
148
+ CONTRIBUTORS
149
+ ------------
150
+
151
+ * Raimonds Simanovskis
152
+ * Edgars Beigarts
153
+ * Oleh Mykytyuk
154
+ * Wiehann Matthysen
155
+ * Dayle Larson
156
+ * Yasuo Honda
157
+
158
+ LICENSE
159
+ -------
160
+
161
+ (The MIT License)
162
+
163
+ Copyright (c) 2008-2012 Raimonds Simanovskis
164
+
165
+ Permission is hereby granted, free of charge, to any person obtaining
166
+ a copy of this software and associated documentation files (the
167
+ 'Software'), to deal in the Software without restriction, including
168
+ without limitation the rights to use, copy, modify, merge, publish,
169
+ distribute, sublicense, and/or sell copies of the Software, and to
170
+ permit persons to whom the Software is furnished to do so, subject to
171
+ the following conditions:
172
+
173
+ The above copyright notice and this permission notice shall be
174
+ included in all copies or substantial portions of the Software.
175
+
176
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
177
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
178
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
179
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
180
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
181
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
182
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,47 +1,42 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+
2
11
  require 'rake'
3
12
 
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "ruby-plsql"
8
- gem.summary = "Ruby API for calling Oracle PL/SQL procedures."
9
- gem.description = <<-EOS
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ gem.name = "ruby-plsql"
16
+ gem.summary = "Ruby API for calling Oracle PL/SQL procedures."
17
+ gem.description = <<-EOS
10
18
  ruby-plsql gem provides simple Ruby API for calling Oracle PL/SQL procedures.
11
19
  It could be used both for accessing Oracle PL/SQL API procedures in legacy applications
12
20
  as well as it could be used to create PL/SQL unit tests using Ruby testing libraries.
13
21
  EOS
14
- gem.email = "raimonds.simanovskis@gmail.com"
15
- gem.homepage = "http://github.com/rsim/ruby-plsql"
16
- gem.authors = ["Raimonds Simanovskis"]
17
- gem.add_development_dependency "rspec", "~> 1.3.0"
18
- gem.add_development_dependency "activerecord", "= 2.3.8"
19
- gem.add_development_dependency "activerecord-oracle_enhanced-adapter", "~> 1.3.1"
20
- gem.extra_rdoc_files = ['README.rdoc']
21
- end
22
- Jeweler::GemcutterTasks.new
23
- rescue LoadError
24
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ gem.email = "raimonds.simanovskis@gmail.com"
23
+ gem.homepage = "http://github.com/rsim/ruby-plsql"
24
+ gem.authors = ["Raimonds Simanovskis"]
25
+ gem.extra_rdoc_files = ['README.md']
25
26
  end
27
+ Jeweler::RubygemsDotOrgTasks.new
26
28
 
27
- require 'spec/rake/spectask'
28
- Spec::Rake::SpecTask.new(:spec) do |spec|
29
- spec.libs << 'lib' << 'spec'
30
- spec.spec_files = FileList['spec/**/*_spec.rb']
31
- end
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec)
32
31
 
33
- Spec::Rake::SpecTask.new(:rcov) do |spec|
34
- spec.libs << 'lib' << 'spec'
35
- spec.pattern = 'spec/**/*_spec.rb'
36
- spec.rcov = true
37
- spec.rcov_opts = ['--exclude', '/Library,spec/']
32
+ RSpec::Core::RakeTask.new(:rcov) do |t|
33
+ t.rcov = true
34
+ t.rcov_opts = ['--exclude', '/Library,spec/']
38
35
  end
39
36
 
40
- task :spec => :check_dependencies
41
-
42
37
  task :default => :spec
43
38
 
44
- require 'rake/rdoctask'
39
+ require 'rdoc/task'
45
40
  Rake::RDocTask.new do |rdoc|
46
41
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
42
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.4
1
+ 0.5.0
@@ -10,7 +10,7 @@ module PLSQL
10
10
  end
11
11
 
12
12
  def self.create(raw_conn, ar_class = nil) #:nodoc:
13
- if ar_class && !(defined?(::ActiveRecord) && [ar_class, ar_class.superclass].include?(::ActiveRecord::Base))
13
+ if ar_class && !(defined?(::ActiveRecord) && ar_class.ancestors.include?(::ActiveRecord::Base))
14
14
  raise ArgumentError, "Wrong ActiveRecord class"
15
15
  end
16
16
  case driver_type
@@ -2,19 +2,28 @@ begin
2
2
  require "java"
3
3
  require "jruby"
4
4
 
5
- # ojdbc14.jar file should be in JRUBY_HOME/lib or should be in ENV['PATH'] or load path
6
-
7
- ojdbc_jar = "ojdbc14.jar"
5
+ # ojdbc6.jar or ojdbc5.jar file should be in JRUBY_HOME/lib or should be in ENV['PATH'] or load path
6
+
7
+ java_version = java.lang.System.getProperty("java.version")
8
+ ojdbc_jar = if java_version =~ /^1.5/
9
+ "ojdbc5.jar"
10
+ elsif java_version >= '1.6'
11
+ "ojdbc6.jar"
12
+ else
13
+ nil
14
+ end
8
15
 
9
16
  unless ENV_JAVA['java.class.path'] =~ Regexp.new(ojdbc_jar)
10
17
  # On Unix environment variable should be PATH, on Windows it is sometimes Path
11
- env_path = ENV["PATH"] || ENV["Path"] || ''
12
- if ojdbc_jar_path = env_path.split(/[:;]/).concat($LOAD_PATH).find{|d| File.exists?(File.join(d,ojdbc_jar))}
18
+ env_path = (ENV["PATH"] || ENV["Path"] || '').split(/[:;]/)
19
+ # Look for JDBC driver at first in lib subdirectory (application specific JDBC file version)
20
+ # then in Ruby load path and finally in environment PATH
21
+ if ojdbc_jar_path = ['./lib'].concat($LOAD_PATH).concat(env_path).find{|d| File.exists?(File.join(d,ojdbc_jar))}
13
22
  require File.join(ojdbc_jar_path,ojdbc_jar)
14
23
  end
15
24
  end
16
25
 
17
- java.sql.DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
26
+ java.sql.DriverManager.registerDriver Java::oracle.jdbc.OracleDriver.new
18
27
 
19
28
  # set tns_admin property from TNS_ADMIN environment variable
20
29
  if !java.lang.System.get_property("oracle.net.tns_admin") && ENV["TNS_ADMIN"]
@@ -23,10 +32,7 @@ begin
23
32
 
24
33
  rescue LoadError, NameError
25
34
  # JDBC driver is unavailable.
26
- error_message = "ERROR: ruby-plsql could not load Oracle JDBC driver. "+
27
- "Please install ojdbc14.jar library."
28
- STDERR.puts error_message
29
- raise LoadError
35
+ raise LoadError, "ERROR: ruby-plsql could not load Oracle JDBC driver. Please install #{ojdbc_jar || "Oracle JDBC"} library."
30
36
  end
31
37
 
32
38
  module PLSQL
@@ -228,7 +234,9 @@ module PLSQL
228
234
 
229
235
  SQL_TYPE_TO_RUBY_CLASS = {
230
236
  java.sql.Types::CHAR => String,
237
+ java.sql.Types::NCHAR => String,
231
238
  java.sql.Types::VARCHAR => String,
239
+ java.sql.Types::NVARCHAR => String,
232
240
  java.sql.Types::LONGVARCHAR => String,
233
241
  java.sql.Types::NUMERIC => BigDecimal,
234
242
  java.sql.Types::INTEGER => Fixnum,
@@ -389,7 +397,7 @@ module PLSQL
389
397
  clob.setString(1, value)
390
398
  clob
391
399
  else
392
- Java::OracleSql::CLOB.getEmptyCLOB
400
+ nil
393
401
  end
394
402
  when :'Java::OracleSql::BLOB'
395
403
  if value
@@ -397,7 +405,7 @@ module PLSQL
397
405
  blob.setBytes(1, value.to_java_bytes)
398
406
  blob
399
407
  else
400
- Java::OracleSql::BLOB.getEmptyBLOB
408
+ nil
401
409
  end
402
410
  when :'Java::OracleSql::ARRAY'
403
411
  if value
@@ -194,8 +194,7 @@ module PLSQL
194
194
  end
195
195
  when :"OCI8::CLOB", :"OCI8::BLOB"
196
196
  # ruby-oci8 cannot create CLOB/BLOB from ''
197
- value = nil if value == ''
198
- type.new(raw_oci_connection, value)
197
+ value.to_s.length > 0 ? type.new(raw_oci_connection, value) : nil
199
198
  when :"OCI8::Cursor"
200
199
  value && value.raw_cursor
201
200
  else
@@ -52,12 +52,17 @@ module PLSQL
52
52
  when 'NUMBER'
53
53
  precision, scale = metadata[:data_precision], metadata[:data_scale]
54
54
  "NUMBER#{precision ? "(#{precision}#{scale ? ",#{scale}": ""})" : ""}"
55
- when 'VARCHAR2', 'CHAR', 'NVARCHAR2', 'NCHAR'
56
- length = metadata[:data_length]
57
- if length && (char_used = metadata[:char_used])
58
- length = "#{length} #{char_used == 'C' ? 'CHAR' : 'BYTE'}"
55
+ when 'VARCHAR2', 'CHAR'
56
+ length = case metadata[:char_used]
57
+ when 'C' then "#{metadata[:char_length]} CHAR"
58
+ when 'B' then "#{metadata[:data_length]} BYTE"
59
+ else
60
+ metadata[:data_length]
59
61
  end
60
- "#{metadata[:data_type]}#{length ? "(#{length})": ""}"
62
+ "#{metadata[:data_type]}#{length && "(#{length})"}"
63
+ when 'NVARCHAR2', 'NCHAR'
64
+ length = metadata[:char_length]
65
+ "#{metadata[:data_type]}#{length && "(#{length})"}"
61
66
  when 'PL/SQL TABLE', 'TABLE', 'VARRAY', 'OBJECT'
62
67
  metadata[:sql_type_name]
63
68
  else
@@ -87,7 +92,7 @@ module PLSQL
87
92
  @schema.select_all(
88
93
  "SELECT #{subprogram_id_column}, object_name, TO_NUMBER(overload), argument_name, position, data_level,
89
94
  data_type, in_out, data_length, data_precision, data_scale, char_used,
90
- type_owner, type_name, type_subname
95
+ char_length, type_owner, type_name, type_subname
91
96
  FROM all_arguments
92
97
  WHERE object_id = :object_id
93
98
  AND owner = :owner
@@ -98,7 +103,7 @@ module PLSQL
98
103
 
99
104
  subprogram_id, object_name, overload, argument_name, position, data_level,
100
105
  data_type, in_out, data_length, data_precision, data_scale, char_used,
101
- type_owner, type_name, type_subname = r
106
+ char_length, type_owner, type_name, type_subname = r
102
107
 
103
108
  @overloaded ||= !overload.nil?
104
109
  # if not overloaded then store arguments at key 0
@@ -134,6 +139,7 @@ module PLSQL
134
139
  :data_precision => data_precision && data_precision.to_i,
135
140
  :data_scale => data_scale && data_scale.to_i,
136
141
  :char_used => char_used,
142
+ :char_length => char_length && char_length.to_i,
137
143
  :type_owner => type_owner,
138
144
  :type_name => type_name,
139
145
  :type_subname => type_subname,