[ruby-oci8-commit] [574] trunk/ruby-oci8: Fix undefined method 'char_used?' when OCI8:: Metadata::Argument#inspect is called.

nobody at rubyforge.org nobody at rubyforge.org
Sat Aug 3 13:00:01 UTC 2013


Revision: 574
Author:   kubo
Date:     2013-08-03 13:00:00 +0000 (Sat, 03 Aug 2013)
Log Message:
-----------
Fix undefined method 'char_used?' when OCI8::Metadata::Argument#inspect is called.
Refactor and add OCI8::Metadata testcases.

Modified Paths:
--------------
    trunk/ruby-oci8/ChangeLog
    trunk/ruby-oci8/lib/oci8/metadata.rb
    trunk/ruby-oci8/test/test_metadata.rb
    trunk/ruby-oci8/test/test_package_type.rb

Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog	2013-07-30 06:37:17 UTC (rev 573)
+++ trunk/ruby-oci8/ChangeLog	2013-08-03 13:00:00 UTC (rev 574)
@@ -1,3 +1,9 @@
+2013-08-03  KUBO Takehiro  <kubo at jiubao.org>
+	* lib/oci8/metadata.rb: fix undefined method 'char_used?' when
+	    OCI8::Metadata::Argument#inspect is called.
+	* test/test_metadata.rb: refactor and add tests for #inspect methods.
+	* test/test_package_type.rb: add some test data.
+
 2013-07-30  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/metadata.c, ext/oci8/ocihandle.c, test/test_metadata.rb:
 	    Fix segmentation fault when metadata are accessed after the

Modified: trunk/ruby-oci8/lib/oci8/metadata.rb
===================================================================
--- trunk/ruby-oci8/lib/oci8/metadata.rb	2013-07-30 06:37:17 UTC (rev 573)
+++ trunk/ruby-oci8/lib/oci8/metadata.rb	2013-08-03 13:00:00 UTC (rev 574)
@@ -110,7 +110,7 @@
                           Proc.new do |p|
                             if p.charset_form == :nchar
                               "NVARCHAR2(#{p.char_size})"
-                            elsif p.char_used?
+                            elsif p.respond_to?(:char_used?) && p.char_used?
                               "VARCHAR2(#{p.char_size} CHAR)"
                             else
                               "VARCHAR2(#{p.data_size})"

Modified: trunk/ruby-oci8/test/test_metadata.rb
===================================================================
--- trunk/ruby-oci8/test/test_metadata.rb	2013-07-30 06:37:17 UTC (rev 573)
+++ trunk/ruby-oci8/test/test_metadata.rb	2013-08-03 13:00:00 UTC (rev 574)
@@ -26,577 +26,28 @@
     end
   end
 
-  class DatatypeData
-    @@attributes =
-      [:data_type_string,
-       :data_type,
-       :charset_form,
-       :nullable?,
-       :data_size,
-       :precision,
-       :scale,
-      ]
-    @@attributes +=
-      [
-       :char_used?,
-       :char_size,
-       :fsprecision,
-       :lfprecision,
-      ] if $oracle_version >= OCI8::ORAVER_9_0
+  def to_obj_id(owner_name, object_name)
+    @conn.select_one('select object_id from all_objects where owner = :1 and object_name = :2', owner_name, object_name)[0].to_i
+  end
 
-    @@attributes.each do |attr|
-      define_method attr do
-        @table[attr]
-      end
-    end
+  def check_attributes(msg, obj, attrs)
+    attrs.each do |method, expected_value|
+      next if expected_value == :skip
 
-    def self.attributes
-      @@attributes
-    end
-
-    def initialize(hash = {})
-      @table = hash
-    end
-
-    def available?(conn)
-      return false if $oracle_version < @table[:oraver]
-      if /^(\w+)\.(\w+)$/ =~ @table[:data_type_string]
-        if conn.select_one('select 1 from all_objects where owner = :1 and object_name = :2', $1, $2)
-          true
-        else
-          warn "skip a test for unsupported datatype: #{@table[:data_type_string]}."
-          false
-        end
+      val = method.is_a?(Array) ? obj[method[0]] : obj.send(method)
+      case expected_value
+      when Hash
+        check_attributes("#{msg} > #{method}", val, expected_value)
+      when Proc
+        assert(expected_value.call(val), "#{msg} > #{method}")
+      when Regexp
+        assert_match(expected_value, val, "#{msg} > #{method}")
       else
-        true
+        assert_equal(expected_value, val, "#{msg} > #{method}")
       end
     end
   end
 
-  # Get data_size of NCHAR(1) and that of CHAR(1 CHAR).
-  # They depend on the database character set and the
-  # client character set.
-  conn = OCI8.new($dbuser, $dbpass, $dbname)
-  begin
-    cursor = conn.exec("select N'1' from dual")
-    # cfrm: data_size of NCHAR(1).
-    cfrm = cursor.column_metadata[0].data_size
-    if $oracle_version >=  OCI8::ORAVER_9_0
-      # csem: data_size of CHAR(1 CHAR).
-      cursor = conn.exec("select CAST('1' AS CHAR(1 char)) from dual")
-      csem = cursor.column_metadata[0].data_size
-    else
-      csem = 1
-    end
-  ensure
-    conn.logoff
-  end
-
-  ora80 = OCI8::ORAVER_8_0
-  ora81 = OCI8::ORAVER_8_1
-  ora90 = OCI8::ORAVER_9_0
-  ora101 = OCI8::ORAVER_10_1
-
-  @@column_test_data =
-    [
-     DatatypeData.new(:data_type_string => "CHAR(10) NOT NULL",
-                      :oraver => ora80,
-                      :data_type => :char,
-                      :charset_form => :implicit,
-                      :nullable? => false,
-                      :char_used? => false,
-                      :char_size => 10,
-                      :data_size => 10,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "CHAR(10 CHAR)",
-                      :oraver => ora90,
-                      :data_type => :char,
-                      :charset_form => :implicit,
-                      :nullable? => true,
-                      :char_used? => true,
-                      :char_size => 10,
-                      :data_size => 10 * csem,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "NCHAR(10)",
-                      :oraver => ora80,
-                      :data_type => :char,
-                      :charset_form => :nchar,
-                      :nullable? => true,
-                      :char_used? => true,
-                      :char_size => 10,
-                      :data_size => 10 * cfrm,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "VARCHAR2(10)",
-                      :oraver => ora80,
-                      :data_type => :varchar2,
-                      :charset_form => :implicit,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 10,
-                      :data_size => 10,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "VARCHAR2(10 CHAR)",
-                      :oraver => ora90,
-                      :data_type => :varchar2,
-                      :charset_form => :implicit,
-                      :nullable? => true,
-                      :char_used? => true,
-                      :char_size => 10,
-                      :data_size => 10 * csem,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "NVARCHAR2(10)",
-                      :oraver => ora80,
-                      :data_type => :varchar2,
-                      :charset_form => :nchar,
-                      :nullable? => true,
-                      :char_used? => true,
-                      :char_size => 10,
-                      :data_size => 10 * cfrm,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "RAW(10)",
-                      :oraver => ora80,
-                      :data_type => :raw,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 10,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-
-     # Skip tests for data_size of CLOB, NCLOB and BLOB
-     # because their values depend on how they are described.
-     #
-     #  Oracle 10g XE 10.2.0.1.0 on Linux:
-     #   +----------------+-----------+
-     #   |                | data_size |
-     #   +----------------+-----------+
-     #   | implicitly(*1) |   4000    |
-     #   | explicitly(*2) |     86    |
-     #   +----------------+-----------+
-     #
-     # *1 explicitly described by column definition.
-     # *2 implicitly described by select list.
-     DatatypeData.new(:data_type_string => "CLOB",
-                      :oraver => ora81,
-                      :data_type => :clob,
-                      :charset_form => :implicit,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => :skip,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "NCLOB",
-                      :oraver => ora81,
-                      :data_type => :clob,
-                      :charset_form => :nchar,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => :skip,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "BLOB",
-                      :oraver => ora80,
-                      :data_type => :blob,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => :skip,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "BFILE",
-                      :oraver => ora80,
-                      :data_type => :bfile,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 530,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-
-     # Skip tests for fsprecision and lfprecision for NUMBER and FLOAT
-     # because their values depend on how they are described.
-     #
-     #  Oracle 10g XE 10.2.0.1.0 on Linux:
-     #   +-----------------------------+-------------+-------------+
-     #   |                             | fsprecision | lfprecision |
-     #   +----------------+------------+-------------+-------------+
-     #   | NUMBER         | implicitly |     129     |      0      |
-     #   |                | explicitly |       0     |    129      |
-     #   +----------------+------------+-------------+-------------+
-     #   | NUMBER(10)     | implicitly |       0     |     10      |
-     #   |                | explicitly |      10     |      0      |
-     #   +----------------+------------+-------------+-------------+
-     #   | NUMBER(10,2)   | implicitly |       2     |     10      |
-     #   |                | explicitly |      10     |      2      |
-     #   +----------------+------------+-------------+-------------+
-     #   | FLOAT          | implicitly |     129     |    126      |
-     #   |                | explicitly |     126     |    129      |
-     #   +----------------+------------+-------------+-------------+
-     #   | FLOAT(10)      | implicitly |     129     |     10      |
-     #   |                | explicitly |      10     |    129      |
-     #   +----------------+------------+-------------+-------------+
-     DatatypeData.new(:data_type_string => "NUMBER",
-                      :oraver => ora80,
-                      :data_type => :number,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 22,
-                      :precision => 0,
-                      :scale => $oracle_version > ora90 ? -127 : 0,
-                      :fsprecision => :skip,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "NUMBER(10)",
-                      :oraver => ora80,
-                      :data_type => :number,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 22,
-                      :precision => 10,
-                      :scale => 0,
-                      :fsprecision => :skip,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "NUMBER(10,2)",
-                      :oraver => ora80,
-                      :data_type => :number,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 22,
-                      :precision => 10,
-                      :scale => 2,
-                      :fsprecision => :skip,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "FLOAT",
-                      :oraver => ora80,
-                      :data_type => :number,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 22,
-                      :precision => 126,
-                      :scale => -127,
-                      :fsprecision => :skip,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "FLOAT(10)",
-                      :oraver => ora80,
-                      :data_type => :number,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 22,
-                      :precision => 10,
-                      :scale => -127,
-                      :fsprecision => :skip,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "BINARY_FLOAT",
-                      :oraver => ora101,
-                      :data_type => :binary_float,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 4,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "BINARY_DOUBLE",
-                      :oraver => ora101,
-                      :data_type => :binary_double,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 8,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-     DatatypeData.new(:data_type_string => "DATE",
-                      :oraver => ora80,
-                      :data_type => :date,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 7,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-
-     # Skip tests for precision and lfprecision for TIMESTAMP
-     # because their values depend on how they are described.
-     #
-     #  Oracle 10g XE 10.2.0.1.0 on Linux:
-     #   +------------------------------------------------+-----------+-------------+
-     #   |                                                | precision | lfprecision |
-     #   +-----------------------------------+------------+-----------+-------------+
-     #   | TIMESTAMP                         | implicitly |     0     |      0      |
-     #   |                                   | explicitly |     6     |      6      |
-     #   +-----------------------------------+------------+-----------+-------------+
-     #   | TIMESTAMP(9)                      | implicitly |     0     |      0      |
-     #   |                                   | explicitly |     9     |      9      |
-     #   +-----------------------------------+------------+-----------+-------------+
-     #   | TIMESTAMP WITH TIME ZONE          | implicitly |     0     |      0      |
-     #   |                                   | explicitly |     6     |      6      |
-     #   +-----------------------------------+------------+-----------+-------------+
-     #   | TIMESTAMP(9) WITH TIME ZONE       | implicitly |     0     |      0      |
-     #   |                                   | explicitly |     9     |      9      |
-     #   +-----------------------------------+------------+-----------+-------------+
-     #   | TIMESTAMP WITH LOCAL TIME ZONE    | implicitly |     0     |      0      |
-     #   |                                   | explicitly |     6     |      6      |
-     #   +-----------------------------------+------------+-----------+-------------+
-     #   | TIMESTAMP(9) WITH LOCAL TIME ZONE | implicitly |     0     |      0      |
-     #   |                                   | explicitly |     9     |      9      |
-     #   +-----------------------------------+------------+-----------+-------------+
-     DatatypeData.new(:data_type_string => "TIMESTAMP",
-                      :oraver => ora90,
-                      :data_type => :timestamp,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 11,
-                      :precision => :skip,
-                      :scale => 6,
-                      :fsprecision => 6,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "TIMESTAMP(9)",
-                      :oraver => ora90,
-                      :data_type => :timestamp,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 11,
-                      :precision => :skip,
-                      :scale => 9,
-                      :fsprecision => 9,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "TIMESTAMP WITH TIME ZONE",
-                      :oraver => ora90,
-                      :data_type => :timestamp_tz,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 13,
-                      :precision => :skip,
-                      :scale => 6,
-                      :fsprecision => 6,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "TIMESTAMP(9) WITH TIME ZONE",
-                      :oraver => ora90,
-                      :data_type => :timestamp_tz,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 13,
-                      :precision => :skip,
-                      :scale => 9,
-                      :fsprecision => 9,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "TIMESTAMP WITH LOCAL TIME ZONE",
-                      :oraver => ora90,
-                      :data_type => :timestamp_ltz,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 11,
-                      :precision => :skip,
-                      :scale => 6,
-                      :fsprecision => 6,
-                      :lfprecision => :skip
-                      ),
-     DatatypeData.new(:data_type_string => "TIMESTAMP(9) WITH LOCAL TIME ZONE",
-                      :oraver => ora90,
-                      :data_type => :timestamp_ltz,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 11,
-                      :precision => :skip,
-                      :scale => 9,
-                      :fsprecision => 9,
-                      :lfprecision => :skip
-                      ),
-
-     # Skip tsets for scale and fsprecision for INTERVAL YEAR TO MONTH
-     # because their values depend on how they are described.
-     #
-     #  Oracle 10g XE 10.2.0.1.0 on Linux:
-     #   +-------------------------------------------+-----------+-------------+
-     #   |                                           |   scale   | fsprecision |
-     #   +------------------------------+------------+-----------+-------------+
-     #   | INTERVAL YEAR TO MONTH       | implicitly |     0     |      0      |
-     #   |                              | explicitly |     2     |      2      |
-     #   +------------------------------+------------+-----------+-------------+
-     #   | INTERVAL YEAR(4) TO MONTH    | implicitly |     0     |      0      |
-     #   |                              | explicitly |     4     |      4      |
-     #   +------------------------------+------------+-----------+-------------+
-     DatatypeData.new(:data_type_string => "INTERVAL YEAR TO MONTH",
-                      :oraver => ora90,
-                      :data_type => :interval_ym,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 5,
-                      :precision => 2,
-                      :scale => :skip,
-                      :fsprecision => :skip,
-                      :lfprecision => 2
-                      ),
-     DatatypeData.new(:data_type_string => "INTERVAL YEAR(4) TO MONTH",
-                      :oraver => ora90,
-                      :data_type => :interval_ym,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 5,
-                      :precision => 4,
-                      :scale => :skip,
-                      :fsprecision => :skip,
-                      :lfprecision => 4
-                      ),
-     # Skip tests for precision and scale for INTERVAL DAY TO SECOND
-     # because their values depend on how they are described.
-     #
-     #  Oracle 10g XE 10.2.0.1.0 on Linux:
-     #   +-------------------------------------------+-----------+-----------+
-     #   |                                           | precision |   scale   |
-     #   +------------------------------+------------+-----------+-----------+
-     #   | INTERVAL DAY TO SECOND       | implicitly |     2     |     6     |
-     #   |                              | explicitly |     6     |     2     |
-     #   +------------------------------+------------+-----------+-----------+
-     #   | INTERVAL DAY(4) TO SECOND(9) | implicitly |     4     |     9     |
-     #   |                              | explicitly |     9     |     4     |
-     #   +------------------------------+------------+-----------+-----------+
-     DatatypeData.new(:data_type_string => "INTERVAL DAY TO SECOND",
-                      :oraver => ora90,
-                      :data_type => :interval_ds,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 11,
-                      :precision => :skip,
-                      :scale => :skip,
-                      :fsprecision => 6,
-                      :lfprecision => 2
-                      ),
-     DatatypeData.new(:data_type_string => "INTERVAL DAY(4) TO SECOND(9)",
-                      :oraver => ora90,
-                      :data_type => :interval_ds,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => 11,
-                      :precision => :skip,
-                      :scale => :skip,
-                      :fsprecision => 9,
-                      :lfprecision => 4
-                      ),
-     # Object Types
-     DatatypeData.new(:data_type_string => "MDSYS.SDO_GEOMETRY",
-                      :oraver => ora101,
-                      :data_type => :named_type,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => :skip, # 1 when explicitly, 2000 when implicitly.
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0
-                      ),
-=begin # uncomment after ref is supported.
-     DatatypeData.new(:data_type_string => "REF MDSYS.SDO_GEOMETRY",
-                      :oraver => ora101,
-                      :data_type => :ref,
-                      :charset_form => nil,
-                      :nullable? => true,
-                      :char_used? => false,
-                      :char_size => 0,
-                      :data_size => :skip,
-                      :precision => 0,
-                      :scale => 0,
-                      :fsprecision => 0,
-                      :lfprecision => 0,
-                      ),
-=end
-    ]
-
   def test_error_describe_table
     drop_table('test_table')
     begin
@@ -618,12 +69,6 @@
     end
   end
 
-  def assert_object_id(object_name, object_id, owner_name = nil)
-    owner_name ||= @conn.username
-    expected_val = @conn.select_one('select object_id from all_objects where owner = :1 and object_name = :2', owner_name, object_name)[0]
-    assert_equal(expected_val, object_id, "ID of #{object_name}")
-  end
-
   def test_table_metadata
     drop_table('test_table')
 
@@ -637,6 +82,41 @@
    MAXEXTENTS UNLIMITED
    PCTINCREASE 0)
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Table,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TABLE'),
+      :obj_name => 'TEST_TABLE',
+      :obj_schema => @conn.username,
+      :num_cols => 2,
+      :type_metadata => nil,
+      :is_temporary? => false,
+      :is_typed? => false,
+      :duration => nil,
+      #:dba => 0,
+      #:tablespace => 0,
+      :clustered? => false,
+      :partitioned? => false,
+      :index_only? => false,
+      :columns => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL1',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL2',
+        },
+      },
+      :inspect => /#<OCI8::Metadata::Table:\(\d+\) #{@conn.username}.TEST_TABLE>/,
+    }
     [
      @conn.describe_any('test_table'),
      @conn.describe_table('test_table'),
@@ -644,21 +124,7 @@
        obj.obj_name == 'TEST_TABLE'
      end
     ].each do |desc|
-      assert_object_id('TEST_TABLE', desc.obj_id)
-      assert_equal('TEST_TABLE', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(2, desc.num_cols)
-      assert_nil(desc.type_metadata)
-      assert_equal(false, desc.is_temporary?)
-      assert_equal(false, desc.is_typed?)
-      assert_nil(desc.duration)
-      refute_nil(desc.dba)
-      refute_nil(desc.tablespace)
-      assert_equal(false, desc.clustered?)
-      assert_equal(false, desc.partitioned?)
-      assert_equal(false, desc.index_only?)
-      assert_instance_of(Array, desc.columns)
-      assert_instance_of(OCI8::Metadata::Column, desc.columns[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
     drop_table('test_table')
 
@@ -666,6 +132,41 @@
     @conn.exec(<<-EOS)
 CREATE GLOBAL TEMPORARY TABLE test_table (col1 number(38,0), col2 varchar2(60))
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Table,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TABLE'),
+      :obj_name => 'TEST_TABLE',
+      :obj_schema => @conn.username,
+      :num_cols => 2,
+      :type_metadata => nil,
+      :is_temporary? => true,
+      :is_typed? => false,
+      :duration => :transaction,
+      #:dba => 0,
+      #:tablespace => 0,
+      :clustered? => false,
+      :partitioned? => false,
+      :index_only? => false,
+      :columns => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL1',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL2',
+        },
+      },
+      :inspect => /#<OCI8::Metadata::Table:\(\d+\) #{@conn.username}.TEST_TABLE>/,
+    }
     [
      @conn.describe_any('test_table'),
      @conn.describe_table('test_table'),
@@ -673,21 +174,7 @@
        obj.obj_name == 'TEST_TABLE'
      end
     ].each do |desc|
-      assert_object_id('TEST_TABLE', desc.obj_id)
-      assert_equal('TEST_TABLE', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(2, desc.num_cols)
-      assert_nil(desc.type_metadata)
-      assert_equal(true, desc.is_temporary?)
-      assert_equal(false, desc.is_typed?)
-      assert_equal(:transaction, desc.duration)
-      refute_nil(desc.dba)
-      refute_nil(desc.tablespace)
-      assert_equal(false, desc.clustered?)
-      assert_equal(false, desc.partitioned?)
-      assert_equal(false, desc.index_only?)
-      assert_instance_of(Array, desc.columns)
-      assert_instance_of(OCI8::Metadata::Column, desc.columns[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
     drop_table('test_table')
 
@@ -696,6 +183,41 @@
 CREATE GLOBAL TEMPORARY TABLE test_table (col1 number(38,0), col2 varchar2(60))
 ON COMMIT PRESERVE ROWS
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Table,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TABLE'),
+      :obj_name => 'TEST_TABLE',
+      :obj_schema => @conn.username,
+      :num_cols => 2,
+      :type_metadata => nil,
+      :is_temporary? => true,
+      :is_typed? => false,
+      :duration => :session,
+      #:dba => 0,
+      #:tablespace => 0,
+      :clustered? => false,
+      :partitioned? => false,
+      :index_only? => false,
+      :columns => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL1',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL2',
+        },
+      },
+      :inspect => /#<OCI8::Metadata::Table:\(\d+\) #{@conn.username}.TEST_TABLE>/,
+    }
     [
      @conn.describe_any('test_table'),
      @conn.describe_table('test_table'),
@@ -703,21 +225,7 @@
        obj.obj_name == 'TEST_TABLE'
      end
     ].each do |desc|
-      assert_object_id('TEST_TABLE', desc.obj_id)
-      assert_equal('TEST_TABLE', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(2, desc.num_cols)
-      assert_nil(desc.type_metadata)
-      assert_equal(true, desc.is_temporary?)
-      assert_equal(false, desc.is_typed?)
-      assert_equal(:session, desc.duration)
-      refute_nil(desc.dba)
-      refute_nil(desc.tablespace)
-      assert_equal(false, desc.clustered?)
-      assert_equal(false, desc.partitioned?)
-      assert_equal(false, desc.index_only?)
-      assert_instance_of(Array, desc.columns)
-      assert_instance_of(OCI8::Metadata::Column, desc.columns[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
     drop_table('test_table')
 
@@ -728,6 +236,114 @@
     @conn.exec(<<-EOS)
 CREATE TABLE test_table OF test_type
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Table,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TABLE'),
+      :obj_name => 'TEST_TABLE',
+      :obj_schema => @conn.username,
+      :num_cols => 2,
+      :type_metadata => {
+        :class => OCI8::Metadata::Type,
+        :obj_id => 0,
+        :obj_name => nil,
+        :obj_schema => nil,
+        :typecode => :named_type,
+        :collection_typecode => nil,
+        :is_incomplete_type? => false,
+        :is_system_type? => false,
+        :is_predefined_type? => false,
+        :is_transient_type? => false,
+        :is_system_generated_type? => false,
+        :has_nested_table? => false,
+        :has_lob? => false,
+        :has_file? => false,
+        :collection_element => nil,
+        :num_type_attrs => 2,
+        :num_type_methods => 0,
+        :map_method => nil,
+        :order_method => nil,
+        :is_invoker_rights? => false,
+        :name => 'TEST_TYPE',
+        :schema_name => @conn.username,
+        :is_final_type? => true,
+        :is_instantiable_type? => true,
+        :is_subtype? => false,
+        :package_name => nil,
+        :type_attrs => {
+          :class => Array,
+          :size => 2,
+          [0] => {
+            :class => OCI8::Metadata::TypeAttr,
+            :obj_id => nil,
+            :obj_name => nil,
+            :obj_schema => nil,
+            :data_size => 22,
+            :typecode => :number,
+            :data_type => :number,
+            :name => 'COL1',
+            :precision => 38,
+            :scale => 0,
+            :type_name => 'NUMBER',
+            :schema_name => 'SYS',
+            :fsprecision => 0,
+            :lfprecision => 38,
+            :type_metadata => {
+              :class => OCI8::Metadata::Type,
+            },
+            :inspect => '#<OCI8::Metadata::TypeAttr: COL1 NUMBER(38)>',
+          },
+          [1] => {
+            :class => OCI8::Metadata::TypeAttr,
+            :obj_id => nil,
+            :obj_name => nil,
+            :obj_schema => nil,
+            :data_size => 60,
+            :typecode => :varchar2,
+            :data_type => :varchar2,
+            :name => 'COL2',
+            :precision => 0,
+            :scale => 0,
+            :type_name => 'VARCHAR2',
+            :schema_name => 'SYS',
+            :fsprecision => 0,
+            :lfprecision => 60,
+            :type_metadata => {
+              :class => OCI8::Metadata::Type,
+            },
+            :inspect => '#<OCI8::Metadata::TypeAttr: COL2 VARCHAR2(60)>',
+          },
+        },
+        :type_methods => [],
+        :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TEST_TYPE>",
+      },
+      :is_temporary? => false,
+      :is_typed? => true,
+      :duration => nil,
+      #:dba => 0,
+      #:tablespace => 0,
+      :clustered? => false,
+      :partitioned? => false,
+      :index_only? => false,
+      :columns => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL1',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL2',
+        },
+      },
+      :inspect => /#<OCI8::Metadata::Table:\(\d+\) #{@conn.username}.TEST_TABLE>/,
+    }
     [
      @conn.describe_any('test_table'),
      @conn.describe_table('test_table'),
@@ -735,21 +351,7 @@
        obj.obj_name == 'TEST_TABLE'
      end
     ].each do |desc|
-      assert_object_id('TEST_TABLE', desc.obj_id)
-      assert_equal('TEST_TABLE', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(2, desc.num_cols)
-      assert_instance_of(OCI8::Metadata::Type, desc.type_metadata)
-      assert_equal(false, desc.is_temporary?)
-      assert_equal(true, desc.is_typed?)
-      assert_equal(nil, desc.duration)
-      refute_nil(desc.dba)
-      refute_nil(desc.tablespace)
-      assert_equal(false, desc.clustered?)
-      assert_equal(false, desc.partitioned?)
-      assert_equal(false, desc.index_only?)
-      assert_instance_of(Array, desc.columns)
-      assert_instance_of(OCI8::Metadata::Column, desc.columns[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
     drop_table('test_table')
     @conn.exec('DROP TYPE TEST_TYPE')
@@ -759,6 +361,41 @@
 CREATE TABLE test_table (col1 number(38,0) PRIMARY KEY, col2 varchar2(60))
 ORGANIZATION INDEX 
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Table,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TABLE'),
+      :obj_name => 'TEST_TABLE',
+      :obj_schema => @conn.username,
+      :num_cols => 2,
+      :type_metadata => nil,
+      :is_temporary? => false,
+      :is_typed? => false,
+      :duration => nil,
+      #:dba => 0,
+      #:tablespace => 0,
+      :clustered? => false,
+      :partitioned? => false,
+      :index_only? => true,
+      :columns => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL1',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'COL2',
+        },
+      },
+      :inspect => /#<OCI8::Metadata::Table:\(\d+\) #{@conn.username}.TEST_TABLE>/,
+    }
     [
      @conn.describe_any('test_table'),
      @conn.describe_table('test_table'),
@@ -766,27 +403,46 @@
        obj.obj_name == 'TEST_TABLE'
      end
     ].each do |desc|
-      assert_object_id('TEST_TABLE', desc.obj_id)
-      assert_equal('TEST_TABLE', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(2, desc.num_cols)
-      assert_nil(desc.type_metadata)
-      assert_equal(false, desc.is_temporary?)
-      assert_equal(false, desc.is_typed?)
-      assert_equal(nil, desc.duration)
-      refute_nil(desc.dba)
-      refute_nil(desc.tablespace)
-      assert_equal(false, desc.clustered?)
-      assert_equal(false, desc.partitioned?)
-      assert_equal(true, desc.index_only?)
-      assert_instance_of(Array, desc.columns)
-      assert_instance_of(OCI8::Metadata::Column, desc.columns[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
     drop_table('test_table')
   end # test_table_metadata
 
   def test_view_metadata
     @conn.exec('CREATE OR REPLACE VIEW test_view as SELECT * FROM tab')
+    attrs = {
+      :class => OCI8::Metadata::View,
+      :obj_id => to_obj_id(@conn.username, 'TEST_VIEW'),
+      :obj_name => 'TEST_VIEW',
+      :obj_schema => @conn.username,
+      :num_cols => 3,
+      :columns => {
+        :class => Array,
+        :size => 3,
+        [0] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'TNAME',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'TABTYPE',
+        },
+        [2] => {
+          :class => OCI8::Metadata::Column,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => 'CLUSTERID',
+        },
+      },
+      :inspect => /#<OCI8::Metadata::View:\(\d+\) #{@conn.username}.TEST_VIEW>/,
+    }
     [
      @conn.describe_any('test_view'),
      @conn.describe_view('test_view'),
@@ -795,12 +451,7 @@
        obj.obj_name == 'TEST_VIEW'
      end
     ].each do |desc|
-      assert_object_id('TEST_VIEW', desc.obj_id)
-      assert_equal('TEST_VIEW', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(3, desc.num_cols)
-      assert_instance_of(Array, desc.columns)
-      assert_instance_of(OCI8::Metadata::Column, desc.columns[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
     @conn.exec('DROP VIEW test_view')
   end # test_view_metadata
@@ -812,6 +463,71 @@
   NULL;
 END;
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Procedure,
+      :obj_id => to_obj_id(@conn.username, 'TEST_PROC'),
+      :obj_name => 'TEST_PROC',
+      :obj_schema => @conn.username,
+      :is_invoker_rights? => false,
+      :name => 'TEST_PROC',
+      :overload_id => nil,
+      :arguments => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG1",
+          :position => 1,
+          #:typecode => nil,
+          :data_type => :number,
+          :data_size => 22,
+          :precision => 38,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :in,
+          :radix => 10,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG2",
+          :position => 2,
+          #:typecode => nil,
+          :data_type => :varchar2,
+          :data_size => 0,
+          :precision => 0,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :out,
+          :radix => 0,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+        },
+      },
+      :is_standalone? => true,
+      :inspect => '#<OCI8::Metadata::Procedure: TEST_PROC>',
+    }
     [
      @conn.describe_any('test_proc'),
      @conn.describe_procedure('test_proc'),
@@ -819,16 +535,7 @@
        obj.obj_name == 'TEST_PROC'
      end
     ].each do |desc|
-      assert_instance_of(OCI8::Metadata::Procedure, desc)
-      assert_object_id('TEST_PROC', desc.obj_id)
-      assert_equal('TEST_PROC', desc.obj_name)
-      assert_equal('TEST_PROC', desc.name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(false, desc.is_invoker_rights?)
-      assert_equal(nil, desc.overload_id)
-      assert_instance_of(Array, desc.arguments)
-      assert_equal(2, desc.arguments.length)
-      assert_instance_of(OCI8::Metadata::Argument, desc.arguments[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
 
     @conn.exec(<<-EOS)
@@ -839,6 +546,71 @@
   NULL;
 END;
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Procedure,
+      :obj_id => to_obj_id(@conn.username, 'TEST_PROC'),
+      :obj_name => 'TEST_PROC',
+      :obj_schema => @conn.username,
+      :is_invoker_rights? => true,
+      :name => 'TEST_PROC',
+      :overload_id => nil,
+      :arguments => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG1",
+          :position => 1,
+          #:typecode => nil,
+          :data_type => :number,
+          :data_size => 22,
+          :precision => 38,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :in,
+          :radix => 10,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG2",
+          :position => 2,
+          #:typecode => nil,
+          :data_type => :varchar2,
+          :data_size => 0,
+          :precision => 0,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :out,
+          :radix => 0,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+        },
+      },
+      :is_standalone? => true,
+      :inspect => '#<OCI8::Metadata::Procedure: TEST_PROC>',
+    }
     [
      @conn.describe_any('test_proc'),
      @conn.describe_procedure('test_proc'),
@@ -846,62 +618,11 @@
        obj.obj_name == 'TEST_PROC'
      end
     ].each do |desc|
-      assert_instance_of(OCI8::Metadata::Procedure, desc)
-      assert_object_id('TEST_PROC', desc.obj_id)
-      assert_equal('TEST_PROC', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(true, desc.is_invoker_rights?)
-      assert_equal(nil, desc.overload_id)
-      assert_instance_of(Array, desc.arguments)
-      assert_equal(2, desc.arguments.length)
-      assert_instance_of(OCI8::Metadata::Argument, desc.arguments[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
 
     @conn.exec('DROP PROCEDURE test_proc');
 
-    @conn.exec(<<-EOS)
-CREATE OR REPLACE PACKAGE TEST_PKG IS
-  PROCEDURE test_proc(arg1 IN INTEGER, arg2 OUT varchar2);
-END;
-EOS
-    desc = @conn.describe_package('test_pkg').subprograms[0]
-    assert_instance_of(OCI8::Metadata::Procedure, desc)
-    assert_equal(nil, desc.obj_id)
-    assert_equal('TEST_PROC', desc.obj_name)
-    assert_equal(nil, desc.obj_schema)
-    assert_equal(false, desc.is_invoker_rights?)
-    assert_equal(0, desc.overload_id)
-    assert_instance_of(Array, desc.arguments)
-    assert_equal(2, desc.arguments.length)
-    assert_instance_of(OCI8::Metadata::Argument, desc.arguments[0])
-
-    @conn.exec(<<-EOS)
-CREATE OR REPLACE PACKAGE TEST_PKG AUTHID CURRENT_USER
-IS
-  PROCEDURE test_proc(arg1 IN INTEGER, arg2 OUT varchar2);
-  PROCEDURE test_proc(arg1 IN INTEGER);
-END;
-EOS
-    desc = @conn.describe_package('test_pkg').subprograms
-    assert_instance_of(OCI8::Metadata::Procedure, desc[0])
-    assert_equal(nil, desc[0].obj_id)
-    assert_equal('TEST_PROC', desc[0].obj_name)
-    assert_equal(nil, desc[0].obj_schema)
-    assert_equal(true, desc[0].is_invoker_rights?)
-    assert_equal(2, desc[0].overload_id)
-    assert_instance_of(Array, desc[0].arguments)
-    assert_equal(2, desc[0].arguments.length)
-    assert_instance_of(OCI8::Metadata::Argument, desc[0].arguments[0])
-
-    assert_instance_of(OCI8::Metadata::Procedure, desc[1])
-    assert_equal(nil, desc[1].obj_id)
-    assert_equal('TEST_PROC', desc[1].obj_name)
-    assert_equal(nil, desc[1].obj_schema)
-    assert_equal(true, desc[1].is_invoker_rights?)
-    assert_equal(1, desc[1].overload_id)
-    assert_instance_of(Array, desc[1].arguments)
-    assert_equal(1, desc[1].arguments.length)
-    assert_instance_of(OCI8::Metadata::Argument, desc[1].arguments[0])
   end # test_procedure_metadata
 
   def test_function_metadata
@@ -911,6 +632,96 @@
   RETURN arg1;
 END;
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Function,
+      :obj_id => to_obj_id(@conn.username, 'TEST_FUNC'),
+      :obj_name => 'TEST_FUNC',
+      :obj_schema => @conn.username,
+      :is_invoker_rights? => false,
+      :name => 'TEST_FUNC',
+      :overload_id => nil,
+      :arguments => {
+        :class => Array,
+        :size => 3,
+        [0] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "",
+          :position => 0,
+          #:typecode => nil,
+          :data_type => :number,
+          :data_size => 22,
+          :precision => 0,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :out,
+          :radix => 10,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument:  NUMBER>',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG1",
+          :position => 1,
+          #:typecode => nil,
+          :data_type => :number,
+          :data_size => 22,
+          :precision => 38,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :in,
+          :radix => 10,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+        },
+        [2] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG2",
+          :position => 2,
+          #:typecode => nil,
+          :data_type => :varchar2,
+          :data_size => 0,
+          :precision => 0,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :out,
+          :radix => 0,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+        },
+      },
+      :is_standalone? => true,
+      :inspect => '#<OCI8::Metadata::Function: TEST_FUNC>',
+    }
     [
      @conn.describe_any('test_func'),
      @conn.describe_function('test_func'),
@@ -918,16 +729,7 @@
        obj.obj_name == 'TEST_FUNC'
      end
     ].each do |desc|
-      assert_instance_of(OCI8::Metadata::Function, desc)
-      assert_object_id('TEST_FUNC', desc.obj_id)
-      assert_equal('TEST_FUNC', desc.obj_name)
-      assert_equal('TEST_FUNC', desc.name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(false, desc.is_invoker_rights?)
-      assert_equal(nil, desc.overload_id)
-      assert_instance_of(Array, desc.arguments)
-      assert_equal(3, desc.arguments.length)
-      assert_instance_of(OCI8::Metadata::Argument, desc.arguments[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
 
     @conn.exec(<<-EOS)
@@ -938,6 +740,96 @@
   RETURN arg1;
 END;
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Function,
+      :obj_id => to_obj_id(@conn.username, 'TEST_FUNC'),
+      :obj_name => 'TEST_FUNC',
+      :obj_schema => @conn.username,
+      :is_invoker_rights? => true,
+      :name => 'TEST_FUNC',
+      :overload_id => nil,
+      :arguments => {
+        :class => Array,
+        :size => 3,
+        [0] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "",
+          :position => 0,
+          #:typecode => nil,
+          :data_type => :number,
+          :data_size => 22,
+          :precision => 0,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :out,
+          :radix => 10,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument:  NUMBER>',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG1",
+          :position => 1,
+          #:typecode => nil,
+          :data_type => :number,
+          :data_size => 22,
+          :precision => 38,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :in,
+          :radix => 10,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+        },
+        [2] => {
+          :class => OCI8::Metadata::Argument,
+          :obj_id => nil,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :name => "ARG2",
+          :position => 2,
+          #:typecode => nil,
+          :data_type => :varchar2,
+          :data_size => 0,
+          :precision => 0,
+          :scale => 0,
+          :level => 0,
+          :has_default => 0,
+          :has_default? => false,
+          :iomode => :out,
+          :radix => 0,
+          :type_name => "",
+          :schema_name => "",
+          :sub_name => "",
+          :link => "",
+          #:type_metadata => nil,
+          :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+        },
+      },
+      :is_standalone? => true,
+      :inspect => '#<OCI8::Metadata::Function: TEST_FUNC>',
+    }
     [
      @conn.describe_any('test_func'),
      @conn.describe_function('test_func'),
@@ -945,70 +837,188 @@
        obj.obj_name == 'TEST_FUNC'
      end
     ].each do |desc|
-      assert_instance_of(OCI8::Metadata::Function, desc)
-      assert_object_id('TEST_FUNC', desc.obj_id)
-      assert_equal('TEST_FUNC', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(true, desc.is_invoker_rights?)
-      assert_equal(nil, desc.overload_id)
-      assert_instance_of(Array, desc.arguments)
-      assert_equal(3, desc.arguments.length)
-      assert_instance_of(OCI8::Metadata::Argument, desc.arguments[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
 
     @conn.exec('DROP FUNCTION test_func');
 
-    @conn.exec(<<-EOS)
-CREATE OR REPLACE PACKAGE TEST_PKG IS
-  FUNCTION test_func(arg1 IN INTEGER, arg2 OUT varchar2) RETURN NUMBER;
-END;
-EOS
-    desc = @conn.describe_package('test_pkg').subprograms[0]
-    assert_instance_of(OCI8::Metadata::Function, desc)
-    assert_equal(nil, desc.obj_id)
-    assert_equal('TEST_FUNC', desc.obj_name)
-    assert_equal(nil, desc.obj_schema)
-    assert_equal(false, desc.is_invoker_rights?)
-    assert_equal(0, desc.overload_id)
-    assert_instance_of(Array, desc.arguments)
-    assert_equal(3, desc.arguments.length)
-    assert_instance_of(OCI8::Metadata::Argument, desc.arguments[0])
-
-    @conn.exec(<<-EOS)
-CREATE OR REPLACE PACKAGE TEST_PKG AUTHID CURRENT_USER
-IS
-  FUNCTION test_func(arg1 IN INTEGER, arg2 OUT varchar2) RETURN NUMBER;
-  FUNCTION test_func(arg1 IN INTEGER) RETURN NUMBER;
-END;
-EOS
-    desc = @conn.describe_package('test_pkg').subprograms
-    assert_instance_of(OCI8::Metadata::Function, desc[0])
-    assert_equal(nil, desc[0].obj_id)
-    assert_equal('TEST_FUNC', desc[0].obj_name)
-    assert_equal(nil, desc[0].obj_schema)
-    assert_equal(true, desc[0].is_invoker_rights?)
-    assert_equal(2, desc[0].overload_id)
-    assert_instance_of(Array, desc[0].arguments)
-    assert_equal(3, desc[0].arguments.length)
-    assert_instance_of(OCI8::Metadata::Argument, desc[0].arguments[0])
-
-    assert_instance_of(OCI8::Metadata::Function, desc[1])
-    assert_equal(nil, desc[1].obj_id)
-    assert_equal('TEST_FUNC', desc[1].obj_name)
-    assert_equal(nil, desc[1].obj_schema)
-    assert_equal(true, desc[1].is_invoker_rights?)
-    assert_equal(1, desc[1].overload_id)
-    assert_instance_of(Array, desc[1].arguments)
-    assert_equal(2, desc[1].arguments.length)
-    assert_instance_of(OCI8::Metadata::Argument, desc[1].arguments[0])
   end # test_function_metadata
 
   def test_package_metadata
     @conn.exec(<<-EOS)
 CREATE OR REPLACE PACKAGE TEST_PKG IS
   FUNCTION test_func(arg1 IN INTEGER, arg2 OUT varchar2) RETURN NUMBER;
+  PROCEDURE test_proc(arg1 IN INTEGER, arg2 OUT varchar2);
 END;
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Package,
+      :obj_id => to_obj_id(@conn.username, 'TEST_PKG'),
+      :obj_name => 'TEST_PKG',
+      :obj_schema => @conn.username,
+      :is_invoker_rights? => false,
+      :subprograms => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::Function,
+          :obj_id => nil,
+          :obj_name => 'TEST_FUNC',
+          :obj_schema => nil,
+          :is_invoker_rights? => false,
+          :name => 'TEST_FUNC',
+          :overload_id => 0,
+          :arguments => {
+            :class => Array,
+            :size => 3,
+            [0] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "",
+              :position => 0,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 0,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :out,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument:  NUMBER>',
+            },
+            [1] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG1",
+              :position => 1,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 38,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :in,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+            },
+            [2] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG2",
+              :position => 2,
+              #:typecode => nil,
+              :data_type => :varchar2,
+              :data_size => 0,
+              :precision => 0,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :out,
+              :radix => 0,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+            },
+          },
+          :is_standalone? => false,
+          :inspect => '#<OCI8::Metadata::Function: TEST_FUNC>',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Procedure,
+          :obj_id => nil,
+          :obj_name => 'TEST_PROC',
+          :obj_schema => nil,
+          :is_invoker_rights? => false,
+          :name => 'TEST_PROC',
+          :overload_id => 0,
+          :arguments => {
+            :class => Array,
+            :size => 2,
+            [0] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG1",
+              :position => 1,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 38,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :in,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+            },
+            [1] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG2",
+              :position => 2,
+              #:typecode => nil,
+              :data_type => :varchar2,
+              :data_size => 0,
+              :precision => 0,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :out,
+              :radix => 0,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+            },
+          },
+          :is_standalone? => false,
+          :inspect => '#<OCI8::Metadata::Procedure: TEST_PROC>',
+        },
+      },
+      :types => ($oracle_version >= OCI8::ORAVER_12_1) ? [] : :skip,
+      :inspect => /#<OCI8::Metadata::Package:\(\d+\) #{@conn.username}.TEST_PKG>/,
+    }
     [
      @conn.describe_any('test_pkg'),
      @conn.describe_package('test_pkg'),
@@ -1016,21 +1026,290 @@
        obj.obj_name == 'TEST_PKG'
      end
     ].each do |desc|
-      assert_instance_of(OCI8::Metadata::Package, desc)
-      assert_object_id('TEST_PKG', desc.obj_id)
-      assert_equal('TEST_PKG', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(false, desc.is_invoker_rights?)
-      assert_instance_of(Array, desc.subprograms)
-      assert_equal(1, desc.subprograms.length)
-      assert_instance_of(OCI8::Metadata::Function, desc.subprograms[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
 
     @conn.exec(<<-EOS)
 CREATE OR REPLACE PACKAGE TEST_PKG AUTHID CURRENT_USER IS
   PROCEDURE test_proc(arg1 IN INTEGER, arg2 OUT varchar2);
+  PROCEDURE test_proc(arg1 IN INTEGER);
+  FUNCTION test_func(arg1 IN INTEGER, arg2 OUT varchar2) RETURN NUMBER;
+  FUNCTION test_func(arg1 IN INTEGER) RETURN NUMBER;
 END;
 EOS
+    attrs = {
+      :class => OCI8::Metadata::Package,
+      :obj_id => to_obj_id(@conn.username, 'TEST_PKG'),
+      :obj_name => 'TEST_PKG',
+      :obj_schema => @conn.username,
+      :is_invoker_rights? => true,
+      :subprograms => {
+        :class => Array,
+        :size => 4,
+        [0] => {
+          :class => OCI8::Metadata::Function,
+          :obj_id => nil,
+          :obj_name => 'TEST_FUNC',
+          :obj_schema => nil,
+          :is_invoker_rights? => true,
+          :name => 'TEST_FUNC',
+          :overload_id => 2,
+          :arguments => {
+            :class => Array,
+            :size => 3,
+            [0] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "",
+              :position => 0,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 0,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :out,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument:  NUMBER>',
+            },
+            [1] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG1",
+              :position => 1,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 38,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :in,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+            },
+            [2] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG2",
+              :position => 2,
+              #:typecode => nil,
+              :data_type => :varchar2,
+              :data_size => 0,
+              :precision => 0,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :out,
+              :radix => 0,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+            },
+          },
+          :is_standalone? => false,
+          :inspect => '#<OCI8::Metadata::Function: TEST_FUNC>',
+        },
+        [1] => {
+          :class => OCI8::Metadata::Function,
+          :obj_id => nil,
+          :obj_name => 'TEST_FUNC',
+          :obj_schema => nil,
+          :is_invoker_rights? => true,
+          :name => 'TEST_FUNC',
+          :overload_id => 1,
+          :arguments => {
+            :class => Array,
+            :size => 2,
+            [0] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "",
+              :position => 0,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 0,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :out,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument:  NUMBER>',
+            },
+            [1] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG1",
+              :position => 1,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 38,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :in,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+            },
+          },
+          :is_standalone? => false,
+          :inspect => '#<OCI8::Metadata::Function: TEST_FUNC>',
+        },
+        [2] => {
+          :class => OCI8::Metadata::Procedure,
+          :obj_id => nil,
+          :obj_name => 'TEST_PROC',
+          :obj_schema => nil,
+          :is_invoker_rights? => true,
+          :name => 'TEST_PROC',
+          :overload_id => 2,
+          :arguments => {
+            :class => Array,
+            :size => 2,
+            [0] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG1",
+              :position => 1,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 38,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :in,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+            },
+            [1] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG2",
+              :position => 2,
+              #:typecode => nil,
+              :data_type => :varchar2,
+              :data_size => 0,
+              :precision => 0,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :out,
+              :radix => 0,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG2 VARCHAR2(0)>', # TODO: change to "VARCHAR2"
+            },
+          },
+          :is_standalone? => false,
+          :inspect => '#<OCI8::Metadata::Procedure: TEST_PROC>',
+        },
+        [3] => {
+          :class => OCI8::Metadata::Procedure,
+          :obj_id => nil,
+          :obj_name => 'TEST_PROC',
+          :obj_schema => nil,
+          :is_invoker_rights? => true,
+          :name => 'TEST_PROC',
+          :overload_id => 1,
+          :arguments => {
+            :class => Array,
+            :size => 1,
+            [0] => {
+              :class => OCI8::Metadata::Argument,
+              :obj_id => nil,
+              :obj_name => nil,
+              :obj_schema => nil,
+              :name => "ARG1",
+              :position => 1,
+              #:typecode => nil,
+              :data_type => :number,
+              :data_size => 22,
+              :precision => 38,
+              :scale => 0,
+              :level => 0,
+              :has_default => 0,
+              :has_default? => false,
+              :iomode => :in,
+              :radix => 10,
+              :type_name => "",
+              :schema_name => "",
+              :sub_name => "",
+              :link => "",
+              #:type_metadata => nil,
+              :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument: ARG1 NUMBER(38)>',
+            },
+          },
+          :is_standalone? => false,
+          :inspect => '#<OCI8::Metadata::Procedure: TEST_PROC>',
+        },
+      },
+      :types => ($oracle_version >= OCI8::ORAVER_12_1) ? [] : :skip,
+      :inspect => /#<OCI8::Metadata::Package:\(\d+\) #{@conn.username}.TEST_PKG>/,
+    }
     [
      @conn.describe_any('test_pkg'),
      @conn.describe_package('test_pkg'),
@@ -1038,15 +1317,9 @@
        obj.obj_name == 'TEST_PKG'
      end
     ].each do |desc|
-      assert_instance_of(OCI8::Metadata::Package, desc)
-      assert_object_id('TEST_PKG', desc.obj_id)
-      assert_equal('TEST_PKG', desc.obj_name)
-      assert_equal(@conn.username, desc.obj_schema)
-      assert_equal(true, desc.is_invoker_rights?)
-      assert_instance_of(Array, desc.subprograms)
-      assert_equal(1, desc.subprograms.length)
-      assert_instance_of(OCI8::Metadata::Procedure, desc.subprograms[0])
+      check_attributes("line: #{__LINE__}", desc, attrs)
     end
+
   end # test_package_metadata
 
   def test_type_metadata
@@ -1063,6 +1336,7 @@
     drop_type('TEST_TYPE_CHILD')
     drop_type('TEST_TYPE_PARENT')
     expected_values = []
+    attrs_map = {}
 
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_parent AS OBJECT (
@@ -1072,8 +1346,11 @@
 NOT INSTANTIABLE
 NOT FINAL
 EOS
-    expected_values << {
+    attrs_map['TEST_TYPE_PARENT'] = {
+      :class => OCI8::Metadata::Type,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TYPE_PARENT'),
       :obj_name => 'TEST_TYPE_PARENT',
+      :obj_schema => @conn.username,
       :typecode => :named_type,
       :collection_typecode => nil,
       :is_incomplete_type? => false,
@@ -1090,13 +1367,28 @@
       :map_method => nil,
       :order_method => nil,
       :is_invoker_rights? => false,
+      :name => 'TEST_TYPE_PARENT',
+      :schema_name => @conn.username,
       :is_final_type? => false,
       :is_instantiable_type? => false,
       :is_subtype? => false,
       :supertype_schema_name => nil,
       :supertype_name => nil,
-      :type_attrs => [:array, 2, OCI8::Metadata::TypeAttr],
-      :type_methods => [:array, 0],
+      :package_name => nil,
+      :type_attrs => {
+        :class => Array,
+        :size => 2,
+        [0] => {
+          :class => OCI8::Metadata::TypeAttr,
+          :inspect => '#<OCI8::Metadata::TypeAttr: COL1 NUMBER(38)>',
+        },
+        [1] => {
+          :class => OCI8::Metadata::TypeAttr,
+          :inspect => '#<OCI8::Metadata::TypeAttr: COL2 VARCHAR2(60)>',
+        },
+      },
+      :type_methods => [],
+      :inspect => /#<OCI8::Metadata::Type:\(\d+\) #{@conn.username}.TEST_TYPE_PARENT>/,
     }
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_child UNDER test_type_parent (
@@ -1104,8 +1396,11 @@
 )
 NOT FINAL
 EOS
-    expected_values << {
+    attrs_map['TEST_TYPE_CHILD'] = {
+      :class => OCI8::Metadata::Type,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TYPE_CHILD'),
       :obj_name => 'TEST_TYPE_CHILD',
+      :obj_schema => @conn.username,
       :typecode => :named_type,
       :collection_typecode => nil,
       :is_incomplete_type? => false,
@@ -1122,19 +1417,35 @@
       :map_method => nil,
       :order_method => nil,
       :is_invoker_rights? => false,
+      :name => 'TEST_TYPE_CHILD',
+      :schema_name => @conn.username,
       :is_final_type? => false,
       :is_instantiable_type? => true,
       :is_subtype? => true,
       :supertype_schema_name => @conn.username,
       :supertype_name => 'TEST_TYPE_PARENT',
-      :type_attrs => [:array, 3, OCI8::Metadata::TypeAttr],
-      :type_methods => [:array, 0],
+      :package_name => nil,
+      :type_attrs => {
+        :class => Array,
+        :size => 3,
+        [0] => attrs_map['TEST_TYPE_PARENT'][:type_attrs][[0]],
+        [1] => attrs_map['TEST_TYPE_PARENT'][:type_attrs][[1]],
+        [2] => {
+          :class => OCI8::Metadata::TypeAttr,
+          :inspect => '#<OCI8::Metadata::TypeAttr: LOB BLOB>',
+        },
+      },
+      :type_methods => [],
+      :inspect => /#<OCI8::Metadata::Type:\(\d+\) #{@conn.username}.TEST_TYPE_CHILD>/,
     }
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_nestead_table AS TABLE OF test_type_child
 EOS
-    expected_values << {
+    attrs_map['TEST_TYPE_NESTEAD_TABLE'] = {
+      :class => OCI8::Metadata::Type,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TYPE_NESTEAD_TABLE'),
       :obj_name => 'TEST_TYPE_NESTEAD_TABLE',
+      :obj_schema => @conn.username,
       :typecode => :named_collection,
       :collection_typecode => :table,
       :is_incomplete_type? => false,
@@ -1145,25 +1456,93 @@
       :has_nested_table? => true,
       :has_lob? => true,
       :has_file? => false,
-      :collection_element => [:type, OCI8::Metadata::Collection],
+      :collection_element => {
+        :class =>  OCI8::Metadata::Collection,
+        :obj_id => nil,
+        :obj_name => nil,
+        :obj_schema => nil,
+        :data_size => 0,
+        :typecode => :named_type,
+        :data_type => :named_type,
+        :num_elems => 0,
+        :precision => 0,
+        :scale => 0,
+        :type_name => 'TEST_TYPE_CHILD',
+        :schema_name => @conn.username,
+        :type_metadata => {
+          :class => OCI8::Metadata::Type,
+          :obj_id => 0,
+          :obj_name => nil,
+          :obj_schema => nil,
+          :typecode => :named_type,
+          :collection_typecode => nil,
+          :is_incomplete_type? => false,
+          :is_system_type? => false,
+          :is_predefined_type? => false,
+          :is_transient_type? => false,
+          :is_system_generated_type? => false,
+          :has_nested_table? => false,
+          :has_lob? => true,
+          :has_file? => false,
+          :collection_element => nil,
+          :num_type_attrs => 3,
+          :num_type_methods => 0,
+          :map_method => nil,
+          :order_method => nil,
+          :is_invoker_rights? => false,
+          :name => 'TEST_TYPE_CHILD',
+          :schema_name => @conn.username,
+          :is_final_type? => false,
+          :is_instantiable_type? => true,
+          :is_subtype? => true,
+          :supertype_schema_name => @conn.username,
+          :supertype_name => 'TEST_TYPE_PARENT',
+          :package_name => nil,
+          :type_attrs => {
+            :class => Array,
+            :size => 3,
+            [0] => {
+              :class => OCI8::Metadata::TypeAttr,
+              :inspect => '#<OCI8::Metadata::TypeAttr: COL1 NUMBER(38)>',
+            },
+            [1] => {
+              :class => OCI8::Metadata::TypeAttr,
+              :inspect => '#<OCI8::Metadata::TypeAttr: COL2 VARCHAR2(60)>',
+            },
+            [2] => {
+              :class => OCI8::Metadata::TypeAttr,
+              :inspect => '#<OCI8::Metadata::TypeAttr: LOB BLOB>',
+            },
+          },
+          :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TEST_TYPE_CHILD>",
+        },
+        :inspect => "#<OCI8::Metadata::Collection: #{@conn.username}.TEST_TYPE_CHILD>",
+      },
       :num_type_attrs => 0,
       :num_type_methods => 0,
       :map_method => nil,
       :order_method => nil,
       :is_invoker_rights? => false,
+      :name => 'TEST_TYPE_NESTEAD_TABLE',
+      :schema_name => @conn.username,
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
       :supertype_schema_name => nil,
       :supertype_name => nil,
-      :type_attrs => [:array, 0],
-      :type_methods => [:array, 0],
+      :package_name => nil,
+      :type_attrs => [],
+      :type_methods => [],
+      :inspect => /#<OCI8::Metadata::Type:\(\d+\) #{@conn.username}.TEST_TYPE_NESTEAD_TABLE>/,
     }
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_varray AS VARRAY(10) OF test_type_child
 EOS
-    expected_values << {
+    attrs_map['TEST_TYPE_VARRAY'] = {
+      :class => OCI8::Metadata::Type,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TYPE_VARRAY'),
       :obj_name => 'TEST_TYPE_VARRAY',
+      :obj_schema => @conn.username,
       :typecode => :named_collection,
       :collection_typecode => :varray,
       :is_incomplete_type? => false,
@@ -1174,19 +1553,38 @@
       :has_nested_table? => false,
       :has_lob? => true,
       :has_file? => false,
-      :collection_element => [:type, OCI8::Metadata::Collection],
+      :collection_element => {
+        :class =>  OCI8::Metadata::Collection,
+        :obj_id => nil,
+        :obj_name => nil,
+        :obj_schema => nil,
+        :data_size => 0,
+        :typecode => :named_type,
+        :data_type => :named_type,
+        :num_elems => 10,
+        :precision => 0,
+        :scale => 0,
+        :type_name => 'TEST_TYPE_CHILD',
+        :schema_name => @conn.username,
+        :type_metadata => attrs_map['TEST_TYPE_NESTEAD_TABLE'][:collection_element][:type_metadata],
+        :inspect => "#<OCI8::Metadata::Collection: #{@conn.username}.TEST_TYPE_CHILD>",
+      },
       :num_type_attrs => 0,
       :num_type_methods => 0,
       :map_method => nil,
       :order_method => nil,
       :is_invoker_rights? => false,
+      :name => 'TEST_TYPE_VARRAY',
+      :schema_name => @conn.username,
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
       :supertype_schema_name => nil,
       :supertype_name => nil,
-      :type_attrs => [:array, 0],
-      :type_methods => [:array, 0],
+      :package_name => nil,
+      :type_attrs => [],
+      :type_methods => [],
+      :inspect => /#<OCI8::Metadata::Type:\(\d+\) #{@conn.username}.TEST_TYPE_VARRAY>/,
     }
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_grandchild UNDER test_type_child (
@@ -1194,8 +1592,11 @@
   file_column BFILE
 )
 EOS
-    expected_values << {
+    attrs_map['TEST_TYPE_GRANDCHILD'] = {
+      :class => OCI8::Metadata::Type,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TYPE_GRANDCHILD'),
       :obj_name => 'TEST_TYPE_GRANDCHILD',
+      :obj_schema => @conn.username,
       :typecode => :named_type,
       :collection_typecode => nil,
       :is_incomplete_type? => false,
@@ -1212,19 +1613,40 @@
       :map_method => nil,
       :order_method => nil,
       :is_invoker_rights? => false,
+      :name => 'TEST_TYPE_GRANDCHILD',
+      :schema_name => @conn.username,
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => true,
       :supertype_schema_name => @conn.username,
       :supertype_name => 'TEST_TYPE_CHILD',
-      :type_attrs => [:array, 5, OCI8::Metadata::TypeAttr],
-      :type_methods => [:array, 0],
+      :package_name => nil,
+      :type_attrs => {
+        :class => Array,
+        :size => 5,
+        [0] => attrs_map['TEST_TYPE_CHILD'][:type_attrs][[0]],
+        [1] => attrs_map['TEST_TYPE_CHILD'][:type_attrs][[1]],
+        [2] => attrs_map['TEST_TYPE_CHILD'][:type_attrs][[2]],
+        [3] => {
+          :class => OCI8::Metadata::TypeAttr,
+          :inspect => "#<OCI8::Metadata::TypeAttr: TABLE_COLUMN #{@conn.username}.TEST_TYPE_NESTEAD_TABLE>",
+        },
+        [4] => {
+          :class => OCI8::Metadata::TypeAttr,
+          :inspect => '#<OCI8::Metadata::TypeAttr: FILE_COLUMN BFILE>',
+        },
+      },
+      :type_methods => [],
+      :inspect => /#<OCI8::Metadata::Type:\(\d+\) #{@conn.username}.TEST_TYPE_GRANDCHILD>/,
     }
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_incomplete
 EOS
-    expected_values << {
+    attrs_map['TEST_TYPE_INCOMPLETE'] = {
+      :class => OCI8::Metadata::Type,
+      :obj_id => to_obj_id(@conn.username, 'TEST_TYPE_INCOMPLETE'),
       :obj_name => 'TEST_TYPE_INCOMPLETE',
+      :obj_schema => @conn.username,
       :typecode => :named_type,
       :collection_typecode => nil,
       :is_incomplete_type? => true,
@@ -1241,20 +1663,23 @@
       :map_method => nil,
       :order_method => nil,
       :is_invoker_rights? => false,
+      :name => 'TEST_TYPE_INCOMPLETE',
+      :schema_name => @conn.username,
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
       :supertype_schema_name => nil,
       :supertype_name => nil,
-      :type_attrs => [:array, 0],
-      :type_methods => [:array, 0],
+      :package_name => nil,
+      :type_attrs => [],
+      :type_methods => [],
+      :inspect => /#<OCI8::Metadata::Type:\(\d+\) #{@conn.username}.TEST_TYPE_INCOMPLETE>/,
     }
-
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_has_clob AS OBJECT (lob CLOB)
 EOS
-    expected_values << {
-      :obj_name => 'TEST_TYPE_HAS_CLOB',
+    attrs_map['TEST_TYPE_HAS_CLOB'] = {
+      :class => OCI8::Metadata::Type,
       :has_lob? => true,
       :has_file? => false,
     }
@@ -1262,8 +1687,8 @@
       @conn.exec(<<-EOS)
 CREATE TYPE test_type_has_nclob AS OBJECT (lob NCLOB)
 EOS
-      expected_values << {
-        :obj_name => 'TEST_TYPE_HAS_NCLOB',
+      attrs_map['TEST_TYPE_HAS_NCLOB'] = {
+        :class => OCI8::Metadata::Type,
         :has_lob? => true,
         :has_file? => false,
       }
@@ -1271,16 +1696,16 @@
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_has_blob AS OBJECT (lob BLOB)
 EOS
-    expected_values << {
-      :obj_name => 'TEST_TYPE_HAS_BLOB',
+    attrs_map['TEST_TYPE_HAS_BLOB'] = {
+      :class => OCI8::Metadata::Type,
       :has_lob? => true,
       :has_file? => false,
     }
     @conn.exec(<<-EOS)
 CREATE TYPE test_type_has_bfile AS OBJECT (lob BFILE)
 EOS
-    expected_values << {
-      :obj_name => 'TEST_TYPE_HAS_BFILE',
+    attrs_map['TEST_TYPE_HAS_BFILE'] = {
+      :class => OCI8::Metadata::Type,
       :has_lob? => false,
       :has_file? => true,
     }
@@ -1291,9 +1716,60 @@
   MAP MEMBER FUNCTION area RETURN NUMBER
 )
 EOS
-    expected_values << {
-      :obj_name => 'TEST_TYPE_MAP_METHOD',
-      :map_method => [:type, OCI8::Metadata::TypeMethod],
+    attrs_map['TEST_TYPE_MAP_METHOD'] = {
+      :class => OCI8::Metadata::Type,
+      :map_method => {
+        :class => OCI8::Metadata::TypeMethod,
+        :name => 'AREA',
+        :encapsulation => :public,
+        :has_result? => true,
+        :is_constructor? => false,
+        :is_destructor? => false,
+        :is_operator? => false,
+        :is_selfish? => true,
+        :is_map? => true,
+        :is_order? => false,
+        :is_rnds? => true,
+        :is_rnps? => true,
+        :is_wnds? => true,
+        :is_wnps? => true,
+        :is_final_method? => false,
+        :is_instantiable_method? => true,
+        :is_overriding_method? => false,
+        :arguments => {
+          :class => Array,
+          :size => 1,
+          [0] => {
+            :class => OCI8::Metadata::TypeArgument,
+            :obj_id => nil,
+            :obj_name => nil,
+            :obj_schema => nil,
+            :name => "SELF",
+            :position => 1,
+            #:typecode => nil,
+            :data_type => :named_type,
+            #:data_size => 0, # ORA-24328: illegal attribute value
+            #:precision => 0, # ORA-24328: illegal attribute value
+            #:scale => 0, # ORA-24328: illegal attribute value
+            :level => 0,
+            :has_default => 0,
+            :has_default? => false,
+            :iomode => :in,
+            #:radix => 0, # ORA-24328: illegal attribute value
+            :type_name => "TEST_TYPE_MAP_METHOD",
+            :schema_name => @conn.username,
+            #:sub_name => nil, # ORA-24328: illegal attribute value
+            #:link => nil, # ORA-24328: illegal attribute value
+            :type_metadata => {
+              :class => OCI8::Metadata::Type,
+              :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TEST_TYPE_MAP_METHOD>",
+            },
+            :arguments => [],
+            :inspect => "#<OCI8::Metadata::TypeArgument: SELF #{@conn.username}.TEST_TYPE_MAP_METHOD>",
+          },
+        },
+        :inspect => '#<OCI8::Metadata::TypeMethod: AREA>',
+      },
       :order_method => nil,
     }
     @conn.exec(<<-EOS)
@@ -1303,42 +1779,100 @@
   ORDER MEMBER FUNCTION match(l test_type_order_method) RETURN INTEGER
 )
 EOS
-    expected_values << {
-      :obj_name => 'TEST_TYPE_ORDER_METHOD',
+    attrs_map['TEST_TYPE_ORDER_METHOD'] = {
+      :class => OCI8::Metadata::Type,
       :map_method => nil,
-      :order_method => [:type, OCI8::Metadata::TypeMethod],
+      :order_method => {
+        :class => OCI8::Metadata::TypeMethod,
+        :name => 'MATCH',
+        :encapsulation => :public,
+        :has_result? => true,
+        :is_constructor? => false,
+        :is_destructor? => false,
+        :is_operator? => false,
+        :is_selfish? => true,
+        :is_map? => false,
+        :is_order? => true,
+        :is_rnds? => true,
+        :is_rnps? => true,
+        :is_wnds? => true,
+        :is_wnps? => true,
+        :is_final_method? => false,
+        :is_instantiable_method? => true,
+        :is_overriding_method? => false,
+        :arguments => {
+          :class => Array,
+          :size => 2,
+          [0] => {
+            :class => OCI8::Metadata::TypeArgument,
+            :obj_id => nil,
+            :obj_name => nil,
+            :obj_schema => nil,
+            :name => "SELF",
+            :position => 1,
+            :typecode => :named_type,
+            :data_type => :named_type,
+            #:data_size => 0, # ORA-24328: illegal attribute value
+            #:precision => 0, # ORA-24328: illegal attribute value
+            #:scale => 0, # ORA-24328: illegal attribute value
+            :level => 0,
+            :has_default => 0,
+            :has_default? => false,
+            :iomode => :in,
+            #:radix => 0, # ORA-24328: illegal attribute value
+            :type_name => "TEST_TYPE_ORDER_METHOD",
+            :schema_name => @conn.username,
+            #:sub_name => nil, # ORA-24328: illegal attribute value
+            #:link => nil, # ORA-24328: illegal attribute value
+            :type_metadata => {
+              :class => OCI8::Metadata::Type,
+              :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TEST_TYPE_ORDER_METHOD>",
+            },
+            :arguments => [],
+            :inspect => "#<OCI8::Metadata::TypeArgument: SELF #{@conn.username}.TEST_TYPE_ORDER_METHOD>",
+          },
+          [1] => {
+            :class => OCI8::Metadata::TypeArgument,
+            :obj_id => nil,
+            :obj_name => nil,
+            :obj_schema => nil,
+            :name => "L",
+            :position => 2,
+            :typecode => :named_type,
+            :data_type => :named_type,
+            #:data_size => 0, # ORA-24328: illegal attribute value
+            #:precision => 0, # ORA-24328: illegal attribute value
+            #:scale => 0, # ORA-24328: illegal attribute value
+            :level => 0,
+            :has_default => 0,
+            :has_default? => false,
+            :iomode => :in,
+            #:radix => 0, # ORA-24328: illegal attribute value
+            :type_name => "TEST_TYPE_ORDER_METHOD",
+            :schema_name => @conn.username,
+            #:sub_name => nil, # ORA-24328: illegal attribute value
+            #:link => nil, # ORA-24328: illegal attribute value
+            :type_metadata => {
+              :class => OCI8::Metadata::Type,
+              :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TEST_TYPE_ORDER_METHOD>",
+            },
+            :arguments => [],
+            :inspect => "#<OCI8::Metadata::TypeArgument: L #{@conn.username}.TEST_TYPE_ORDER_METHOD>",
+          },
+        },
+        :inspect => '#<OCI8::Metadata::TypeMethod: MATCH>',
+      },
     }
 
-    expected_values.each do |elem|
+    attrs_map.each do |name, attrs|
       [
-       @conn.describe_any(elem[:obj_name]),
-       @conn.describe_type(elem[:obj_name]),
+       @conn.describe_any(name),
+       @conn.describe_type(name),
        @conn.describe_schema(@conn.username).objects.detect do |obj|
-         obj.obj_name == elem[:obj_name]
+         obj.obj_name == name
        end,
       ].each do |desc|
-        assert_object_id(elem[:obj_name], desc.obj_id)
-        assert_equal(@conn.username, desc.obj_schema)
-        assert_equal(elem[:obj_name], desc.name)
-        assert_equal(@conn.username, desc.schema_name)
-
-        elem.each do |key, val|
-          msg = elem[:obj_name] + '.' + key.to_s
-          if val.is_a? Array
-            case val[0]
-            when :array
-              assert_instance_of(Array, desc.send(key), msg)
-              assert_equal(val[1], desc.send(key).length)
-              assert_instance_of(val[2], desc.send(key)[0]) if val[1] > 0
-            when :type
-              assert_instance_of(val[1], desc.send(key), msg)
-            else
-              raise "Invalid test case: #{elem[:obj_name]}.#{key} : #{val[0]}"
-            end
-          else
-            assert_equal(val, desc.send(key), msg)
-          end
-        end
+        check_attributes(name, desc, attrs)
       end
     end
 
@@ -1357,22 +1891,570 @@
   end # test_type_metadata
 
   def test_column_metadata
-    if $oracle_version < OCI8::ORAVER_8_1
-      begin
-        @conn.describe_table('tab').columns
-      rescue RuntimeError
-        assert_equal("This feature is unavailable on Oracle 8.0", $!.to_s)
-      end
-      return
+
+    # Get data_size of NCHAR(1) and that of CHAR(1 CHAR).
+    # They depend on the database character set and the
+    # client character set.
+    cursor = @conn.exec("select N'1' from dual")
+    # cfrm: data_size of NCHAR(1).
+    cfrm = cursor.column_metadata[0].data_size
+    # csem: data_size of CHAR(1 CHAR).
+    cursor = @conn.exec("select CAST('1' AS CHAR(1 char)) from dual")
+    csem = cursor.column_metadata[0].data_size
+
+    column_attrs_list = []
+
+    column_attrs_list << {
+      :name => 'CHAR_10_NOT_NULL_COL',
+      :data_type_string => 'CHAR(10) NOT NULL',
+      :data_type => :char,
+      :charset_form => :implicit,
+      :nullable? => false,
+      :char_used? => false,
+      :char_size => 10,
+      :data_size => 10,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: CHAR_10_NOT_NULL_COL CHAR(10) NOT NULL>',
+    }
+    column_attrs_list << {
+      :name => 'CHAR_10_CHAR_COL',
+      :data_type_string => 'CHAR(10 CHAR)',
+      :data_type => :char,
+      :charset_form => :implicit,
+      :nullable? => true,
+      :char_used? => true,
+      :char_size => 10,
+      :data_size => 10 * csem,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: CHAR_10_CHAR_COL CHAR(10 CHAR)>',
+    }
+    column_attrs_list << {
+      :name => 'NCHAR_10_COL',
+      :data_type_string => 'NCHAR(10)',
+      :data_type => :char,
+      :charset_form => :nchar,
+      :nullable? => true,
+      :char_used? => true,
+      :char_size => 10,
+      :data_size => 10 * cfrm,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: NCHAR_10_COL NCHAR(10)>',
+    }
+    column_attrs_list << {
+      :name => 'VARCHAR2_10_COL',
+      :data_type_string => 'VARCHAR2(10)',
+      :data_type => :varchar2,
+      :charset_form => :implicit,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 10,
+      :data_size => 10,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: VARCHAR2_10_COL VARCHAR2(10)>',
+    }
+    column_attrs_list << {
+      :name => 'VARCHAR2_10_CHAR_COL',
+      :data_type_string => 'VARCHAR2(10 CHAR)',
+      :data_type => :varchar2,
+      :charset_form => :implicit,
+      :nullable? => true,
+      :char_used? => true,
+      :char_size => 10,
+      :data_size => 10 * csem,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: VARCHAR2_10_CHAR_COL VARCHAR2(10 CHAR)>',
+    }
+    column_attrs_list << {
+      :name => 'NVARCHAR2_10_COL',
+      :data_type_string => 'NVARCHAR2(10)',
+      :data_type => :varchar2,
+      :charset_form => :nchar,
+      :nullable? => true,
+      :char_used? => true,
+      :char_size => 10,
+      :data_size => 10 * cfrm,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: NVARCHAR2_10_COL NVARCHAR2(10)>',
+    }
+    column_attrs_list << {
+      :name => 'RAW_10_COL',
+      :data_type_string => 'RAW(10)',
+      :data_type => :raw,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 10,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: RAW_10_COL RAW(10)>',
+    }
+
+    # Skip tests for data_size of CLOB, NCLOB and BLOB
+    # because their values depend on how they are described.
+    #
+    #  Oracle 10g XE 10.2.0.1.0 on Linux:
+    #   +----------------+-----------+
+    #   |                | data_size |
+    #   +----------------+-----------+
+    #   | implicitly(*1) |   4000    |
+    #   | explicitly(*2) |     86    |
+    #   +----------------+-----------+
+    #
+    # *1 explicitly described by column definition.
+    # *2 implicitly described by select list.
+    column_attrs_list << {
+      :name => 'CLOB_COL',
+      :data_type_string => 'CLOB',
+      :data_type => :clob,
+      :charset_form => :implicit,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => :skip,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: CLOB_COL CLOB>',
+    }
+    column_attrs_list << {
+      :name => 'NCLOB_COL',
+      :data_type_string => 'NCLOB',
+      :data_type => :clob,
+      :charset_form => :nchar,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => :skip,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: NCLOB_COL NCLOB>',
+    }
+    column_attrs_list << {
+      :name => 'BLOB_COL',
+      :data_type_string => 'BLOB',
+      :data_type => :blob,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => :skip,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: BLOB_COL BLOB>',
+    }
+    column_attrs_list << {
+      :name => 'BFILE_COL',
+      :data_type_string => 'BFILE',
+      :data_type => :bfile,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 530,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: BFILE_COL BFILE>',
+    }
+
+    # Skip tests for fsprecision and lfprecision for NUMBER and FLOAT
+    # because their values depend on how they are described.
+    #
+    #  Oracle 10g XE 10.2.0.1.0 on Linux:
+    #   +-----------------------------+-------------+-------------+
+    #   |                             | fsprecision | lfprecision |
+    #   +----------------+------------+-------------+-------------+
+    #   | NUMBER         | implicitly |     129     |      0      |
+    #   |                | explicitly |       0     |    129      |
+    #   +----------------+------------+-------------+-------------+
+    #   | NUMBER(10)     | implicitly |       0     |     10      |
+    #   |                | explicitly |      10     |      0      |
+    #   +----------------+------------+-------------+-------------+
+    #   | NUMBER(10,2)   | implicitly |       2     |     10      |
+    #   |                | explicitly |      10     |      2      |
+    #   +----------------+------------+-------------+-------------+
+    #   | FLOAT          | implicitly |     129     |    126      |
+    #   |                | explicitly |     126     |    129      |
+    #   +----------------+------------+-------------+-------------+
+    #   | FLOAT(10)      | implicitly |     129     |     10      |
+    #   |                | explicitly |      10     |    129      |
+    #   +----------------+------------+-------------+-------------+
+    column_attrs_list << {
+      :name => 'NUMBER_COL',
+      :data_type_string => 'NUMBER',
+      :data_type => :number,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 22,
+      :precision => 0,
+      :scale => -127,
+      :fsprecision => :skip,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: NUMBER_COL NUMBER>',
+    }
+    column_attrs_list << {
+      :name => 'NUMBER_10_COL',
+      :data_type_string => 'NUMBER(10)',
+      :data_type => :number,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 22,
+      :precision => 10,
+      :scale => 0,
+      :fsprecision => :skip,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: NUMBER_10_COL NUMBER(10)>',
+    }
+    column_attrs_list << {
+      :name => 'NUMBER_10_2_COL',
+      :data_type_string => 'NUMBER(10,2)',
+      :data_type => :number,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 22,
+      :precision => 10,
+      :scale => 2,
+      :fsprecision => :skip,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: NUMBER_10_2_COL NUMBER(10,2)>',
+    }
+    column_attrs_list << {
+      :name => 'FLOAT_COL',
+      :data_type_string => 'FLOAT',
+      :data_type => :number,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 22,
+      :precision => 126,
+      :scale => -127,
+      :fsprecision => :skip,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: FLOAT_COL FLOAT>',
+    }
+    column_attrs_list << {
+      :name => 'FLOAT_10_COL',
+      :data_type_string => 'FLOAT(10)',
+      :data_type => :number,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 22,
+      :precision => 10,
+      :scale => -127,
+      :fsprecision => :skip,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: FLOAT_10_COL FLOAT(10)>',
+    }
+    if $oracle_version >= OCI8::ORAVER_10_1
+      column_attrs_list << {
+        :name => 'BINARY_FLOAT_COL',
+        :data_type_string => 'BINARY_FLOAT',
+        :data_type => :binary_float,
+        :charset_form => nil,
+        :nullable? => true,
+        :char_used? => false,
+        :char_size => 0,
+        :data_size => 4,
+        :precision => 0,
+        :scale => 0,
+        :fsprecision => 0,
+        :lfprecision => 0,
+        :inspect => '#<OCI8::Metadata::Column: BINARY_FLOAT_COL BINARY_FLOAT>',
+      }
+      column_attrs_list << {
+        :name => 'BINARY_DOUBLE_COL',
+        :data_type_string => 'BINARY_DOUBLE',
+        :data_type => :binary_double,
+        :charset_form => nil,
+        :nullable? => true,
+        :char_used? => false,
+        :char_size => 0,
+        :data_size => 8,
+        :precision => 0,
+        :scale => 0,
+        :fsprecision => 0,
+        :lfprecision => 0,
+        :inspect => '#<OCI8::Metadata::Column: BINARY_DOUBLE_COL BINARY_DOUBLE>',
+      }
     end
+    column_attrs_list << {
+      :name => 'DATE_COL',
+      :data_type_string => 'DATE',
+      :data_type => :date,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 7,
+      :precision => 0,
+      :scale => 0,
+      :fsprecision => 0,
+      :lfprecision => 0,
+      :inspect => '#<OCI8::Metadata::Column: DATE_COL DATE>',
+    }
 
-    coldef = @@column_test_data.find_all do |c|
-      c.available?(@conn)
+    # Skip tests for precision and lfprecision for TIMESTAMP
+    # because their values depend on how they are described.
+    #
+    #  Oracle 10g XE 10.2.0.1.0 on Linux:
+    #   +------------------------------------------------+-----------+-------------+
+    #   |                                                | precision | lfprecision |
+    #   +-----------------------------------+------------+-----------+-------------+
+    #   | TIMESTAMP                         | implicitly |     0     |      0      |
+    #   |                                   | explicitly |     6     |      6      |
+    #   +-----------------------------------+------------+-----------+-------------+
+    #   | TIMESTAMP(9)                      | implicitly |     0     |      0      |
+    #   |                                   | explicitly |     9     |      9      |
+    #   +-----------------------------------+------------+-----------+-------------+
+    #   | TIMESTAMP WITH TIME ZONE          | implicitly |     0     |      0      |
+    #   |                                   | explicitly |     6     |      6      |
+    #   +-----------------------------------+------------+-----------+-------------+
+    #   | TIMESTAMP(9) WITH TIME ZONE       | implicitly |     0     |      0      |
+    #   |                                   | explicitly |     9     |      9      |
+    #   +-----------------------------------+------------+-----------+-------------+
+    #   | TIMESTAMP WITH LOCAL TIME ZONE    | implicitly |     0     |      0      |
+    #   |                                   | explicitly |     6     |      6      |
+    #   +-----------------------------------+------------+-----------+-------------+
+    #   | TIMESTAMP(9) WITH LOCAL TIME ZONE | implicitly |     0     |      0      |
+    #   |                                   | explicitly |     9     |      9      |
+    #   +-----------------------------------+------------+-----------+-------------+
+    column_attrs_list << {
+      :name => 'TIMESTAMP_COL',
+      :data_type_string => 'TIMESTAMP',
+      :data_type => :timestamp,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 11,
+      :precision => :skip,
+      :scale => 6,
+      :fsprecision => 6,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: TIMESTAMP_COL TIMESTAMP>',
+    }
+    column_attrs_list << {
+      :name => 'TIMESTAMP_9_COL',
+      :data_type_string => 'TIMESTAMP(9)',
+      :data_type => :timestamp,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 11,
+      :precision => :skip,
+      :scale => 9,
+      :fsprecision => 9,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: TIMESTAMP_9_COL TIMESTAMP(9)>',
+    }
+    column_attrs_list << {
+      :name => 'TIMESTAMP_TZ_COL',
+      :data_type_string => 'TIMESTAMP WITH TIME ZONE',
+      :data_type => :timestamp_tz,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 13,
+      :precision => :skip,
+      :scale => 6,
+      :fsprecision => 6,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: TIMESTAMP_TZ_COL TIMESTAMP WITH TIME ZONE>',
+    }
+    column_attrs_list << {
+      :name => 'TIMESTAMP_9_TZ_COL',
+      :data_type_string => 'TIMESTAMP(9) WITH TIME ZONE',
+      :data_type => :timestamp_tz,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 13,
+      :precision => :skip,
+      :scale => 9,
+      :fsprecision => 9,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: TIMESTAMP_9_TZ_COL TIMESTAMP(9) WITH TIME ZONE>',
+    }
+    column_attrs_list << {
+      :name => 'TIMESTAMP_LTZ_COL',
+      :data_type_string => 'TIMESTAMP WITH LOCAL TIME ZONE',
+      :data_type => :timestamp_ltz,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 11,
+      :precision => :skip,
+      :scale => 6,
+      :fsprecision => 6,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: TIMESTAMP_LTZ_COL TIMESTAMP WITH LOCAL TIME ZONE>',
+    }
+    column_attrs_list << {
+      :name => 'TIMESTAMP_9_LTZ_COL',
+      :data_type_string => 'TIMESTAMP(9) WITH LOCAL TIME ZONE',
+      :data_type => :timestamp_ltz,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 11,
+      :precision => :skip,
+      :scale => 9,
+      :fsprecision => 9,
+      :lfprecision => :skip,
+      :inspect => '#<OCI8::Metadata::Column: TIMESTAMP_9_LTZ_COL TIMESTAMP(9) WITH LOCAL TIME ZONE>',
+    }
+
+    # Skip tsets for scale and fsprecision for INTERVAL YEAR TO MONTH
+    # because their values depend on how they are described.
+    #
+    #  Oracle 10g XE 10.2.0.1.0 on Linux:
+    #   +-------------------------------------------+-----------+-------------+
+    #   |                                           |   scale   | fsprecision |
+    #   +------------------------------+------------+-----------+-------------+
+    #   | INTERVAL YEAR TO MONTH       | implicitly |     0     |      0      |
+    #   |                              | explicitly |     2     |      2      |
+    #   +------------------------------+------------+-----------+-------------+
+    #   | INTERVAL YEAR(4) TO MONTH    | implicitly |     0     |      0      |
+    #   |                              | explicitly |     4     |      4      |
+    #   +------------------------------+------------+-----------+-------------+
+    column_attrs_list << {
+      :name => 'INTERVAL_YM_COL',
+      :data_type_string => 'INTERVAL YEAR TO MONTH',
+      :data_type => :interval_ym,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 5,
+      :precision => 2,
+      :scale => :skip,
+      :fsprecision => :skip,
+      :lfprecision => 2,
+      :inspect => '#<OCI8::Metadata::Column: INTERVAL_YM_COL INTERVAL YEAR TO MONTH>',
+    }
+    column_attrs_list << {
+      :name => 'INTERVAL_YM_4_COL',
+      :data_type_string => 'INTERVAL YEAR(4) TO MONTH',
+      :data_type => :interval_ym,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 5,
+      :precision => 4,
+      :scale => :skip,
+      :fsprecision => :skip,
+      :lfprecision => 4,
+      :inspect => '#<OCI8::Metadata::Column: INTERVAL_YM_4_COL INTERVAL YEAR(4) TO MONTH>',
+    }
+
+    # Skip tests for precision and scale for INTERVAL DAY TO SECOND
+    # because their values depend on how they are described.
+    #
+    #  Oracle 10g XE 10.2.0.1.0 on Linux:
+    #   +-------------------------------------------+-----------+-----------+
+    #   |                                           | precision |   scale   |
+    #   +------------------------------+------------+-----------+-----------+
+    #   | INTERVAL DAY TO SECOND       | implicitly |     2     |     6     |
+    #   |                              | explicitly |     6     |     2     |
+    #   +------------------------------+------------+-----------+-----------+
+    #   | INTERVAL DAY(4) TO SECOND(9) | implicitly |     4     |     9     |
+    #   |                              | explicitly |     9     |     4     |
+    #   +------------------------------+------------+-----------+-----------+
+    column_attrs_list << {
+      :name => 'INTERVAL_DS_COL',
+      :data_type_string => 'INTERVAL DAY TO SECOND',
+      :data_type => :interval_ds,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 11,
+      :precision => :skip,
+      :scale => :skip,
+      :fsprecision => 6,
+      :lfprecision => 2,
+      :inspect => '#<OCI8::Metadata::Column: INTERVAL_DS_COL INTERVAL DAY TO SECOND>',
+    }
+    column_attrs_list << {
+      :name => 'INTERVAL_DS_4_9_COL',
+      :data_type_string => 'INTERVAL DAY(4) TO SECOND(9)',
+      :data_type => :interval_ds,
+      :charset_form => nil,
+      :nullable? => true,
+      :char_used? => false,
+      :char_size => 0,
+      :data_size => 11,
+      :precision => :skip,
+      :scale => :skip,
+      :fsprecision => 9,
+      :lfprecision => 4,
+      :inspect => '#<OCI8::Metadata::Column: INTERVAL_DS_4_9_COL INTERVAL DAY(4) TO SECOND(9)>',
+    }
+
+    # Object Types
+    if $oracle_version >= OCI8::ORAVER_10_1
+      column_attrs_list << {
+        :name => 'SDO_GEOMETRY_COL',
+        :data_type_string => 'MDSYS.SDO_GEOMETRY',
+        :data_type => :named_type,
+        :charset_form => nil,
+        :nullable? => true,
+        :char_used? => false,
+        :char_size => 0,
+        :data_size => :skip, # 1 when explicitly, 2000 when implicitly.
+        :precision => 0,
+        :scale => 0,
+        :fsprecision => 0,
+        :lfprecision => 0,
+        :inspect => '#<OCI8::Metadata::Column: SDO_GEOMETRY_COL MDSYS.SDO_GEOMETRY>',
+      }
     end
 
     drop_table('test_table')
     sql = <<-EOS
-CREATE TABLE test_table (#{idx = 0; coldef.collect do |c| idx += 1; "C#{idx} " + c.data_type_string; end.join(',')})
+CREATE TABLE test_table (#{column_attrs_list.collect do |c| c[:name] + " " + c[:data_type_string]; end.join(',')})
 STORAGE (
    INITIAL 100k
    NEXT 100k
@@ -1381,7 +2463,6 @@
    PCTINCREASE 0)
 EOS
     @conn.exec(sql)
-
     [
      @conn.describe_any('test_table').columns,
      @conn.describe_table('test_table').columns,
@@ -1390,44 +2471,36 @@
      end.columns,
      @conn.exec('select * from test_table').column_metadata,
     ].each do |columns|
-        columns.each_with_index do |column, i|
-        assert_equal("C#{i + 1}", column.name, "'#{coldef[i].data_type_string}': name")
-        DatatypeData.attributes.each do |attr|
-          expected_val = coldef[i].send(attr)
-          if expected_val != :skip
-            assert_equal(expected_val, column.send(attr), "'#{coldef[i].data_type_string}': #{attr})")
-          end
-        end
+      column_attrs_list.each_with_index do |attrs, idx|
+        check_attributes(attrs[:name], columns[idx], attrs)
       end
     end
     drop_table('test_table')
   end # test_column_metadata
 
-  def assert_sequence(sequence_name, desc)
-    # defined in OCI8::Metadata::Base
-    assert_object_id(sequence_name, desc.obj_id)
-    assert_equal(sequence_name, desc.obj_name, 'obj_name')
-    assert_equal(@conn.username, desc.obj_schema, 'obj_schema')
-    # defined in OCI8::Metadata::Sequence
-    assert_object_id(sequence_name, desc.objid)
+  def assert_sequence(sequence_name, desc, msg)
     min, max, incr, cache, order = @conn.select_one(<<EOS, sequence_name)
 select min_value, max_value, increment_by, cache_size, order_flag
   from user_sequences
  where sequence_name = :1
 EOS
-    min = min.to_i
-    max = max.to_i
-    incr = incr.to_i
-    cache = cache.to_i
-    order = order == 'Y'
     currval = @conn.select_one("select cast(#{sequence_name}.currval as integer) from dual")[0]
 
-    assert_equal(min, desc.min, 'min')
-    assert_equal(max, desc.max, 'max')
-    assert_equal(incr, desc.incr, 'incr')
-    assert_equal(cache, desc.cache, 'cache')
-    assert_equal(order, desc.order?, 'order?')
-    assert_operator(currval, :<=, desc.hw_mark, 'hw_mark')
+    attrs = {
+      :class => OCI8::Metadata::Sequence,
+      :obj_id => to_obj_id(@conn.username, sequence_name),
+      :obj_name => sequence_name,
+      :obj_schema => @conn.username,
+      :objid => to_obj_id(@conn.username, sequence_name),
+      :min => min.to_i,
+      :max => max.to_i,
+      :incr => incr.to_i,
+      :cache => cache.to_i,
+      :order? => order == 'Y',
+      :hw_mark => Proc.new {|v| currval <= v},
+      :inspect => /#<OCI8::Metadata::Sequence:\(\d+\) #{@conn.username}.#{sequence_name}/,
+    }
+    check_attributes(msg, desc, attrs)
   end
 
   def test_sequence
@@ -1447,13 +2520,13 @@
     ORDER
 EOS
     @conn.select_one('select test_seq_oci8.nextval from dual')
-    assert_sequence('TEST_SEQ_OCI8', @conn.describe_any('test_seq_oci8'))
+    assert_sequence('TEST_SEQ_OCI8', @conn.describe_any('test_seq_oci8'), "line: #{__LINE__}")
     @conn.select_one('select test_seq_oci8.nextval from dual')
-    assert_sequence('TEST_SEQ_OCI8', @conn.describe_sequence('test_seq_oci8'))
+    assert_sequence('TEST_SEQ_OCI8', @conn.describe_sequence('test_seq_oci8'), "line: #{__LINE__}")
     @conn.select_one('select test_seq_oci8.nextval from dual')
     assert_sequence('TEST_SEQ_OCI8', @conn.describe_schema(@conn.username).objects.detect do |obj|
                       obj.obj_name == 'TEST_SEQ_OCI8'
-                    end)
+                    end, "line: #{__LINE__}")
 
     @conn.exec("DROP SEQUENCE TEST_SEQ_OCI8")
     @conn.exec(<<-EOS)
@@ -1470,13 +2543,13 @@
     #   -999999999999999999999999999 on Oracle 11gR2
 
     @conn.select_one('select test_seq_oci8.nextval from dual')
-    assert_sequence('TEST_SEQ_OCI8', @conn.describe_any('test_seq_oci8'))
+    assert_sequence('TEST_SEQ_OCI8', @conn.describe_any('test_seq_oci8'), "line: #{__LINE__}")
     @conn.select_one('select test_seq_oci8.nextval from dual')
-    assert_sequence('TEST_SEQ_OCI8', @conn.describe_sequence('test_seq_oci8'))
+    assert_sequence('TEST_SEQ_OCI8', @conn.describe_sequence('test_seq_oci8'), "line: #{__LINE__}")
     @conn.select_one('select test_seq_oci8.nextval from dual')
     assert_sequence('TEST_SEQ_OCI8', @conn.describe_schema(@conn.username).objects.detect do |obj|
                       obj.obj_name == 'TEST_SEQ_OCI8'
-                    end)
+                    end, "line: #{__LINE__}")
 
     @conn.exec("DROP SEQUENCE TEST_SEQ_OCI8")
   end
@@ -1490,6 +2563,17 @@
 
     # private synonym
     begin
+      attrs = {
+        :class => OCI8::Metadata::Synonym,
+        :obj_id => nil,
+        :obj_name => 'TEST_SYNONYM',
+        :obj_schema => @conn.username,
+        :schema_name => 'FOO',
+        :name => 'BAR',
+        :link => 'BAZ.QUZ',
+        :translated_name => 'FOO.BAR at BAZ.QUZ',
+        :inspect => /#<OCI8::Metadata::Synonym:\(\d+\) #{@conn.username}.TEST_SYNONYM FOR FOO.BAR at BAZ.QUZ>/,
+      }
       @conn.exec("CREATE SYNONYM test_synonym FOR foo.bar at baz.quz")
       [
        @conn.describe_any('test_synonym'),
@@ -1497,31 +2581,34 @@
        @conn.describe_any(@conn.username + '.test_synonym'),
        @conn.describe_synonym(@conn.username + '.Test_Synonym'),
       ].each do |desc|
-        assert_equal(@conn.username, desc.obj_schema)
-        assert_equal('TEST_SYNONYM', desc.obj_name)
-        assert_equal('FOO', desc.schema_name)
-        assert_equal('BAR', desc.name)
-        assert_equal('BAZ.QUZ', desc.link)
-        assert_equal('FOO.BAR at BAZ.QUZ', desc.translated_name)
+        attrs[:obj_id] = to_obj_id(@conn.username, 'TEST_SYNONYM')
+        check_attributes('private synonym', desc, attrs)
       end
       @conn.exec("DROP SYNONYM test_synonym")
     rescue OCIError
-      raise if $!.code != 1031 # ORA-01031: insufficient privileges
+      raise "grant create synonym privilege to user #{@conn.username} to pass tests." if $!.code == 1031 # ORA-01031: insufficient privileges
+      raise
     end
 
     # public synonym
+    attrs = {
+      :class => OCI8::Metadata::Synonym,
+      :obj_id => to_obj_id('PUBLIC', 'SDO_GEOMETRY'),
+      :obj_name => 'SDO_GEOMETRY',
+      :obj_schema => 'PUBLIC',
+      :schema_name => 'MDSYS',
+      :name => 'SDO_GEOMETRY',
+      :link => nil,
+      :translated_name => 'MDSYS.SDO_GEOMETRY',
+      :inspect => /#<OCI8::Metadata::Synonym:\(\d+\) PUBLIC.SDO_GEOMETRY FOR MDSYS.SDO_GEOMETRY>/,
+    }
     [
      @conn.describe_any('sdo_geometry'),
      @conn.describe_synonym('sdo_geometry'),
      @conn.describe_any('public.sdo_geometry'),
      @conn.describe_synonym('PUBLIC.sdo_geometry'),
     ].each do |desc|
-      assert_equal('PUBLIC', desc.obj_schema)
-      assert_equal('SDO_GEOMETRY', desc.obj_name)
-      assert_equal('MDSYS', desc.schema_name)
-      assert_equal('SDO_GEOMETRY', desc.name)
-      assert_equal(nil, desc.link)
-      assert_equal('MDSYS.SDO_GEOMETRY', desc.translated_name)
+      check_attributes('public synonym', desc, attrs)
     end
 
   end

Modified: trunk/ruby-oci8/test/test_package_type.rb
===================================================================
--- trunk/ruby-oci8/test/test_package_type.rb	2013-07-30 06:37:17 UTC (rev 573)
+++ trunk/ruby-oci8/test/test_package_type.rb	2013-08-03 13:00:00 UTC (rev 574)
@@ -68,9 +68,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => nil,
       :type_attrs => [],
       #:type_methods => [],
+      :inspect => '#<OCI8::Metadata::Type:(0) SYS.INTEGER>', # TODO: change to "INTEGER"
     }
 
     pls_integer_type_attrs = {
@@ -96,9 +99,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => nil,
       :type_attrs => [],
       #:type_methods => [],
+      :inspect => '#<OCI8::Metadata::Type:(0) SYS.PL/SQL PLS INTEGER>', # TODO: change to "PLS_INTEGER"
     }
 
     boolean_type_attrs = {
@@ -124,9 +130,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => nil,
       :type_attrs => [],
       #:type_methods => [],
+      :inspect => '#<OCI8::Metadata::Type:(0) SYS.PL/SQL BOOLEAN>', # TODO: change to "BOOLEAN"
     }
 
     varchar2_type_attrs = {
@@ -152,9 +161,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => nil,
       :type_attrs => [],
       #:type_methods => #[],
+      :inspect => '#<OCI8::Metadata::Type:(0) SYS.VARCHAR2>', # TODO: change to "VARCHAR2"
     }
 
     array_of_integer_type_attrs = {
@@ -180,6 +192,7 @@
         :type_name => 'INTEGER',
         :schema_name => 'SYS',
         :type_metadata => integer_type_attrs,
+        :inspect => '#<OCI8::Metadata::Collection: NUMBER(38)>', # TODO: change to "INTEGER"
       },
       :num_type_attrs => 0,
       :num_type_methods => 0,
@@ -191,9 +204,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => [],
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.ARRAY_OF_INTEGER>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.ARRAY_OF_INTEGER"
     }
 
     table_of_pls_integer_type_attrs = {
@@ -219,6 +235,7 @@
         :type_name => 'PL/SQL PLS INTEGER',
         :schema_name => 'SYS',
         :type_metadata => pls_integer_type_attrs,
+        :inspect => '#<OCI8::Metadata::Collection: PLS_INTEGER>',
       },
       :num_type_attrs => 0,
       :num_type_methods => 0,
@@ -230,9 +247,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => [],
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TABLE_OF_PLS_INTEGER>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.TABLE_OF_PLS_INTEGER"
     }
 
     table_of_boolean_type_attrs = {
@@ -258,6 +278,7 @@
         :type_name => 'PL/SQL BOOLEAN',
         :schema_name => 'SYS',
         :type_metadata => boolean_type_attrs,
+        :inspect => '#<OCI8::Metadata::Collection: BOOLEAN>',
       },
       :num_type_attrs => 0,
       :num_type_methods => 0,
@@ -269,9 +290,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => [],
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TABLE_OF_BOOLEAN>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.TABLE_OF_BOOLEAN"
     }
 
     indexed_table_of_varchar2_type_attrs = {
@@ -297,6 +321,7 @@
         :type_name => 'VARCHAR2',
         :schema_name => 'SYS',
         :type_metadata => varchar2_type_attrs,
+        :inspect => '#<OCI8::Metadata::Collection: VARCHAR2(10)>',
       },
       :num_type_attrs => 0,
       :num_type_methods => 0,
@@ -308,9 +333,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => [],
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.INDEXED_TABLE_OF_VARCHAR2>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.INDEXED_TABLE_OF_VARCHAR2"
     }
 
     rec1_type_attrs = {
@@ -336,6 +364,8 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => {
         :class => Array,
@@ -353,6 +383,7 @@
           :fsprecision => 0,
           :lfprecision => 0,
           :type_metadata => pls_integer_type_attrs,
+          :inspect => '#<OCI8::Metadata::TypeAttr: I PLS_INTEGER>',
         },
         [1] => {
           :class => OCI8::Metadata::TypeAttr,
@@ -367,9 +398,11 @@
           :fsprecision => 0,
           :lfprecision => 0,
           :type_metadata => integer_type_attrs,
+          :inspect => '#<OCI8::Metadata::TypeAttr: J NUMBER(38)>', # TODO: change to "INTEGER"
         },
       },
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.REC1>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.REC1"
     }
 
     rec2_type_attrs = {
@@ -395,6 +428,8 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => {
         :class => Array,
@@ -412,6 +447,7 @@
           :fsprecision => 0,
           :lfprecision => 0,
           :type_metadata => boolean_type_attrs,
+          :inspect => '#<OCI8::Metadata::TypeAttr: B BOOLEAN>',
         },
         [1] => {
           :class => OCI8::Metadata::TypeAttr,
@@ -426,6 +462,7 @@
           :fsprecision => 0,
           :lfprecision => 0,
           :type_metadata => indexed_table_of_varchar2_type_attrs,
+          :inspect => "#<OCI8::Metadata::TypeAttr: IT #{@conn.username}.INDEXED_TABLE_OF_VARCHAR2>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.INDEXED_TABLE_OF_VARCHAR2"
         },
         [2] => {
           :class => OCI8::Metadata::TypeAttr,
@@ -440,9 +477,11 @@
           :fsprecision => 0,
           :lfprecision => 0,
           :type_metadata => rec1_type_attrs,
+          :inspect => "#<OCI8::Metadata::TypeAttr: REC #{@conn.username}.REC1>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.REC1"
         },
       },
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.REC2>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.REC2"
     }
 
     table_of_rec1_type_attrs = {
@@ -468,6 +507,7 @@
         :type_name => 'REC1',
         :schema_name => @conn.username,
         :type_metadata => rec1_type_attrs,
+        :inspect => "#<OCI8::Metadata::Collection: #{@conn.username}.REC1>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.REC1"
       },
       :num_type_attrs => 0,
       :num_type_methods => 0,
@@ -479,9 +519,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => [],
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TABLE_OF_REC1>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.TABLE_OF_REC1"
     }
 
     table_of_rec2_type_attrs = {
@@ -507,6 +550,8 @@
         :type_name => 'REC2',
         :schema_name => @conn.username,
         :type_metadata => rec2_type_attrs,
+        :inspect => "#<OCI8::Metadata::Collection: #{@conn.username}.REC2>",
+        #:inspect => "#<OCI8::Metadata::Collection: #{@conn.username}.RB_TEST_PKG.REC2>",
       },
       :num_type_attrs => 0,
       :num_type_methods => 0,
@@ -518,9 +563,12 @@
       :is_final_type? => true,
       :is_instantiable_type? => true,
       :is_subtype? => false,
+      :supertype_schema_name => nil,
+      :supertype_name => nil,
       :package_name => 'RB_TEST_PKG',
       :type_attrs => [],
       :type_methods => [],
+      :inspect => "#<OCI8::Metadata::Type:(0) #{@conn.username}.TABLE_OF_REC2>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.TABLE_OF_REC2"
     }
 
     type_metadata_attrs = {
@@ -566,6 +614,7 @@
           :link => "",
           #:type_metadata => nil,
           :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument:  unknown(3)>', # TODO: change to "PLS_INTEGER"
         },
         [1] => {
           :class => OCI8::Metadata::Argument,
@@ -613,11 +662,14 @@
               :link => "",
               #:type_metadata => nil,
               :arguments => [],
+              :inspect => '#<OCI8::Metadata::Argument:  unknown(3)>', # TODO: change to "PLS_INTEGER"
             },
           },
+          :inspect => "#<OCI8::Metadata::Argument: TBL #{@conn.username}.RB_TEST_PKG>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.TABLE_OF_PLS_INTEGER"
         },
       },
       :is_standalone? => false,
+      :inspect => '#<OCI8::Metadata::Function: SUM_TABLE_OF_PLS_INTEGER>', # FIXME
     }
 
     add_rec1_values_subprogram_attrs = {
@@ -652,6 +704,7 @@
           :link => "",
           #:type_metadata => nil,
           :arguments => [],
+          :inspect => '#<OCI8::Metadata::Argument:  unknown(3)>', # TODO: change to "PLS_INTEGER"
         },
         [1] => {
           :class => OCI8::Metadata::Argument,
@@ -723,6 +776,7 @@
                   :link => "",
                   #:type_metadata => nil,
                   :arguments => [],
+                  :inspect => '#<OCI8::Metadata::Argument: I unknown(3)>', # TODO: change to "PLS_INTEGER"
                 },
                 [1] => {
                   :class => OCI8::Metadata::Argument,
@@ -746,13 +800,17 @@
                   :link => "",
                   #:type_metadata => nil,
                   :arguments => [],
+                  :inspect => '#<OCI8::Metadata::Argument: J NUMBER(38)>', # TODO: change to "INTEGER"
                 },
               },
+              :inspect => '#<OCI8::Metadata::Argument:  unknown(250)>', # TODO: change to "#{@conn.username}.RB_TEST_PKG.REC1"
             },
           },
+          :inspect => "#<OCI8::Metadata::Argument: TBL #{@conn.username}.RB_TEST_PKG>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.TABLE_OF_REC1"
         },
       },
       :is_standalone? => false,
+      :inspect => '#<OCI8::Metadata::Function: ADD_REC1_VALUES>', # TODO: change to "#{@conn.username}.RB_TEST_PKG.ADD_REC1_VALUES"
     }
 
     out_rec1_values_subprogram_attrs = {
@@ -835,6 +893,7 @@
                   :link => "",
                   #:type_metadata => nil,
                   :arguments => [],
+                  :inspect => '#<OCI8::Metadata::Argument: I unknown(3)>', # TODO: change to "PLS_INTEGER"
                 },
                 [1] => {
                   :class => OCI8::Metadata::Argument,
@@ -858,13 +917,17 @@
                   :link => "",
                   #:type_metadata => nil,
                   :arguments => [],
+                  :inspect => '#<OCI8::Metadata::Argument: J NUMBER(38)>', # TODO: change to "INTEGER"
                 },
               },
+              :inspect => '#<OCI8::Metadata::Argument:  unknown(250)>', # TODO: change to "#{@conn.username}.RB_TEST_PKG.REC1"
             },
           },
+          :inspect => "#<OCI8::Metadata::Argument: TBL #{@conn.username}.RB_TEST_PKG>", # TODO: change to "#{@conn.username}.RB_TEST_PKG.TABLE_OF_REC1"
         },
       },
       :is_standalone? => false,
+      :inspect => '#<OCI8::Metadata::Procedure: OUT_REC1_VALUES>', # TODO: change to "#{@conn.username}.RB_TEST_PKG.OUT_REC1_VALUES"
     }
 
     subprogram_metadata_attrs = {



More information about the ruby-oci8-commit mailing list