<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -115,13 +115,18 @@ module PLSQL
       end
 
       def bind_param(arg, value, metadata)
-        type, length = @connection.plsql_to_ruby_data_type(metadata[:data_type], metadata[:data_length])
-        ora_value = @connection.ruby_value_to_ora_value(value, type)
-        @connection.set_bind_variable(@statement, arg, ora_value, type, length)
+        type, length = @connection.plsql_to_ruby_data_type(metadata)
+        ora_value = @connection.ruby_value_to_ora_value(value, type, metadata)
+        @connection.set_bind_variable(@statement, arg, ora_value, type, length, metadata)
         if metadata[:in_out] =~ /OUT/
           @out_types[arg] = type || ora_value.class
           @out_index[arg] = bind_param_index(arg)
-          @statement.registerOutParameter(@out_index[arg],@connection.get_java_sql_type(ora_value,type))
+          if metadata[:data_type] == 'TABLE'
+            @statement.registerOutParameter(@out_index[arg], @connection.get_java_sql_type(ora_value,type), 
+              metadata[:sql_type_name])
+          else
+            @statement.registerOutParameter(@out_index[arg],@connection.get_java_sql_type(ora_value,type))
+          end
         end
       end
       
@@ -186,12 +191,14 @@ module PLSQL
         java.sql.Types::DATE
       when 'DateTime'
         java.sql.Types::DATE
+      when 'Java::OracleSql::ARRAY'
+        Java::oracle.jdbc.OracleTypes::ARRAY
       else
         java.sql.Types::VARCHAR
       end
     end
 
-    def set_bind_variable(stmt, i, value, type=nil, length=nil)
+    def set_bind_variable(stmt, i, value, type=nil, length=nil, metadata={})
       key = i.kind_of?(Integer) ? nil : i.to_s.gsub(':','')
       case !value.nil? &amp;&amp; type ? type.to_s : value.class.to_s
       when 'Fixnum', 'Bignum', 'Integer'
@@ -209,7 +216,14 @@ module PLSQL
       when 'Date', 'Time', 'DateTime'
         stmt.send(&quot;setDATE#{key &amp;&amp; &quot;AtName&quot;}&quot;, key || i, Java::oracle.sql.DATE.new(value.strftime(&quot;%Y-%m-%d %H:%M:%S&quot;)))
       when 'NilClass'
-        stmt.send(&quot;setNull#{key &amp;&amp; &quot;AtName&quot;}&quot;, key || i, get_java_sql_type(value, type))
+        if metadata[:data_type] == 'TABLE'
+          stmt.send(&quot;setNull#{key &amp;&amp; &quot;AtName&quot;}&quot;, key || i, get_java_sql_type(value, type),
+            metadata[:sql_type_name])
+        else
+          stmt.send(&quot;setNull#{key &amp;&amp; &quot;AtName&quot;}&quot;, key || i, get_java_sql_type(value, type))
+        end
+      when 'Java::OracleSql::ARRAY'
+        stmt.send(&quot;setARRAY#{key &amp;&amp; &quot;AtName&quot;}&quot;, key || i, value)
       end
     end
     
@@ -236,6 +250,8 @@ module PLSQL
         else
           nil
         end
+      when 'Java::OracleSql::ARRAY'
+        stmt.getArray(i)
       end
     end
 
@@ -273,7 +289,8 @@ module PLSQL
       end
     end
     
-    def plsql_to_ruby_data_type(data_type, data_length)
+    def plsql_to_ruby_data_type(metadata)
+      data_type, data_length = metadata[:data_type], metadata[:data_length]
       case data_type
       when &quot;VARCHAR2&quot;
         [String, data_length || 32767]
@@ -287,12 +304,14 @@ module PLSQL
         [Time, nil]
       when &quot;TIMESTAMP&quot;
         [Time, nil]
+      when &quot;TABLE&quot;
+        [Java::OracleSql::ARRAY, nil]
       else
         [String, 32767]
       end
     end
 
-    def ruby_value_to_ora_value(val, type)
+    def ruby_value_to_ora_value(val, type, metadata={})
       if type == BigDecimal
         case val
         when NilClass, Fixnum, BigDecimal
@@ -329,6 +348,11 @@ module PLSQL
         else
           Java::OracleSql::BLOB.getEmptyBLOB
         end
+      elsif type == Java::OracleSql::ARRAY
+        if val
+          descriptor = Java::OracleSql::ArrayDescriptor.createDescriptor(metadata[:sql_type_name], raw_connection)
+          Java::OracleSql::ARRAY.new(descriptor, raw_connection, val.to_java)
+        end
       else
         val
       end
@@ -338,6 +362,8 @@ module PLSQL
       case val
       when Float, BigDecimal
         ora_number_to_ruby_number(val)
+      when Java::JavaMath::BigDecimal
+        val &amp;&amp; ora_number_to_ruby_number(BigDecimal.new(val.to_s))
       when Java::OracleSql::CLOB
         if val.isEmptyLob
           nil
@@ -350,6 +376,8 @@ module PLSQL
         else
           String.from_java_bytes(val.getBytes(1, val.length))
         end
+      when Java::OracleSql::ARRAY
+        val.getArray.map{|e| ora_value_to_ruby_value(e)}
       else
         val
       end</diff>
      <filename>lib/plsql/jdbc_connection.rb</filename>
    </modified>
    <modified>
      <diff>@@ -73,7 +73,7 @@ module PLSQL
       end
 
       def bind_param(arg, value, metadata)
-        type, length = @connection.plsql_to_ruby_data_type(metadata[:data_type], metadata[:data_length])
+        type, length = @connection.plsql_to_ruby_data_type(metadata)
         ora_value = @connection.ruby_value_to_ora_value(value, type)
         @raw_cursor.bind_param(arg, ora_value, type, length)
       end
@@ -96,7 +96,8 @@ module PLSQL
       Cursor.new(sql, self)
     end
 
-    def plsql_to_ruby_data_type(data_type, data_length)
+    def plsql_to_ruby_data_type(metadata)
+      data_type, data_length = metadata[:data_type], metadata[:data_length]
       case data_type
       when &quot;VARCHAR2&quot;
         [String, data_length || 32767]
@@ -110,8 +111,11 @@ module PLSQL
         [DateTime, nil]
       when &quot;TIMESTAMP&quot;
         [Time, nil]
-      # CLOB
-      # BLOB
+      when &quot;TABLE&quot;
+        # create Ruby class for collection
+        klass = Class.new(OCI8::Object::Base)
+        klass.set_typename metadata[:sql_type_name]
+        [klass, nil]
       else
         [String, 32767]
       end
@@ -169,6 +173,10 @@ module PLSQL
         else
           nil
         end
+      when OCI8::Object::Base
+        if val.instance_variable_get(:@attributes).is_a? Array
+          val.to_ary.map{|e| ora_value_to_ruby_value(e)}
+        end
       else
         val
       end</diff>
      <filename>lib/plsql/oci_connection.rb</filename>
    </modified>
    <modified>
      <diff>@@ -69,26 +69,30 @@ module PLSQL
         &quot;, @schema_name, @package ? @package : @procedure
       )[0] rescue nil
       num_rows = @schema.connection.select_all(&quot;
-        SELECT a.argument_name, a.position, a.sequence, a.data_level,
-              a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale, a.char_used, a.overload
-        FROM all_arguments a
-        WHERE a.object_id = :object_id
-        AND a.owner = :owner
-        AND a.object_name = :procedure_name
-        AND NVL(a.package_name,'nil') = :package
-        ORDER BY a.overload, a.sequence
+        SELECT overload, argument_name, position, data_level,
+              data_type, in_out, data_length, data_precision, data_scale, char_used,
+              type_owner, type_name, type_subname
+        FROM all_arguments
+        WHERE object_id = :object_id
+        AND owner = :owner
+        AND object_name = :procedure_name
+        AND NVL(package_name,'nil') = :package
+        ORDER BY overload, sequence
         &quot;, object_id, @schema_name, @procedure, @package ? @package : 'nil'
       ) do |r|
 
-        argument_name, position, sequence, data_level,
-            data_type, in_out, data_length, data_precision, data_scale, char_used, overload = r
+        overload, argument_name, position, data_level,
+            data_type, in_out, data_length, data_precision, data_scale, char_used,
+            type_owner, type_name, type_subname = r
 
         @overloaded ||= !overload.nil?
         # if not overloaded then store arguments at key 0
         overload ||= 0
         @arguments[overload] ||= {}
         @return[overload] ||= nil
-        
+
+        raise ArgumentError, &quot;Parameter type definition inside package is not supported, use CREATE TYPE outside package&quot; if type_subname
+
         argument_metadata = {
           :position =&gt; position &amp;&amp; position.to_i,
           :data_type =&gt; data_type,
@@ -96,7 +100,11 @@ module PLSQL
           :data_length =&gt; data_length &amp;&amp; data_length.to_i,
           :data_precision =&gt; data_precision &amp;&amp; data_precision.to_i,
           :data_scale =&gt; data_scale &amp;&amp; data_scale.to_i,
-          :char_used =&gt; char_used
+          :char_used =&gt; char_used,
+          :type_owner =&gt; type_owner,
+          :type_name =&gt; type_name,
+          :type_subname =&gt; type_subname,
+          :sql_type_name =&gt; &quot;#{type_owner}.#{type_name}&quot;
         }
         if composite_type?(data_type)
           case data_type
@@ -116,6 +124,8 @@ module PLSQL
             case previous_level_argument_metadata[data_level - 1][:data_type]
             when 'PL/SQL RECORD'
               previous_level_argument_metadata[data_level - 1][:fields][argument_name.downcase.to_sym] = argument_metadata
+            when 'TABLE'
+              previous_level_argument_metadata[data_level - 1][:element] = argument_metadata
             end
           end
         # if function has return value</diff>
      <filename>lib/plsql/procedure.rb</filename>
    </modified>
    <modified>
      <diff>@@ -44,25 +44,25 @@ describe &quot;Connection&quot; do
   if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
     describe &quot;OCI data type conversions&quot; do
       it &quot;should translate PL/SQL VARCHAR2 to Ruby String&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;VARCHAR2&quot;, 100).should == [String, 100]
-        @conn.plsql_to_ruby_data_type(&quot;VARCHAR2&quot;, nil).should == [String, 32767]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;VARCHAR2&quot;, :data_length =&gt; 100).should == [String, 100]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;VARCHAR2&quot;, :data_length =&gt; nil).should == [String, 32767]
       end
 
       it &quot;should translate PL/SQL CLOB to Ruby String&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;CLOB&quot;, 100_000).should == [OCI8::CLOB, nil]
-        @conn.plsql_to_ruby_data_type(&quot;CLOB&quot;, nil).should == [OCI8::CLOB, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;CLOB&quot;, :data_length =&gt; 100_000).should == [OCI8::CLOB, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;CLOB&quot;, :data_length =&gt; nil).should == [OCI8::CLOB, nil]
       end
 
       it &quot;should translate PL/SQL NUMBER to Ruby OraNumber&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;NUMBER&quot;, 15).should == [OraNumber, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;NUMBER&quot;, :data_length =&gt; 15).should == [OraNumber, nil]
       end
 
       it &quot;should translate PL/SQL DATE to Ruby DateTime&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;DATE&quot;, nil).should == [DateTime, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;DATE&quot;, :data_length =&gt; nil).should == [DateTime, nil]
       end
 
       it &quot;should translate PL/SQL TIMESTAMP to Ruby Time&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;TIMESTAMP&quot;, nil).should == [Time, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;TIMESTAMP&quot;, :data_length =&gt; nil).should == [Time, nil]
       end
 
       it &quot;should not translate Ruby Fixnum when OraNumber type specified&quot; do
@@ -114,20 +114,20 @@ describe &quot;Connection&quot; do
     
     describe &quot;JDBC data type conversions&quot; do
       it &quot;should translate PL/SQL VARCHAR2 to Ruby String&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;VARCHAR2&quot;, 100).should == [String, 100]
-        @conn.plsql_to_ruby_data_type(&quot;VARCHAR2&quot;, nil).should == [String, 32767]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;VARCHAR2&quot;, :data_length =&gt; 100).should == [String, 100]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;VARCHAR2&quot;, :data_length =&gt; nil).should == [String, 32767]
       end
 
       it &quot;should translate PL/SQL NUMBER to Ruby BigDecimal&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;NUMBER&quot;, 15).should == [BigDecimal, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;NUMBER&quot;, :data_length =&gt; 15).should == [BigDecimal, nil]
       end
       
       it &quot;should translate PL/SQL DATE to Ruby DateTime&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;DATE&quot;, nil).should == [Time, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;DATE&quot;, :data_length =&gt; nil).should == [Time, nil]
       end
       
       it &quot;should translate PL/SQL TIMESTAMP to Ruby Time&quot; do
-        @conn.plsql_to_ruby_data_type(&quot;TIMESTAMP&quot;, nil).should == [Time, nil]
+        @conn.plsql_to_ruby_data_type(:data_type =&gt; &quot;TIMESTAMP&quot;, :data_length =&gt; nil).should == [Time, nil]
       end
       
       it &quot;should not translate Ruby Fixnum when BigDecimal type specified&quot; do</diff>
      <filename>spec/plsql/connection_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -681,6 +681,136 @@ describe &quot;Function with boolean parameters&quot; do
 
 end
 
+describe &quot;Function with table parameter&quot; do
+
+  before(:all) do
+    plsql.connection = get_connection
+
+    # Array of numbers
+    plsql.connection.exec &lt;&lt;-SQL
+      CREATE OR REPLACE TYPE t_numbers AS TABLE OF NUMBER(15)
+    SQL
+    plsql.connection.exec &lt;&lt;-SQL
+      CREATE OR REPLACE FUNCTION test_sum (p_numbers IN t_numbers)
+        RETURN NUMBER
+      IS
+        l_sum   NUMBER(15) := 0;
+      BEGIN
+        IF p_numbers.COUNT &gt; 0 THEN
+          FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
+            IF p_numbers.EXISTS(i) THEN
+              l_sum := l_sum + p_numbers(i);
+            END IF;
+          END LOOP;
+          RETURN l_sum;
+        ELSE
+          RETURN NULL;
+        END IF;
+      END;
+    SQL
+
+    plsql.connection.exec &lt;&lt;-SQL
+      CREATE OR REPLACE FUNCTION test_increment(p_numbers IN t_numbers, p_increment_by IN NUMBER DEFAULT 1)
+        RETURN t_numbers
+      IS
+        l_numbers t_numbers := t_numbers();
+      BEGIN
+        FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
+          IF p_numbers.EXISTS(i) THEN
+            l_numbers.EXTEND;
+            l_numbers(i) := p_numbers(i) + p_increment_by;
+          END IF;
+        END LOOP;
+        RETURN l_numbers;
+      END;
+    SQL
+
+    # Array of strings
+    plsql.connection.exec &lt;&lt;-SQL
+      CREATE OR REPLACE TYPE t_strings AS TABLE OF VARCHAR2(4000)
+    SQL
+    plsql.connection.exec &lt;&lt;-SQL
+      CREATE OR REPLACE FUNCTION test_copy_strings(p_strings IN t_strings, x_strings OUT t_strings)
+        RETURN t_strings
+      IS
+      BEGIN
+        x_strings := t_strings();
+        FOR i IN p_strings.FIRST..p_strings.LAST LOOP
+          IF p_strings.EXISTS(i) THEN
+            x_strings.EXTEND;
+            x_strings(i) := p_strings(i);
+          END IF;
+        END LOOP;
+        RETURN x_strings;
+      END;
+    SQL
+
+    # Wrong type definition inside package
+    plsql.connection.exec &lt;&lt;-SQL
+      CREATE OR REPLACE PACKAGE test_collections IS
+        TYPE t_numbers IS TABLE OF NUMBER(15);
+        FUNCTION test_sum (p_numbers IN t_numbers)
+          RETURN NUMBER;
+      END;
+    SQL
+    plsql.connection.exec &lt;&lt;-SQL
+      CREATE OR REPLACE PACKAGE BODY test_collections IS
+        FUNCTION test_sum (p_numbers IN t_numbers)
+        RETURN NUMBER
+        IS
+          l_sum   NUMBER(15) := 0;
+        BEGIN
+          IF p_numbers.COUNT &gt; 0 THEN
+            FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
+              IF p_numbers.EXISTS(i) THEN
+                l_sum := l_sum + p_numbers(i);
+              END IF;
+            END LOOP;
+            RETURN l_sum;
+          ELSE
+            RETURN NULL;
+          END IF;
+        END;
+      END;
+    SQL
+  end
+
+  after(:all) do
+    plsql.connection.exec &quot;DROP FUNCTION test_sum&quot;
+    plsql.connection.exec &quot;DROP FUNCTION test_increment&quot;
+    plsql.connection.exec &quot;DROP FUNCTION test_copy_strings&quot;
+    plsql.connection.exec &quot;DROP PACKAGE test_collections&quot;
+    plsql.connection.exec &quot;DROP TYPE t_numbers&quot;
+    plsql.connection.exec &quot;DROP TYPE t_strings&quot;
+    plsql.logoff
+  end
+
+  it &quot;should find existing function&quot; do
+    PLSQL::Procedure.find(plsql, :test_sum).should_not be_nil
+  end
+
+  it &quot;should execute function with number array parameter&quot; do
+    plsql.test_sum([1,2,3,4]).should == 10
+  end
+
+  it &quot;should return number array return value&quot; do
+    plsql.test_increment([1,2,3,4], 1).should == [2,3,4,5]
+  end
+
+  it &quot;should execute function with string array and return string array output parameter&quot; do
+    pending &quot;ruby-oci8 gives segmentation fault&quot; if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
+    strings = ['1','2','3','4']
+    plsql.test_copy_strings(strings).should == [strings, {:x_strings =&gt; strings}]
+  end
+
+  it &quot;should raise error if parameter type is defined inside package&quot; do
+    lambda do
+      plsql.test_collections.test_sum([1,2,3,4])
+    end.should raise_error(ArgumentError)
+  end
+
+end
+
 describe &quot;Synonym to function&quot; do
   
   before(:all) do</diff>
      <filename>spec/plsql/procedure_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,11 @@ gem &quot;activerecord&quot;
 require &quot;activerecord&quot;
 gem &quot;activerecord-oracle_enhanced-adapter&quot;
 
+if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
+  # gem &quot;ruby-oci8&quot;, &quot;=2.0.2&quot;
+  gem &quot;ruby-oci8&quot;, &quot;=2.0.3&quot;
+end
+
 $:.unshift(File.dirname(__FILE__) + '/../lib')
 
 require &quot;ruby_plsql&quot;</diff>
      <filename>spec/spec_helper.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>5205dca79cd277eb74c9f58d49d3a6052ede91ae</id>
    </parent>
  </parents>
  <author>
    <name>Raimonds Simanovskis</name>
    <email>raimonds.simanovskis@gmail.com</email>
  </author>
  <url>http://github.com/rsim/ruby-plsql/commit/b9894be4a5aea44da568b0e4d7c3154591d804fe</url>
  <id>b9894be4a5aea44da568b0e4d7c3154591d804fe</id>
  <committed-date>2009-11-01T15:00:02-08:00</committed-date>
  <authored-date>2009-11-01T15:00:02-08:00</authored-date>
  <message>initial implementation of PL/SQL collection type (TABLE OF) parameters</message>
  <tree>38874fc77c275a7bbdcc7a9be2c51800c622c3c8</tree>
  <committer>
    <name>Raimonds Simanovskis</name>
    <email>raimonds.simanovskis@gmail.com</email>
  </committer>
</commit>
