From nobody at rubyforge.org Tue Jun 1 09:18:10 2010 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Tue, 1 Jun 2010 09:18:10 -0400 (EDT) Subject: [ruby-oci8-commit] [396] trunk/ruby-oci8: * ext/oci8/extconf.rb, ext/oci8/oci8.c, lib/oci8.rb. in: move Message-ID: <20100601131810.CD3091D799E0@rubyforge.org> Revision: 396 Author: kubo Date: 2010-06-01 09:18:10 -0400 (Tue, 01 Jun 2010) Log Message: ----------- * ext/oci8/extconf.rb, ext/oci8/oci8.c, lib/oci8.rb.in: move the location where OCI8::VERSION is defined from oci8.rb to oci8lib_*.so. Add code to check the version of oci8.rb and oci8lib_*.so. * test/test_clob.rb: create test_clob table while executing tests. * README: delete the instruction to create test_clob before executing tests. Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/README trunk/ruby-oci8/ext/oci8/extconf.rb trunk/ruby-oci8/ext/oci8/oci8.c trunk/ruby-oci8/lib/oci8.rb.in trunk/ruby-oci8/test/test_clob.rb Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2010-05-17 13:37:21 UTC (rev 395) +++ trunk/ruby-oci8/ChangeLog 2010-06-01 13:18:10 UTC (rev 396) @@ -1,3 +1,13 @@ +2010-06-01 KUBO Takehiro + * ext/oci8/extconf.rb, ext/oci8/oci8.c, lib/oci8.rb.in: move + the location where OCI8::VERSION is defined from oci8.rb to + oci8lib_*.so. Add code to check the version of oci8.rb and + oci8lib_*.so. + * test/test_clob.rb: create test_clob table while executing + tests. + * README: delete the instruction to create test_clob before + executing tests. + 2010-05-17 KUBO Takehiro * ext/oci8/metadata.c: delete OCI8::Metadata::Base's methods which get and set OCI handle attributes. Modified: trunk/ruby-oci8/README =================================================================== --- trunk/ruby-oci8/README 2010-05-17 13:37:21 UTC (rev 395) +++ trunk/ruby-oci8/README 2010-06-01 13:18:10 UTC (rev 396) @@ -60,27 +60,17 @@ SQL> GRANT connect, resource TO ruby; -4. If the Oracle version is 8i or later: +4. connect to Oracle as sys - SQL> CREATE TABLE ruby.test_clob (filename VARCHAR2(40), content CLOB); - -5. connect to Oracle as sys - $ sqlplus 'sys/ as sysdba' -6. grant the privilege for the unittest of blocking-mode. +5. grant the privilege for the unittest of blocking-mode. SQL> GRANT EXECUTE ON dbms_lock TO ruby; -7. change test/config.rb as you like +6. change test/config.rb as you like Then you can run: $ make check or $ nmake check (If your compiler is MS Visual C++.) - -= TODO - -* more proper handling of OCI_SUCCESS_WITH_INFO. -* more proper handling of NUMBER without its scale values. -* support Timestamp. Modified: trunk/ruby-oci8/ext/oci8/extconf.rb =================================================================== --- trunk/ruby-oci8/ext/oci8/extconf.rb 2010-05-17 13:37:21 UTC (rev 395) +++ trunk/ruby-oci8/ext/oci8/extconf.rb 2010-06-01 13:18:10 UTC (rev 396) @@ -130,6 +130,7 @@ $defs << "-DInit_oci8lib=Init_#{so_basename}" $defs << "-Doci8lib=#{so_basename}" +$defs << "-DOCI8LIB_VERSION=\\\"#{RUBY_OCI8_VERSION}\\\"" create_header() Modified: trunk/ruby-oci8/ext/oci8/oci8.c =================================================================== --- trunk/ruby-oci8/ext/oci8/oci8.c 2010-05-17 13:37:21 UTC (rev 395) +++ trunk/ruby-oci8/ext/oci8/oci8.c 2010-06-01 13:18:10 UTC (rev 396) @@ -989,6 +989,7 @@ id_at_prefetch_rows = rb_intern("@prefetch_rows"); id_set_prefetch_rows = rb_intern("prefetch_rows="); + rb_define_const(cOCI8, "VERSION", rb_obj_freeze(rb_usascii_str_new_cstr(OCI8LIB_VERSION))); rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0); if (have_OCIMessageOpen && have_OCIMessageGet) { rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1); Modified: trunk/ruby-oci8/lib/oci8.rb.in =================================================================== --- trunk/ruby-oci8/lib/oci8.rb.in 2010-05-17 13:37:21 UTC (rev 395) +++ trunk/ruby-oci8/lib/oci8.rb.in 2010-06-01 13:18:10 UTC (rev 396) @@ -18,15 +18,23 @@ end end +so_basename = nil case RUBY_VERSION when /^1\.9/ - require 'oci8lib_191' + so_basename = 'oci8lib_191' when /^1\.8/ - require 'oci8lib_18' + so_basename = 'oci8lib_18' else raise 'unsupported ruby version: ' + RUBY_VERSION end +require so_basename +if OCI8::VERSION != '@@OCI8_MODULE_VERSION@@' + require 'rbconfig' + so_name = so_basename + "." + Config::CONFIG['DLEXT'] + raise "VERSION MISMATCH! #{so_name} version is #{OCI8::VERSION}, but oci8.rb version is @@OCI8_MODULE_VERSION@@." +end + require 'oci8/encoding-init.rb' require 'oci8/oracle_version.rb' @@ -60,6 +68,11 @@ def self.oracle_client_version @@oracle_client_version end + + # defined for backward compatibility. + CLIENT_VERSION = @@oracle_client_version.major.to_s + + @@oracle_client_version.minor.to_s + + @@oracle_client_version.update.to_s end require 'oci8/ocihandle.rb' @@ -70,8 +83,3 @@ require 'oci8/compat.rb' require 'oci8/object.rb' require 'oci8/connection_pool.rb' - -class OCI8 - VERSION = '@@OCI8_MODULE_VERSION@@' - CLIENT_VERSION = '@@OCI8_CLIENT_VERSION@@' -end Modified: trunk/ruby-oci8/test/test_clob.rb =================================================================== --- trunk/ruby-oci8/test/test_clob.rb 2010-05-17 13:37:21 UTC (rev 395) +++ trunk/ruby-oci8/test/test_clob.rb 2010-06-01 13:18:10 UTC (rev 396) @@ -7,6 +7,8 @@ def setup @conn = get_oci8_connection + drop_table('test_clob') + @conn.exec('CREATE TABLE test_clob (filename VARCHAR2(40), content CLOB)') end def test_insert @@ -74,6 +76,7 @@ end def teardown + drop_table('test_clob') @conn.logoff end end From nobody at rubyforge.org Thu Jun 10 10:19:05 2010 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Thu, 10 Jun 2010 10:19:05 -0400 (EDT) Subject: [ruby-oci8-commit] [397] trunk/ruby-oci8: * lib/oci8/metadata.rb: revice rdoc comments of OCI8 ::Metadata::Table Message-ID: <20100610141905.9C71B185835A@rubyforge.org> Revision: 397 Author: kubo Date: 2010-06-10 10:19:05 -0400 (Thu, 10 Jun 2010) Log Message: ----------- * lib/oci8/metadata.rb: revice rdoc comments of OCI8::Metadata::Table and OCI8::Metadata::View and delete some unavailable methods of OCI8::Metadata::View. * test/test_metadata.rb: add tests for OCI8::Metadata::Table and OCI8::Metadata::View. * README: change the description about the privilege to run tests. 'create view' privilege is needed to test OCI8::Metadata::View. Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/README trunk/ruby-oci8/lib/oci8/metadata.rb trunk/ruby-oci8/test/test_metadata.rb Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2010-06-01 13:18:10 UTC (rev 396) +++ trunk/ruby-oci8/ChangeLog 2010-06-10 14:19:05 UTC (rev 397) @@ -1,3 +1,12 @@ +2010-06-10 KUBO Takehiro + * lib/oci8/metadata.rb: revice rdoc comments of OCI8::Metadata::Table + and OCI8::Metadata::View and delete some unavailable methods + of OCI8::Metadata::View. + * test/test_metadata.rb: add tests for OCI8::Metadata::Table and + OCI8::Metadata::View. + * README: change the description about the privilege to run tests. + 'create view' privilege is needed to test OCI8::Metadata::View. + 2010-06-01 KUBO Takehiro * ext/oci8/extconf.rb, ext/oci8/oci8.c, lib/oci8.rb.in: move the location where OCI8::VERSION is defined from oci8.rb to Modified: trunk/ruby-oci8/README =================================================================== --- trunk/ruby-oci8/README 2010-06-01 13:18:10 UTC (rev 396) +++ trunk/ruby-oci8/README 2010-06-10 14:19:05 UTC (rev 397) @@ -58,7 +58,7 @@ 3. grant the privilege to connect and execute. - SQL> GRANT connect, resource TO ruby; + SQL> GRANT connect, resource, create view TO ruby; 4. connect to Oracle as sys Modified: trunk/ruby-oci8/lib/oci8/metadata.rb =================================================================== --- trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-01 13:18:10 UTC (rev 396) +++ trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-10 14:19:05 UTC (rev 397) @@ -8,74 +8,91 @@ # class OCI8 - # = OCI8 can describe database object's metadata. - # [user objects] - # OCI8#describe_any(object_name) - # [table or view] - # OCI8#describe_table(table_name, table_only = false) - # [view] - # OCI8#describe_view(view_name) - # [procedure] - # OCI8#describe_procedure(procedure_name) - # [function] - # OCI8#describe_function(function_name) - # [package] - # OCI8#describe_package(package_name) - # [type] - # OCI8#describe_type(type_name) - # [synonym] - # OCI8#describe_synonym(synonym_name, check_public_also = false) - # [sequence] - # OCI8#describe_sequence(sequence_name) - # [schema] - # OCI8#describe_schema(schema_name) - # [database] - # OCI8#describe_database(database_name) + # OCI8 has methods to obtain information about database objects such + # as tables, views, procedures, functions ans so on. The obtained + # data are called metadata and retrived as an instance of + # OCI8::Metadata::Base's subclass. # - # The name can be supplied as 'OBJECT_NAME' or 'SCHEMA_NAME.OBJECT_NAME'. - # For example: 'emp', 'scott.emp'. + # List of methots which return OCI8::Metadata::Base. + # * OCI8::describe_any(object_name) + # * OCI8::describe_table(table_name, table_only = false) + # * OCI8::describe_view(view_name) + # * OCI8::describe_procedure(procedure_name) + # * OCI8::describe_function(function_name) + # * OCI8::describe_package(package_name) + # * OCI8::describe_type(type_name) + # * OCI8::describe_synonym(synonym_name, check_public_also = true) + # * OCI8::describe_sequence(sequence_name) + # * OCI8::describe_schema(schema_name) + # * OCI8::describe_database(database_name) + # * OCI8::Metadata::Type#map_method + # * OCI8::Metadata::Type#order_method + # * OCI8::Metadata::Type#collection_element # - # = Retrieving Column Datatypes for a Table + # List of methots which return an array of OCI8::Metadata::Base. + # * OCI8::Cusror#column_metadata + # * OCI8::Metadata::Database#schemas + # * OCI8::Metadata::Schema#all_objects + # * OCI8::Metadata::Schema#objects + # * OCI8::Metadata::Table#columns + # * OCI8::Metadata::Package#subprograms + # * OCI8::Metadata::Procedure#arguments + # * OCI8::Metadata::Function#arguments + # * OCI8::Metadata::Type#type_attrs + # * OCI8::Metadata::Type#type_methods + # * OCI8::Metadata::TypeMethod#arguments # - # conn = OCI8.new('ruby', 'oci8') - # table = conn.describe_table('EMPLOYEES') - # table.columns.each do |col| - # if col.char_used - # col_width = col.char_size - # else - # col_width = col.data_size - # end - # end + # Example: + # conn = OCI8.new('username/passord') + # table = conn.describe_table('scott.emp') + # table.columns.each do |col| + # puts "#{col.name} #{col.type_string}" + # end module Metadata - # Abstract super class for Metadata classes. + # Abstract super class of Metadata classes. class Base # Table 6-1 Attributes Belonging to All Parameters - # don't use this. The number of parameters - def num_params + # Returns the number of parameters. + def num_params # :nodoc: attr_get_ub2(OCI_ATTR_NUM_PARAMS) end private :num_params - # object or schema ID + # call-seq: + # obj_id -> integer or nil + # + # Returns an object ID, which is the same as the value of the + # OBJECT_ID column from ALL_OBJECTS. It returns nil + # if the database object doesn't have ID. def obj_id attr_get_ub4(OCI_ATTR_OBJ_ID) end - # database name or object name in a schema + # call-seq: + # obj_name -> string + # + # Retruns object name; table name, view name, procedure name, etc. def obj_name attr_get_string(OCI_ATTR_OBJ_NAME) end - # schema name where the object is located + # call-seq: + # obj_schema -> string + # + # Retruns a schema name. It returns nil + # if the database object is not defined just under a schema. def obj_schema attr_get_string(OCI_ATTR_OBJ_SCHEMA) end # The timestamp of the object - def timestamp - attr_get_oradate(OCI_ATTR_TIMESTAMP) - end + #- + # As far as I checked, it is current timestamp, not the object's timestamp. Why? + #+ + #def timestamp + # attr_get_oradate(OCI_ATTR_TIMESTAMP) + #end def inspect # :nodoc: "#<#{self.class.name}:(#{obj_id}) #{obj_schema}.#{obj_name}>" @@ -235,7 +252,7 @@ end end] - def __data_type + def __data_type # :nodoc: return @data_type if defined? @data_type entry = DATA_TYPE_MAP[attr_get_ub2(OCI_ATTR_DATA_TYPE)] type = entry.nil? ? attr_get_ub2(OCI_ATTR_DATA_TYPE) : entry[0] @@ -243,7 +260,7 @@ @data_type = type end - def __duration + def __duration # :nodoc: case attr_get_ub2(OCI_ATTR_DURATION) when OCI_DURATION_SESSION :session @@ -254,7 +271,7 @@ end end - def __charset_form + def __charset_form # :nodoc: case attr_get_ub1(OCI_ATTR_CHARSET_FORM) when 1; :implicit # for CHAR, VARCHAR2, CLOB w/o a specified set when 2; :nchar # for NCHAR, NCHAR VARYING, NCLOB @@ -264,7 +281,7 @@ end end - def __type_string + def __type_string # :nodoc: entry = DATA_TYPE_MAP[attr_get_ub2(OCI_ATTR_DATA_TYPE)] type = entry.nil? ? "unknown(#{attr_get_ub2(OCI_ATTR_DATA_TYPE)})" : entry[1] type = type.call(self) if type.is_a? Proc @@ -275,7 +292,7 @@ end end - def __typecode(idx) + def __typecode(idx) # :nodoc: case attr_get_ub2(idx) when 110; :ref # OCI_TYPECODE_REF when 12; :date # OCI_TYPECODE_DATE @@ -327,18 +344,18 @@ end end - # metadata for a object which cannot be classified into other - # metadata classes. + # Information about database objects which cannot be classified + # into other metadata classes. # - # This is returned by: + # An instance of this class is returned by: # * OCI8::Metadata::Schema#all_objects class Unknown < Base register_ptype OCI_PTYPE_UNK end - # Metadata for a table. + # Information about tables # - # This is returned by: + # An instance of this class is returned by: # * OCI8#describe_any(name) # * OCI8#describe_table(name) # * OCI8::Metadata::Schema#all_objects @@ -352,76 +369,127 @@ ## Table 6-2 Attributes Belonging to Tables or Views - # number of columns + # call-seq: + # num_cols -> integer + # + # Returns number of columns def num_cols attr_get_ub2(OCI_ATTR_NUM_COLS) end # column list - def list_columns + def list_columns # :nodoc: __param(OCI_ATTR_LIST_COLUMNS) end private :list_columns - # to type metadata if possible + # call-seq: + # type_methods -> an OCI8::Metadata::Type or nil + # + # Retruns an instance of OCI8::Metadata::Type if the table is an + # {object table}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjint.htm#sthref48]. + # Otherwise, nil. def type_metadata - __type_metadata(OCI8::Metadata::Type) + __type_metadata(OCI8::Metadata::Type) if is_typed? end - # indicates the table is temporary. + # call-seq: + # is_temporary? -> true or false + # + # Returns true if the table is a + # {temporary table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/schema.htm#i16096]. + # Otherwise, false. def is_temporary? - __boolean(OCI_ATTR_IS_TEMPORARY) + attr_get_ub1(OCI_ATTR_IS_TEMPORARY) != 0 end - # indicates the table is typed. + # call-seq: + # is_typed? -> true or false + # + # Returns true if the table is a object table. Otherwise, false. def is_typed? - __boolean(OCI_ATTR_IS_TYPED) + attr_get_ub1(OCI_ATTR_IS_TYPED) != 0 end - # Duration of a temporary table. Values can be :session or - # :transaction. nil if not a temporary table. + # call-seq: + # duration -> :transaction, :session or nil + # + # Retruns :transaction if the table is a + # {transaction-specific temporary table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_7002.htm#i2189569]. + # :session if it is a + # {session-specific temporary table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_7002.htm#i2189569]. + # Otherwise, nil. def duration __duration end ## Table 6-3 Attributes Specific to Tables - # data block address of the segment header. (How to use this?) + # call-seq: + # dba -> integer + # + # Returns a Data Block Address(DBA) of the segment header. + # + # The dba is converted to the file number and the block number + # by DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE and + # DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK respectively. def dba attr_get_ub4(OCI_ATTR_RDBA) end - # tablespace the table resides in. (How to use this?) + # call-seq: + # tablespace -> integer + # + # Returns a tablespace number the table resides in. def tablespace __word(OCI_ATTR_TABLESPACE) end - # indicates the table is clustered. + # call-seq: + # clustered? -> true or false + # + # Returns true if the table is part of a + # cluster[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/schema.htm#CNCPT608]. + # Otherwise, false. def clustered? - __boolean(OCI_ATTR_CLUSTERED) + attr_get_ub1(OCI_ATTR_CLUSTERED) != 0 end - # indicates the table is partitioned. + # call-seq: + # partitioned? -> true or false + # + # Returns true if the table is a + # {partitioned table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/partconc.htm#i449863]. + # Otherwise, false. def partitioned? - __boolean(OCI_ATTR_PARTITIONED) + attr_get_ub1(OCI_ATTR_PARTITIONED) != 0 end - # indicates the table is index-only. + # call-seq: + # index_only? -> true or false + # + # Returns true if the table is an + # {index-organized table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/schema.htm#i23877] + # Otherwise, false. def index_only? - __boolean(OCI_ATTR_INDEX_ONLY) + attr_get_ub1(OCI_ATTR_INDEX_ONLY) != 0 end - # array of Column objects in a table. + # call-seq: + # columns -> an array of OCI8::Metadata::Column + # + # Returns an array of {column information}[link:OCI8/Metadata/Column.html] + # of the table. def columns @columns ||= list_columns.to_a end end - # Metadata for a view. + # Information about views # - # This is returned by: + # Related methods: # * OCI8#describe_any(name) - # * OCI8#describe_table(name, true) + # * OCI8#describe_table(name, false) # * OCI8#describe_view(name) # * OCI8::Metadata::Schema#all_objects # * OCI8::Metadata::Schema#objects @@ -434,39 +502,45 @@ ## Table 6-2 Attributes Belonging to Tables or Views - # number of columns + # call-seq: + # num_cols -> integer + # + # Returns number of columns def num_cols attr_get_ub2(OCI_ATTR_NUM_COLS) end # column list - def list_columns + def list_columns # :nodoc: __param(OCI_ATTR_LIST_COLUMNS) end private :list_columns - # to type metadata if possible - def type_metadata - __type_metadata(OCI8::Metadata::Type) - end + # This does't work for view. + #def type_metadata + # __type_metadata(OCI8::Metadata::Type) + #end - # indicates the table is temporary. - def is_temporary? - __boolean(OCI_ATTR_IS_TEMPORARY) - end + # This does't work for view. + #def is_temporary? + # attr_get_ub1(OCI_ATTR_IS_TEMPORARY) != 0 + #end - # indicates the table is typed. - def is_typed? - __boolean(OCI_ATTR_IS_TYPED) - end + # This does't work for view. + #def is_typed? + # attr_get_ub1(OCI_ATTR_IS_TYPED) != 0 + #end - # Duration of a temporary table. Values can be :session or - # :transaction. nil if not a temporary table. - def duration - __duration - end + # This does't work for view. + #def duration + # __duration + #end - # array of Column objects in a table. + # call-seq: + # columns -> an array of OCI8::Metadata::Column + # + # Returns an array of {column information}[link:OCI8/Metadata/Column.html] + # of the table. def columns @columns ||= list_columns.to_a end @@ -1532,41 +1606,46 @@ # array of objects in the schema. # This includes unusable objects. def all_objects - unless @all_objects + @all_objects ||= begin - objs = list_objects - rescue OCIError => exc - if exc.code != -1 - raise + begin + objs = list_objects + rescue OCIError => exc + if exc.code != -1 + raise + end + # describe again. + objs = __con.describe_schema(obj_schema).list_objects end - # describe again. - objs = __con.describe_schema(obj_schema).list_objects + objs.to_a.collect! do |elem| + case elem + when OCI8::Metadata::Type + # to avoid a segmentation fault + __con.describe_type(elem.obj_schema + '.' + elem.obj_name) + else + elem + end + end end - @all_objects = objs.to_a - end - @all_objects end # array of objects in the schema. def objects - unless @objects - @objects = all_objects.dup.reject! do |obj| - case obj - when Unknown + @objects ||= all_objects.reject do |obj| + case obj + when Unknown + true + when Synonym + begin + obj.objid + false + rescue OCIError true - when Synonym - begin - obj.objid - false - rescue OCIError - true - end - else - false end + else + false end end - @objects end def inspect # :nodoc: Modified: trunk/ruby-oci8/test/test_metadata.rb =================================================================== --- trunk/ruby-oci8/test/test_metadata.rb 2010-06-01 13:18:10 UTC (rev 396) +++ trunk/ruby-oci8/test/test_metadata.rb 2010-06-10 14:19:05 UTC (rev 397) @@ -254,4 +254,190 @@ 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') + + # Relational table + @conn.exec(<<-EOS) +CREATE TABLE test_table (col1 number(38,0), col2 varchar2(60)) +STORAGE ( + INITIAL 100k + NEXT 100k + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + PCTINCREASE 0) +EOS + [ + @conn.describe_any('test_table'), + @conn.describe_table('test_table'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + 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) + assert_not_nil(desc.dba) + assert_not_nil(desc.tablespace) + assert_equal(false, desc.clustered?) + assert_equal(false, desc.partitioned?) + assert_equal(false, desc.index_only?) + assert_equal(Array, desc.columns.class) + assert_equal(OCI8::Metadata::Column, desc.columns[0].class) + end + drop_table('test_table') + + # Transaction-specific temporary table + @conn.exec(<<-EOS) +CREATE GLOBAL TEMPORARY TABLE test_table (col1 number(38,0), col2 varchar2(60)) +EOS + [ + @conn.describe_any('test_table'), + @conn.describe_table('test_table'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + 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) + assert_not_nil(desc.dba) + assert_not_nil(desc.tablespace) + assert_equal(false, desc.clustered?) + assert_equal(false, desc.partitioned?) + assert_equal(false, desc.index_only?) + assert_equal(Array, desc.columns.class) + assert_equal(OCI8::Metadata::Column, desc.columns[0].class) + end + drop_table('test_table') + + # Session-specific temporary table + @conn.exec(<<-EOS) +CREATE GLOBAL TEMPORARY TABLE test_table (col1 number(38,0), col2 varchar2(60)) +ON COMMIT PRESERVE ROWS +EOS + [ + @conn.describe_any('test_table'), + @conn.describe_table('test_table'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + 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) + assert_not_nil(desc.dba) + assert_not_nil(desc.tablespace) + assert_equal(false, desc.clustered?) + assert_equal(false, desc.partitioned?) + assert_equal(false, desc.index_only?) + assert_equal(Array, desc.columns.class) + assert_equal(OCI8::Metadata::Column, desc.columns[0].class) + end + drop_table('test_table') + + # Object table + @conn.exec(<<-EOS) +CREATE OR REPLACE TYPE test_type AS OBJECT (col1 number(38,0), col2 varchar2(60)) +EOS + @conn.exec(<<-EOS) +CREATE TABLE test_table OF test_type +EOS + [ + @conn.describe_any('test_table'), + @conn.describe_table('test_table'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + 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_equal(OCI8::Metadata::Type, desc.type_metadata.class) + assert_equal(false, desc.is_temporary?) + assert_equal(true, desc.is_typed?) + assert_equal(nil, desc.duration) + assert_not_nil(desc.dba) + assert_not_nil(desc.tablespace) + assert_equal(false, desc.clustered?) + assert_equal(false, desc.partitioned?) + assert_equal(false, desc.index_only?) + assert_equal(Array, desc.columns.class) + assert_equal(OCI8::Metadata::Column, desc.columns[0].class) + end + drop_table('test_table') + @conn.exec('DROP TYPE TEST_TYPE') + + # Index-organized table + @conn.exec(<<-EOS) +CREATE TABLE test_table (col1 number(38,0) PRIMARY KEY, col2 varchar2(60)) +ORGANIZATION INDEX +EOS + [ + @conn.describe_any('test_table'), + @conn.describe_table('test_table'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + 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) + assert_not_nil(desc.dba) + assert_not_nil(desc.tablespace) + assert_equal(false, desc.clustered?) + assert_equal(false, desc.partitioned?) + assert_equal(true, desc.index_only?) + assert_equal(Array, desc.columns.class) + assert_equal(OCI8::Metadata::Column, desc.columns[0].class) + 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') + [ + @conn.describe_any('test_view'), + @conn.describe_view('test_view'), + @conn.describe_table('test_view'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + 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_equal(Array, desc.columns.class) + assert_equal(OCI8::Metadata::Column, desc.columns[0].class) + end + @conn.exec('DROP VIEW test_view') + end # test_view_metadata end # TestMetadata From nobody at rubyforge.org Fri Jun 11 06:24:41 2010 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Fri, 11 Jun 2010 06:24:41 -0400 (EDT) Subject: [ruby-oci8-commit] [398] trunk/ruby-oci8: * lib/oci8/metadata.rb: rename OCI8::Metabase:: ProcBase to Message-ID: <20100611102442.102521858354@rubyforge.org> Revision: 398 Author: kubo Date: 2010-06-11 06:24:41 -0400 (Fri, 11 Jun 2010) Log Message: ----------- * lib/oci8/metadata.rb: rename OCI8::Metabase::ProcBase to OCI8::Metabase::Subprogram, add #is_standalone? and change #obj_id, #obj_name and #obj_schema to work for packaged subprograms. Fix rdoc comments. * test/test_metadata.rb: add tests for OCI8::Metadata::Function, OCI8::Metadata::Procedure and OCI8::Metadata::Package. Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/lib/oci8/metadata.rb trunk/ruby-oci8/test/test_metadata.rb Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2010-06-10 14:19:05 UTC (rev 397) +++ trunk/ruby-oci8/ChangeLog 2010-06-11 10:24:41 UTC (rev 398) @@ -1,3 +1,11 @@ +2010-06-11 KUBO Takehiro + * lib/oci8/metadata.rb: rename OCI8::Metabase::ProcBase to + OCI8::Metabase::Subprogram, add #is_standalone? and change + #obj_id, #obj_name and #obj_schema to work for packaged + subprograms. Fix rdoc comments. + * test/test_metadata.rb: add tests for OCI8::Metadata::Function, + OCI8::Metadata::Procedure and OCI8::Metadata::Package. + 2010-06-10 KUBO Takehiro * lib/oci8/metadata.rb: revice rdoc comments of OCI8::Metadata::Table and OCI8::Metadata::View and delete some unavailable methods Modified: trunk/ruby-oci8/lib/oci8/metadata.rb =================================================================== --- trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-10 14:19:05 UTC (rev 397) +++ trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-11 10:24:41 UTC (rev 398) @@ -14,23 +14,23 @@ # OCI8::Metadata::Base's subclass. # # List of methots which return OCI8::Metadata::Base. - # * OCI8::describe_any(object_name) - # * OCI8::describe_table(table_name, table_only = false) - # * OCI8::describe_view(view_name) - # * OCI8::describe_procedure(procedure_name) - # * OCI8::describe_function(function_name) - # * OCI8::describe_package(package_name) - # * OCI8::describe_type(type_name) - # * OCI8::describe_synonym(synonym_name, check_public_also = true) - # * OCI8::describe_sequence(sequence_name) - # * OCI8::describe_schema(schema_name) - # * OCI8::describe_database(database_name) + # * OCI8#describe_any(object_name) + # * OCI8#describe_table(table_name, table_only = false) + # * OCI8#describe_view(view_name) + # * OCI8#describe_procedure(procedure_name) + # * OCI8#describe_function(function_name) + # * OCI8#describe_package(package_name) + # * OCI8#describe_type(type_name) + # * OCI8#describe_synonym(synonym_name, check_public_also = true) + # * OCI8#describe_sequence(sequence_name) + # * OCI8#describe_schema(schema_name) + # * OCI8#describe_database(database_name) # * OCI8::Metadata::Type#map_method # * OCI8::Metadata::Type#order_method # * OCI8::Metadata::Type#collection_element # # List of methots which return an array of OCI8::Metadata::Base. - # * OCI8::Cusror#column_metadata + # * OCI8::Cursor#column_metadata # * OCI8::Metadata::Database#schemas # * OCI8::Metadata::Schema#all_objects # * OCI8::Metadata::Schema#objects @@ -60,17 +60,17 @@ private :num_params # call-seq: - # obj_id -> integer or nil + # obj_id -> integer or nil # # Returns an object ID, which is the same as the value of the - # OBJECT_ID column from ALL_OBJECTS. It returns nil + # OBJECT_ID column from ALL_OBJECTS. It returns +nil+ # if the database object doesn't have ID. def obj_id attr_get_ub4(OCI_ATTR_OBJ_ID) end # call-seq: - # obj_name -> string + # obj_name -> string # # Retruns object name; table name, view name, procedure name, etc. def obj_name @@ -78,9 +78,9 @@ end # call-seq: - # obj_schema -> string + # obj_schema -> string # - # Retruns a schema name. It returns nil + # Retruns a schema name. It returns +nil+ # if the database object is not defined just under a schema. def obj_schema attr_get_string(OCI_ATTR_OBJ_SCHEMA) @@ -384,41 +384,41 @@ private :list_columns # call-seq: - # type_methods -> an OCI8::Metadata::Type or nil + # type_methods -> an OCI8::Metadata::Type or nil # # Retruns an instance of OCI8::Metadata::Type if the table is an # {object table}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjint.htm#sthref48]. - # Otherwise, nil. + # Otherwise, +nil+. def type_metadata __type_metadata(OCI8::Metadata::Type) if is_typed? end # call-seq: - # is_temporary? -> true or false + # is_temporary? -> true or false # - # Returns true if the table is a + # Returns +true+ if the table is a # {temporary table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/schema.htm#i16096]. - # Otherwise, false. + # Otherwise, +false+. def is_temporary? attr_get_ub1(OCI_ATTR_IS_TEMPORARY) != 0 end # call-seq: - # is_typed? -> true or false + # is_typed? -> true or false # - # Returns true if the table is a object table. Otherwise, false. + # Returns +true+ if the table is a object table. Otherwise, +false+. def is_typed? attr_get_ub1(OCI_ATTR_IS_TYPED) != 0 end # call-seq: - # duration -> :transaction, :session or nil + # duration -> :transaction, :session or nil # - # Retruns :transaction if the table is a + # Retruns +:transaction+ if the table is a # {transaction-specific temporary table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_7002.htm#i2189569]. - # :session if it is a + # +:session+ if it is a # {session-specific temporary table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_7002.htm#i2189569]. - # Otherwise, nil. + # Otherwise, +nil+. def duration __duration end @@ -446,31 +446,31 @@ end # call-seq: - # clustered? -> true or false + # clustered? -> true or false # - # Returns true if the table is part of a + # Returns +true+ if the table is part of a # cluster[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/schema.htm#CNCPT608]. - # Otherwise, false. + # Otherwise, +false+. def clustered? attr_get_ub1(OCI_ATTR_CLUSTERED) != 0 end # call-seq: - # partitioned? -> true or false + # partitioned? -> true or false # - # Returns true if the table is a + # Returns +true+ if the table is a # {partitioned table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/partconc.htm#i449863]. - # Otherwise, false. + # Otherwise, +false+. def partitioned? attr_get_ub1(OCI_ATTR_PARTITIONED) != 0 end # call-seq: - # index_only? -> true or false + # index_only? -> true or false # - # Returns true if the table is an + # Returns +true+ if the table is an # {index-organized table}[http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/schema.htm#i23877] - # Otherwise, false. + # Otherwise, +false+. def index_only? attr_get_ub1(OCI_ATTR_INDEX_ONLY) != 0 end @@ -487,7 +487,7 @@ # Information about views # - # Related methods: + # An instance of this class is returned by: # * OCI8#describe_any(name) # * OCI8#describe_table(name, false) # * OCI8#describe_view(name) @@ -546,87 +546,121 @@ end end - # Abstract super class of Procedure and Function. + # Information about PL/SQL subprograms # - #-- - # How can I know whether FUNCTION or PROCEDURE? - #++ - class ProcBase < Base + # A PL/SQL subprogram is a named PL/SQL block that can be invoked + # with a set of parameters. A subprogram can be either a procedure + # or a function. + # + # This is the abstract base class of OCI8::Metadata::Procedure and + # OCI8::Metadata::Function. + class Subprogram < Base ## Table 6-4 Attribute Belonging to Procedures or Functions # Argument list - def list_arguments + def list_arguments # :nodoc: __param(OCI_ATTR_LIST_ARGUMENTS) end private :list_arguments - # indicates the procedure or function has invoker's rights + def obj_id # :nodoc: + super if is_standalone? + end + + def obj_name # :nodoc: + is_standalone? ? super : attr_get_string(OCI_ATTR_NAME) + end + + def obj_schema # :nodoc: + super if is_standalone? + end + + # call-seq: + # is_invoker_rights? -> true or false + # + # Returns +true+ if the subprogram has + # {invoker's rights}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/subprograms.htm#i18574]. + # Otherwise, +false+. def is_invoker_rights? - __boolean(OCI_ATTR_IS_INVOKER_RIGHTS) + attr_get_ub1(OCI_ATTR_IS_INVOKER_RIGHTS) != 0 end ## Table 6-5 Attributes Specific to Package Subprograms - # name of the procedure or function. + # name of the subprogram # - # available only for a Package subprogram. - def name - attr_get_string(OCI_ATTR_NAME) - end + #def name + # attr_get_string(OCI_ATTR_NAME) + #end + alias name obj_name # :nodoc: for backward compatibility - # overloading ID number (relevant in case the procedure or - # function is part of a package and is overloaded). Values - # returned may be different from direct query of a PL/SQL - # function or procedure. (What this means?) + # call-seq: + # overload_id -> integer or nil # - # available only for a Package subprogram. + # Returns +nil+ for a standalone stored subprogram, + # positive integer for a + # {overloaded packaged subprogram}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/subprograms.htm#i12352]. + # , otherwise zero. def overload_id - attr_get_ub2(OCI_ATTR_OVERLOAD_ID) + attr_get_ub2(OCI_ATTR_OVERLOAD_ID) unless is_standalone? end - # array of Argument objects. + # call-seq: + # arguments -> an array of OCI8::Metadata::Argument # - # The first element is the return type in case of Function. + # Returns an array of {argument information}[link:OCI8/Metadata/Argument.html] + # of the subprogram. + # If it is a function, the first array element is information of its return type. def arguments @arguments ||= list_arguments.to_a end + # call-seq: + # is_standalone? -> true or false + # + # Returns +true+ if the subprogram is standalone, +false+ + # if packaged. + def is_standalone? + @is_standalone = true unless defined? @is_standalone + @is_standalone + end + def inspect # :nodoc: "#<#{self.class.name}: #{name}>" end end - # Metadata for a procedure. + # Information about procedures # - # This is returned by: + # An instance of this class is returned by: # * OCI8#describe_any(name) # * OCI8#describe_procedure(name) # * OCI8::Metadata::Schema#all_objects # * OCI8::Metadata::Schema#objects # * OCI8::Metadata::Package#subprograms # - # See ProcBase's methods. - class Procedure < ProcBase + # See OCI8::Metadata::Subprogram. + class Procedure < Subprogram register_ptype OCI_PTYPE_PROC end - # Metadata for a function. + # Information about functions # - # This is returned by: + # An instance of this class is returned by: # * OCI8#describe_any(name) # * OCI8#describe_function(name) # * OCI8::Metadata::Schema#all_objects # * OCI8::Metadata::Schema#objects # * OCI8::Metadata::Package#subprograms # - # See ProcBase's methods. - class Function < ProcBase + # See OCI8::Metadata::Subprogram. + class Function < Subprogram register_ptype OCI_PTYPE_FUNC end - # Metadata for a package. + # Information about packages. # - # This is returned by: + # An instance of this class is returned by: # * OCI8#describe_any(name) # * OCI8#describe_package(name) # * OCI8::Metadata::Schema#all_objects @@ -637,19 +671,26 @@ ## Table 6-6 Attributes Belonging to Packages # subprogram list - def list_subprograms + def list_subprograms # :nodoc: __param(OCI_ATTR_LIST_SUBPROGRAMS) end private :list_subprograms - # is the package invoker's rights? + # call-seq: + # is_invoker_rights? -> true or false + # + # Returns true if the package subprograms have + # [invoker's rights][http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/subprograms.htm#i18574]. + # Otherwise, false. def is_invoker_rights? - __boolean(OCI_ATTR_IS_INVOKER_RIGHTS) + attr_get_ub1(OCI_ATTR_IS_INVOKER_RIGHTS) != 0 end # array of Procedure or Function objects. def subprograms - @subprograms ||= list_subprograms.to_a + @subprograms ||= list_subprograms.to_a.each do |prog| + prog.instance_variable_set(:@is_standalone, false) + end end end Modified: trunk/ruby-oci8/test/test_metadata.rb =================================================================== --- trunk/ruby-oci8/test/test_metadata.rb 2010-06-10 14:19:05 UTC (rev 397) +++ trunk/ruby-oci8/test/test_metadata.rb 2010-06-11 10:24:41 UTC (rev 398) @@ -440,4 +440,250 @@ end @conn.exec('DROP VIEW test_view') end # test_view_metadata + + def test_procedure_metadata + @conn.exec(<<-EOS) +CREATE OR REPLACE PROCEDURE test_proc(arg1 IN INTEGER, arg2 OUT varchar2) IS +BEGIN + NULL; +END; +EOS + [ + @conn.describe_any('test_proc'), + @conn.describe_procedure('test_proc'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == 'TEST_PROC' + end + ].each do |desc| + assert_equal(OCI8::Metadata::Procedure, desc.class) + 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_equal(Array, desc.arguments.class) + assert_equal(2, desc.arguments.length) + assert_equal(OCI8::Metadata::Argument, desc.arguments[0].class) + end + + @conn.exec(<<-EOS) +CREATE OR REPLACE PROCEDURE test_proc(arg1 IN INTEGER, arg2 OUT varchar2) + AUTHID CURRENT_USER +IS +BEGIN + NULL; +END; +EOS + [ + @conn.describe_any('test_proc'), + @conn.describe_procedure('test_proc'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == 'TEST_PROC' + end + ].each do |desc| + assert_equal(OCI8::Metadata::Procedure, desc.class) + 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_equal(Array, desc.arguments.class) + assert_equal(2, desc.arguments.length) + assert_equal(OCI8::Metadata::Argument, desc.arguments[0].class) + 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_equal(OCI8::Metadata::Procedure, desc.class) + 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_equal(Array, desc.arguments.class) + assert_equal(2, desc.arguments.length) + assert_equal(OCI8::Metadata::Argument, desc.arguments[0].class) + + @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_equal(OCI8::Metadata::Procedure, desc[0].class) + 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_equal(Array, desc[0].arguments.class) + assert_equal(2, desc[0].arguments.length) + assert_equal(OCI8::Metadata::Argument, desc[0].arguments[0].class) + + descs = @conn.describe_package('test_pkg').subprograms + assert_equal(OCI8::Metadata::Procedure, desc[1].class) + 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_equal(Array, desc[1].arguments.class) + assert_equal(1, desc[1].arguments.length) + assert_equal(OCI8::Metadata::Argument, desc[1].arguments[0].class) + end # test_procedure_metadata + + def test_function_metadata + @conn.exec(<<-EOS) +CREATE OR REPLACE FUNCTION test_func(arg1 IN INTEGER, arg2 OUT varchar2) RETURN NUMBER IS +BEGIN + RETURN arg1; +END; +EOS + [ + @conn.describe_any('test_func'), + @conn.describe_function('test_func'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == 'TEST_FUNC' + end + ].each do |desc| + assert_equal(OCI8::Metadata::Function, desc.class) + 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_equal(Array, desc.arguments.class) + assert_equal(3, desc.arguments.length) + assert_equal(OCI8::Metadata::Argument, desc.arguments[0].class) + end + + @conn.exec(<<-EOS) +CREATE OR REPLACE FUNCTION test_func(arg1 IN INTEGER, arg2 OUT varchar2) RETURN NUMBER + AUTHID CURRENT_USER +IS +BEGIN + RETURN arg1; +END; +EOS + [ + @conn.describe_any('test_func'), + @conn.describe_function('test_func'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == 'TEST_FUNC' + end + ].each do |desc| + assert_equal(OCI8::Metadata::Function, desc.class) + 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_equal(Array, desc.arguments.class) + assert_equal(3, desc.arguments.length) + assert_equal(OCI8::Metadata::Argument, desc.arguments[0].class) + 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_equal(OCI8::Metadata::Function, desc.class) + 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_equal(Array, desc.arguments.class) + assert_equal(3, desc.arguments.length) + assert_equal(OCI8::Metadata::Argument, desc.arguments[0].class) + + @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_equal(OCI8::Metadata::Function, desc[0].class) + 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_equal(Array, desc[0].arguments.class) + assert_equal(3, desc[0].arguments.length) + assert_equal(OCI8::Metadata::Argument, desc[0].arguments[0].class) + + descs = @conn.describe_package('test_pkg').subprograms + assert_equal(OCI8::Metadata::Function, desc[1].class) + 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_equal(Array, desc[1].arguments.class) + assert_equal(2, desc[1].arguments.length) + assert_equal(OCI8::Metadata::Argument, desc[1].arguments[0].class) + 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; +END; +EOS + [ + @conn.describe_any('test_pkg'), + @conn.describe_package('test_pkg'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == 'TEST_PKG' + end + ].each do |desc| + assert_equal(OCI8::Metadata::Package, desc.class) + 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_equal(Array, desc.subprograms.class) + assert_equal(1, desc.subprograms.length) + assert_equal(OCI8::Metadata::Function, desc.subprograms[0].class) + end + + @conn.exec(<<-EOS) +CREATE OR REPLACE PACKAGE TEST_PKG AUTHID CURRENT_USER IS + PROCEDURE test_proc(arg1 IN INTEGER, arg2 OUT varchar2); +END; +EOS + [ + @conn.describe_any('test_pkg'), + @conn.describe_package('test_pkg'), + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == 'TEST_PKG' + end + ].each do |desc| + assert_equal(OCI8::Metadata::Package, desc.class) + 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_equal(Array, desc.subprograms.class) + assert_equal(1, desc.subprograms.length) + assert_equal(OCI8::Metadata::Procedure, desc.subprograms[0].class) + end + end # test_package_metadata end # TestMetadata From nobody at rubyforge.org Sun Jun 13 05:26:16 2010 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Sun, 13 Jun 2010 05:26:16 -0400 (EDT) Subject: [ruby-oci8-commit] [399] trunk/ruby-oci8: * ext/oci8/metadata.c: fix a private method Message-ID: <20100613092616.BDA44185838B@rubyforge.org> Revision: 399 Author: kubo Date: 2010-06-13 05:26:15 -0400 (Sun, 13 Jun 2010) Log Message: ----------- * ext/oci8/metadata.c: fix a private method OCI8::Metadata::Base#__param to return nil when the specified attribute is NULL. * lib/oci8/metadata.rb: add rdoc comment of OCI8::Metadata::Type and fix other typos. change OCI8::Metadata::Schema#all_objects not to raise "ORA-24372: invalid object for describe" by invalid objects. * test/test_metadata.rb: add tests for OCI8::Metadata::Type. Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/ext/oci8/metadata.c trunk/ruby-oci8/lib/oci8/metadata.rb trunk/ruby-oci8/test/test_metadata.rb Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2010-06-11 10:24:41 UTC (rev 398) +++ trunk/ruby-oci8/ChangeLog 2010-06-13 09:26:15 UTC (rev 399) @@ -1,3 +1,13 @@ +2010-06-13 KUBO Takehiro + * ext/oci8/metadata.c: fix a private method + OCI8::Metadata::Base#__param to return nil when the specified + attribute is NULL. + * lib/oci8/metadata.rb: add rdoc comment of OCI8::Metadata::Type + and fix other typos. change OCI8::Metadata::Schema#all_objects + not to raise "ORA-24372: invalid object for describe" by + invalid objects. + * test/test_metadata.rb: add tests for OCI8::Metadata::Type. + 2010-06-11 KUBO Takehiro * lib/oci8/metadata.rb: rename OCI8::Metabase::ProcBase to OCI8::Metabase::Subprogram, add #is_standalone? and change Modified: trunk/ruby-oci8/ext/oci8/metadata.c =================================================================== --- trunk/ruby-oci8/ext/oci8/metadata.c 2010-06-11 10:24:41 UTC (rev 398) +++ trunk/ruby-oci8/ext/oci8/metadata.c 2010-06-13 09:26:15 UTC (rev 399) @@ -69,6 +69,16 @@ return Qnil; } +/* + * call-seq: + * __param(attr_type) -> metadata information or nil + * + * Gets the value of the attribute specified by +attr_type+ + * as an instance of an OCI8::Metadata::Base's subclass. + * + * Caution: If the specified attr_type's datatype is not a + * metadata, it causes a segmentation fault. + */ static VALUE metadata_get_param(VALUE self, VALUE idx) { oci8_metadata_t *md = DATA_PTR(self); @@ -76,11 +86,15 @@ OCIParam *value; ub4 size = sizeof(value); - /* remote call? */ + Check_Type(idx, T_FIXNUM); + /* Is it remote call? */ oci_lc(OCIAttrGet_nb(svcctx, md->base.hp.ptr, md->base.type, &value, &size, FIX2INT(idx), oci8_errhp)); if (size != sizeof(OCIParam *)) { rb_raise(rb_eRuntimeError, "Invalid attribute size. expect %d, but %d", (sb4)sizeof(OCIParam *), size); } + if (value == NULL) { + return Qnil; + } return oci8_metadata_create(value, md->svc, self); } Modified: trunk/ruby-oci8/lib/oci8/metadata.rb =================================================================== --- trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-11 10:24:41 UTC (rev 398) +++ trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-13 09:26:15 UTC (rev 399) @@ -13,7 +13,7 @@ # data are called metadata and retrived as an instance of # OCI8::Metadata::Base's subclass. # - # List of methots which return OCI8::Metadata::Base. + # List of methods which return OCI8::Metadata::Base. # * OCI8#describe_any(object_name) # * OCI8#describe_table(table_name, table_only = false) # * OCI8#describe_view(view_name) @@ -29,7 +29,7 @@ # * OCI8::Metadata::Type#order_method # * OCI8::Metadata::Type#collection_element # - # List of methots which return an array of OCI8::Metadata::Base. + # List of methods which return an array of OCI8::Metadata::Base. # * OCI8::Cursor#column_metadata # * OCI8::Metadata::Database#schemas # * OCI8::Metadata::Schema#all_objects @@ -62,7 +62,7 @@ # call-seq: # obj_id -> integer or nil # - # Returns an object ID, which is the same as the value of the + # Returns the object ID, which is the same as the value of the # OBJECT_ID column from ALL_OBJECTS. It returns +nil+ # if the database object doesn't have ID. def obj_id @@ -72,7 +72,8 @@ # call-seq: # obj_name -> string # - # Retruns object name; table name, view name, procedure name, etc. + # Retruns the object name such as table name, view name, + # procedure name, and so on. def obj_name attr_get_string(OCI_ATTR_OBJ_NAME) end @@ -80,7 +81,7 @@ # call-seq: # obj_schema -> string # - # Retruns a schema name. It returns +nil+ + # Retruns the schema name. It returns +nil+ # if the database object is not defined just under a schema. def obj_schema attr_get_string(OCI_ATTR_OBJ_SCHEMA) @@ -384,10 +385,10 @@ private :list_columns # call-seq: - # type_methods -> an OCI8::Metadata::Type or nil + # type_metadata -> an OCI8::Metadata::Type or nil # # Retruns an instance of OCI8::Metadata::Type if the table is an - # {object table}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjint.htm#sthref48]. + # {object table}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjint.htm#sthref61]. # Otherwise, +nil+. def type_metadata __type_metadata(OCI8::Metadata::Type) if is_typed? @@ -476,10 +477,9 @@ end # call-seq: - # columns -> an array of OCI8::Metadata::Column + # columns -> list of column information # - # Returns an array of {column information}[link:OCI8/Metadata/Column.html] - # of the table. + # Returns an array of OCI8::Metadata::Column of the table. def columns @columns ||= list_columns.to_a end @@ -537,10 +537,9 @@ #end # call-seq: - # columns -> an array of OCI8::Metadata::Column + # columns -> list of column information # - # Returns an array of {column information}[link:OCI8/Metadata/Column.html] - # of the table. + # Returns an array of OCI8::Metadata::Column of the table. def columns @columns ||= list_columns.to_a end @@ -606,10 +605,9 @@ end # call-seq: - # arguments -> an array of OCI8::Metadata::Argument + # arguments -> list of argument information # - # Returns an array of {argument information}[link:OCI8/Metadata/Argument.html] - # of the subprogram. + # Returns an array of OCI8::Metadata::Argument of the subprogram. # If it is a function, the first array element is information of its return type. def arguments @arguments ||= list_arguments.to_a @@ -677,16 +675,19 @@ private :list_subprograms # call-seq: - # is_invoker_rights? -> true or false + # is_invoker_rights? -> true or false # - # Returns true if the package subprograms have - # [invoker's rights][http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/subprograms.htm#i18574]. - # Otherwise, false. + # Returns +true+ if the package subprograms have + # {invoker's rights}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/subprograms.htm#i18574]. + # Otherwise, +false+. def is_invoker_rights? attr_get_ub1(OCI_ATTR_IS_INVOKER_RIGHTS) != 0 end - # array of Procedure or Function objects. + # call-seq: + # subprograms -> array + # + # Returns an array of Function and Procedure defined within the Package. def subprograms @subprograms ||= list_subprograms.to_a.each do |prog| prog.instance_variable_set(:@is_standalone, false) @@ -694,9 +695,9 @@ end end - # Metadata for a type. + # Information about types # - # This is returned by: + # An instance of this class is returned by: # * OCI8#describe_any(name) # * OCI8#describe_type(name) # * OCI8::Metadata::Schema#all_objects @@ -711,139 +712,250 @@ self end - # typecode. :object or :named_collection + # call-seq: + # typecode -> :named_type or :named_collection + # + # Returns +:named_type+ if the type is an object type, + # +:named_collection+ if it is a nested table or a varray. def typecode __typecode(OCI_ATTR_TYPECODE) end - # typecode of collection if type is collection. nil if otherwise. + # call-seq: + # collection_typecode -> :table, :varray or nil + # + # Returns +:table+ if the type is a nested table, + # +:varray+ if it is a varray. Otherwise, +nil+. def collection_typecode __typecode(OCI_ATTR_COLLECTION_TYPECODE) if typecode == :named_collection end - # indicates this is an incomplete type + # call-seq: + # is_incomplete_type? -> boolean + # + # Returns +true+ if the type is an + # {incomplete type}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjmng.htm#i1003083], + # which is used for {forward declaration}[http://en.wikipedia.org/wiki/Forward_declaration]. + # Otherwise, +false+. def is_incomplete_type? - __boolean(OCI_ATTR_IS_INCOMPLETE_TYPE) + attr_get_ub1(OCI_ATTR_IS_INCOMPLETE_TYPE) != 0 end - # indicates this is a system type - def is_system_type? - __boolean(OCI_ATTR_IS_SYSTEM_TYPE) + # call-seq: + # is_system_type? -> boolean + # + # Always returns +false+ because there is no way to create + # a type metadata object for a system type such as +NUMBER+, + # +CHAR+ and +VARCHAR+. + def is_system_type? # :nodoc: + attr_get_ub1(OCI_ATTR_IS_SYSTEM_TYPE) != 0 end - # indicates this is a predefined type - def is_predefined_type? - __boolean(OCI_ATTR_IS_PREDEFINED_TYPE) + # call-seq: + # is_predefined_type? -> boolean + # + # Always returns +false+. + #-- + # I don't know the definition of predefined type... + def is_predefined_type? # :nodoc: + attr_get_ub1(OCI_ATTR_IS_PREDEFINED_TYPE) != 0 end - # indicates this is a transient type - def is_transient_type? - __boolean(OCI_ATTR_IS_TRANSIENT_TYPE) + # call-seq: + # is_transient_type? -> boolean + # + # Always returns +false+ because there is no way to create + # a type metadata object for a transient type, which is a type + # dynamically created by C API. + def is_transient_type? # :nodoc: + attr_get_ub1(OCI_ATTR_IS_TRANSIENT_TYPE) != 0 end - # indicates this is a system-generated type - def is_system_generated_type? - __boolean(OCI_ATTR_IS_SYSTEM_GENERATED_TYPE) + # call-seq: + # is_predefined_type? -> boolean + # + # Always returns +false+. + #-- + # I don't know the definition of system generated type. + # What is different with system type and predefined type. + def is_system_generated_type? # :nodoc: + attr_get_ub1(OCI_ATTR_IS_SYSTEM_GENERATED_TYPE) != 0 end - # indicates this type contains a nested table attribute. + # call-seq: + # has_nested_table? -> boolean + # + # Returns +true+ if the type is a nested table or + # has a nested table attribute. + # Otherwise, +false+. def has_nested_table? - __boolean(OCI_ATTR_HAS_NESTED_TABLE) + attr_get_ub1(OCI_ATTR_HAS_NESTED_TABLE) != 0 end - # indicates this type contains a LOB attribute + # call-seq: + # has_lob? -> boolean + # + # Returns +true+ if the type has a CLOB, NCLOB or BLOB + # attribute. + # Otherwise, +false+. def has_lob? - __boolean(OCI_ATTR_HAS_LOB) + attr_get_ub1(OCI_ATTR_HAS_LOB) != 0 end - # indicates this type contains a BFILE attribute + # call-seq: + # has_file? -> boolean + # + # Returns +true+ if the type has a BFILE attribute. + # Otherwise, +false+. def has_file? - __boolean(OCI_ATTR_HAS_FILE) + attr_get_ub1(OCI_ATTR_HAS_FILE) != 0 end - # returns OCI8::Metadata::Collection if type is collection. nil if otherwise. + # call-seq: + # collection_element -> element information of the collection type + # + # Returns an OCI8::Metadata::Collection if the type is a nested + # table or a varray. + # Otherwise, +nil+. def collection_element __param(OCI_ATTR_COLLECTION_ELEMENT) if typecode == :named_collection end - # number of type attributes + # call-seq: + # num_type_attrs -> integer + # + # Returns number of type attributes. def num_type_attrs attr_get_ub2(OCI_ATTR_NUM_TYPE_ATTRS) end # list of type attributes - def list_type_attrs + def list_type_attrs # :nodoc: __param(OCI_ATTR_LIST_TYPE_ATTRS) end private :list_type_attrs - # number of type methods + # call-seq: + # num_type_methods -> integer + # + # Returns number of type methods. def num_type_methods attr_get_ub2(OCI_ATTR_NUM_TYPE_METHODS) end # list of type methods - def list_type_methods + def list_type_methods # :nodoc: __param(OCI_ATTR_LIST_TYPE_METHODS) end private :list_type_methods - # map method of type + # call-seq: + # map_method -> map method information + # + # Returns an instance of OCI8::Metadata::TypeMethod of a + # {map method}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjbas.htm#sthref180] + # if it is defined in the type. Otherwise, +nil+. def map_method __param(OCI_ATTR_MAP_METHOD) end - # order method of type + # call-seq: + # order_method -> order method information + # + # Returns an instance of OCI8::Metadata::TypeMethod of a + # {order method}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjbas.htm#sthref185] + # if it is defined in the type. Otherwise, +nil+. def order_method __param(OCI_ATTR_ORDER_METHOD) end - # indicates the type has invoker's rights + # call-seq: + # is_invoker_rights? -> boolean + # + # Returns +true+ if the type has + # {invoker's rights}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/appdev.111/b28371/adobjdes.htm#ADOBJ00810]. + # Otherwise, +false+. def is_invoker_rights? - __boolean(OCI_ATTR_IS_INVOKER_RIGHTS) + attr_get_ub1(OCI_ATTR_IS_INVOKER_RIGHTS) != 0 end - # type name + # call-seq: + # name -> string + # + # Returns the type name. def name attr_get_string(OCI_ATTR_NAME) end - # schema name where the type has been created + # call-seq: + # schema_name -> string + # + # Returns the schema name where the type has been created. def schema_name attr_get_string(OCI_ATTR_SCHEMA_NAME) end - # indicates this is a final type + # call-seq: + # is_final_type? -> boolean + # + # Returns +true+ if the type is a + # {final type}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjbas.htm#CIHFBHFC]; + # in other words, subtypes cannot be derived from the type. + # Otherwise, +false+. def is_final_type? - __boolean(OCI_ATTR_IS_FINAL_TYPE) + attr_get_ub1(OCI_ATTR_IS_FINAL_TYPE) != 0 end - # indicates this is an instantiable type + # call-seq: + # is_instantiable_type? -> boolean + # + # Returns +true+ if the type is not declared without + # {NOT INSTANTIABLE}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjbas.htm#i456586]. + # Otherwise, +false+. def is_instantiable_type? - __boolean(OCI_ATTR_IS_INSTANTIABLE_TYPE) + attr_get_ub1(OCI_ATTR_IS_INSTANTIABLE_TYPE) != 0 end - # indicates this is a subtype + # call-seq: + # is_subtype? -> boolean + # + # Returns +true+ if the type is a + # {subtype}[http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjbas.htm#BCFJJADG]. + # Otherwise, +false+. def is_subtype? - __boolean(OCI_ATTR_IS_SUBTYPE) + attr_get_ub1(OCI_ATTR_IS_SUBTYPE) != 0 end - # supertype's schema name + # call-seq: + # supertype_schema_name -> string or nil + # + # Returns the supertype's schema name if the type is a subtype. + # Otherwise, +nil+. def supertype_schema_name attr_get_string(OCI_ATTR_SUPERTYPE_SCHEMA_NAME) if is_subtype? end - # supertype's name + # call-seq: + # supertype_name -> string or nil + # + # Returns the supertype's name if the type is a subtype. + # Otherwise, +nil+. def supertype_name attr_get_string(OCI_ATTR_SUPERTYPE_NAME) if is_subtype? end - # array of TypeAttr objects. + # call-seq: + # type_attrs -> list of attribute information + # + # Returns an array of OCI8::Metadata::TypeAttr which the type has. def type_attrs @type_attrs ||= list_type_attrs.to_a end - # array of TypeMethod objects. + # call-seq: + # type_methods -> list of method information + # + # Returns an array of OCI8::Metadata::TypeMethod which the type has. def type_methods @type_methods ||= list_type_methods.to_a end @@ -1662,11 +1774,16 @@ case elem when OCI8::Metadata::Type # to avoid a segmentation fault - __con.describe_type(elem.obj_schema + '.' + elem.obj_name) + begin + __con.describe_type(elem.obj_schema + '.' + elem.obj_name) + rescue OCIError + # ignore ORA-24372: invalid object for describe + raise if $!.code != 24372 + end else elem end - end + end.compact end end Modified: trunk/ruby-oci8/test/test_metadata.rb =================================================================== --- trunk/ruby-oci8/test/test_metadata.rb 2010-06-11 10:24:41 UTC (rev 398) +++ trunk/ruby-oci8/test/test_metadata.rb 2010-06-13 09:26:15 UTC (rev 399) @@ -12,6 +12,21 @@ @conn.logoff end + def drop_type(name, drop_body = false) + if drop_body + begin + @conn.exec("DROP TYPE BODY #{name}") + rescue OCIError + raise if $!.code != 4043 + end + end + begin + @conn.exec("DROP TYPE #{name}") + rescue OCIError + raise if $!.code != 4043 + end + end + def test_metadata if $oracle_version < OCI8::ORAVER_8_1 begin @@ -686,4 +701,308 @@ assert_equal(OCI8::Metadata::Procedure, desc.subprograms[0].class) end end # test_package_metadata + + def test_type_metadata + drop_type('TEST_TYPE_ORDER_METHOD') + drop_type('TEST_TYPE_MAP_METHOD') + drop_type('TEST_TYPE_HAS_BFILE') + drop_type('TEST_TYPE_HAS_BLOB') + drop_type('TEST_TYPE_HAS_NCLOB') + drop_type('TEST_TYPE_HAS_CLOB') + drop_type('TEST_TYPE_INCOMPLETE') + drop_type('TEST_TYPE_GRANDCHILD') + drop_type('TEST_TYPE_VARRAY') + drop_type('TEST_TYPE_NESTEAD_TABLE') + drop_type('TEST_TYPE_CHILD') + drop_type('TEST_TYPE_PARENT') + expected_values = [] + + @conn.exec(<<-EOS) +CREATE TYPE test_type_parent AS OBJECT ( + col1 number(38,0), + col2 varchar2(60) +) +NOT INSTANTIABLE +NOT FINAL +EOS + expected_values << { + :obj_name => 'TEST_TYPE_PARENT', + :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, + :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], + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_child UNDER test_type_parent ( + lob BLOB +) +NOT FINAL +EOS + expected_values << { + :obj_name => 'TEST_TYPE_CHILD', + :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, + :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], + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_nestead_table AS TABLE OF test_type_child +EOS + expected_values << { + :obj_name => 'TEST_TYPE_NESTEAD_TABLE', + :typecode => :named_collection, + :collection_typecode => :table, + :is_incomplete_type? => false, + :is_system_type? => false, + :is_predefined_type? => false, + :is_transient_type? => false, + :is_system_generated_type? => false, + :has_nested_table? => true, + :has_lob? => true, + :has_file? => false, + :collection_element => [:type, OCI8::Metadata::Collection], + :num_type_attrs => 0, + :num_type_methods => 0, + :map_method => nil, + :order_method => nil, + :is_invoker_rights? => false, + :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], + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_varray AS VARRAY(10) OF test_type_child +EOS + expected_values << { + :obj_name => 'TEST_TYPE_VARRAY', + :typecode => :named_collection, + :collection_typecode => :varray, + :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 => [:type, OCI8::Metadata::Collection], + :num_type_attrs => 0, + :num_type_methods => 0, + :map_method => nil, + :order_method => nil, + :is_invoker_rights? => false, + :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], + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_grandchild UNDER test_type_child ( + table_column test_type_nestead_table, + file_column BFILE +) +EOS + expected_values << { + :obj_name => 'TEST_TYPE_GRANDCHILD', + :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? => true, + :has_lob? => true, + :has_file? => true, + :collection_element => nil, + :num_type_attrs => 5, + :num_type_methods => 0, + :map_method => nil, + :order_method => nil, + :is_invoker_rights? => false, + :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], + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_incomplete +EOS + expected_values << { + :obj_name => 'TEST_TYPE_INCOMPLETE', + :typecode => :named_type, + :collection_typecode => nil, + :is_incomplete_type? => true, + :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 => 0, + :num_type_methods => 0, + :map_method => nil, + :order_method => nil, + :is_invoker_rights? => false, + :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], + } + + @conn.exec(<<-EOS) +CREATE TYPE test_type_has_clob AS OBJECT (lob CLOB) +EOS + expected_values << { + :obj_name => 'TEST_TYPE_HAS_CLOB', + :has_lob? => true, + :has_file? => false, + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_has_nclob AS OBJECT (lob NCLOB) +EOS + expected_values << { + :obj_name => 'TEST_TYPE_HAS_NCLOB', + :has_lob? => true, + :has_file? => false, + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_has_blob AS OBJECT (lob BLOB) +EOS + expected_values << { + :obj_name => 'TEST_TYPE_HAS_BLOB', + :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', + :has_lob? => false, + :has_file? => true, + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_map_method AS OBJECT ( + x integer, + y integer, + MAP MEMBER FUNCTION area RETURN NUMBER +) +EOS + expected_values << { + :obj_name => 'TEST_TYPE_MAP_METHOD', + :map_method => [:type, OCI8::Metadata::TypeMethod], + :order_method => nil, + } + @conn.exec(<<-EOS) +CREATE TYPE test_type_order_method AS OBJECT ( + x integer, + y integer, + ORDER MEMBER FUNCTION match(l test_type_order_method) RETURN INTEGER +) +EOS + expected_values << { + :obj_name => 'TEST_TYPE_ORDER_METHOD', + :map_method => nil, + :order_method => [:type, OCI8::Metadata::TypeMethod], + } + + expected_values.each do |elem| + [ + @conn.describe_any(elem[:obj_name]), + @conn.describe_type(elem[:obj_name]), + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == elem[:obj_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| + if val.is_a? Array + case val[0] + when :array + assert_equal(Array, desc.send(key).class, elem[:obj_name] + '.' + key) + assert_equal(val[1], desc.send(key).length) + assert_equal(val[2], desc.send(key)[0].class) if val[1] > 0 + when :type + assert_equal(val[1], desc.send(key).class, elem[:obj_name] + '.' + key) + else + raise "Invalid test case: #{elem[:obj_name]}.#{key} : #{val[0]}" + end + else + assert_equal(val, desc.send(key), elem[:obj_name] + '.' + key) + end + end + end + end + + drop_type('TEST_TYPE_ORDER_METHOD') + drop_type('TEST_TYPE_MAP_METHOD') + drop_type('TEST_TYPE_HAS_BFILE') + drop_type('TEST_TYPE_HAS_BLOB') + drop_type('TEST_TYPE_HAS_NCLOB') + drop_type('TEST_TYPE_HAS_CLOB') + drop_type('TEST_TYPE_INCOMPLETE') + drop_type('TEST_TYPE_GRANDCHILD') + drop_type('TEST_TYPE_VARRAY') + drop_type('TEST_TYPE_NESTEAD_TABLE') + drop_type('TEST_TYPE_CHILD') + drop_type('TEST_TYPE_PARENT') + end # test_type_metadata end # TestMetadata From nobody at rubyforge.org Tue Jun 15 08:31:22 2010 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Tue, 15 Jun 2010 08:31:22 -0400 (EDT) Subject: [ruby-oci8-commit] [400] trunk/ruby-oci8: * lib/oci8/metadata.rb: rename OCI8::Metadata:: Column#type_string Message-ID: <20100615123122.51EB41779957@rubyforge.org> Revision: 400 Author: kubo Date: 2010-06-15 08:31:21 -0400 (Tue, 15 Jun 2010) Log Message: ----------- * lib/oci8/metadata.rb: rename OCI8::Metadata::Column#type_string to #data_type_string and add an alias from the former to the latter. fix a return value of OCI8::Metadata::Column#data_type_string of REF datatype. * test/test_metadata.rb: rename a test method test_metadata to test_column_metadata and do refactoring to make test data reusable for other metadata classes in future. Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/lib/oci8/metadata.rb trunk/ruby-oci8/test/test_metadata.rb Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2010-06-13 09:26:15 UTC (rev 399) +++ trunk/ruby-oci8/ChangeLog 2010-06-15 12:31:21 UTC (rev 400) @@ -1,3 +1,12 @@ +2010-06-15 KUBO Takehiro + * lib/oci8/metadata.rb: rename OCI8::Metadata::Column#type_string + to #data_type_string and add an alias from the former to the + latter. fix a return value of OCI8::Metadata::Column#data_type_string + of REF datatype. + * test/test_metadata.rb: rename a test method test_metadata to + test_column_metadata and do refactoring to make test data + reusable for other metadata classes in future. + 2010-06-13 KUBO Takehiro * ext/oci8/metadata.c: fix a private method OCI8::Metadata::Base#__param to return nil when the specified Modified: trunk/ruby-oci8/lib/oci8/metadata.rb =================================================================== --- trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-13 09:26:15 UTC (rev 399) +++ trunk/ruby-oci8/lib/oci8/metadata.rb 2010-06-15 12:31:21 UTC (rev 400) @@ -46,7 +46,7 @@ # conn = OCI8.new('username/passord') # table = conn.describe_table('scott.emp') # table.columns.each do |col| - # puts "#{col.name} #{col.type_string}" + # puts "#{col.name} #{col.data_type_string}" # end module Metadata # Abstract super class of Metadata classes. @@ -184,7 +184,7 @@ # SQLT_REF DATA_TYPE_MAP[110] = [:ref, Proc.new do |p| - "#{p.schema_name}.#{p.type_name}" + "REF #{p.schema_name}.#{p.type_name}" end] # SQLT_CLOB DATA_TYPE_MAP[112] = [:clob, @@ -282,7 +282,7 @@ end end - def __type_string # :nodoc: + def __data_type_string # :nodoc: entry = DATA_TYPE_MAP[attr_get_ub2(OCI_ATTR_DATA_TYPE)] type = entry.nil? ? "unknown(#{attr_get_ub2(OCI_ATTR_DATA_TYPE)})" : entry[1] type = type.call(self) if type.is_a? Proc @@ -1064,7 +1064,7 @@ end def inspect # :nodoc: - "#<#{self.class.name}: #{name} #{__type_string}>" + "#<#{self.class.name}: #{name} #{__data_type_string}>" end end @@ -1268,7 +1268,7 @@ end def inspect # :nodoc: - "#<#{self.class.name}: #{__type_string}>" + "#<#{self.class.name}: #{__data_type_string}>" end end @@ -1503,16 +1503,17 @@ __charset_name(charset_id) end - def type_string - __type_string + def data_type_string + __data_type_string end + alias :type_string :data_type_string # :nodoc: old name of data_type_string def to_s - %Q{"#{name}" #{__type_string}} + %Q{"#{name}" #{__data_type_string}} end def inspect # :nodoc: - "#<#{self.class.name}: #{name} #{__type_string}>" + "#<#{self.class.name}: #{name} #{__data_type_string}>" end end @@ -1661,7 +1662,7 @@ end def inspect # :nodoc: - "#<#{self.class.name}: #{name} #{__type_string}>" + "#<#{self.class.name}: #{name} #{__data_type_string}>" end end Modified: trunk/ruby-oci8/test/test_metadata.rb =================================================================== --- trunk/ruby-oci8/test/test_metadata.rb 2010-06-13 09:26:15 UTC (rev 399) +++ trunk/ruby-oci8/test/test_metadata.rb 2010-06-15 12:31:21 UTC (rev 400) @@ -27,227 +27,567 @@ end end - def test_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) + 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 + + @@attributes.each do |attr| + define_method attr do + @table[attr] end - return end - # data_size factor for nchar charset_form. - cursor = @conn.exec("select N'1' from dual") + def self.attributes + @@attributes + end + + def initialize(hash = {}) + @table = hash + end + + def oraver + @table[:oraver] + 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 - # data_size factor for char semantics. - cursor = @conn.exec("select CAST('1' AS CHAR(1 char)) from dual") + # 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 - coldef = - [ - # oracle_version, definition, data_type, csfrm, null?,csem?,csize, data_size,prec,scale,fsprec,lfprec - [ora80, "CHAR(10) NOT NULL", :char, :implicit, false, false, 10, 10, 0, 0, 0, 0], - [ora90, "CHAR(10 CHAR)", :char, :implicit, true, true, 10, 10 * csem, 0, 0, 0, 0], - [ora80, "NCHAR(10)", :char, :nchar, true, true, 10, 10 * cfrm, 0, 0, 0, 0], - [ora80, "VARCHAR2(10)", :varchar2, :implicit, true, false, 10, 10, 0, 0, 0, 0], - [ora90, "VARCHAR2(10 CHAR)", :varchar2, :implicit, true, true, 10, 10 * csem, 0, 0, 0, 0], - [ora80, "NVARCHAR2(10)", :varchar2, :nchar, true, true, 10, 10 * cfrm, 0, 0, 0, 0], - [ora80, "RAW(10)", :raw, nil, true, false, 0, 10, 0, 0, 0, 0], + ora80 = OCI8::ORAVER_8_0 + ora81 = OCI8::ORAVER_8_1 + ora90 = OCI8::ORAVER_9_0 + ora101 = OCI8::ORAVER_10_1 - # Don't check data_size of CLOB, NCLOB and BLOB. - # - # Oracle 10g XE 10.2.0.1.0 on Linux: - # +----------+-----------+ - # | | data_size | - # +----------+-----------+ - # | implicit | 4000 | <= OCI8::Cursor#column_metadata - # | explicit | 86 | <= OCI8.describe_table('table_name').columns - # +----------+-----------+ - [ora81, "CLOB", :clob, :implicit, true, false, 0, :nc, 0, 0, 0, 0], - [ora81, "NCLOB", :clob, :nchar, true, false, 0, :nc, 0, 0, 0, 0], - [ora80, "BLOB", :blob, nil, true, false, 0, :nc, 0, 0, 0, 0], + @@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, + ), - [ora80, "BFILE", :bfile, nil, true, false, 0, 530, 0, 0, 0, 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, + ), - # Don't check fsprecision and lfprecision for NUMBER and FLOAT - # - # Oracle 10g XE 10.2.0.1.0 on Linux: - # +---------------------------+-------------+-------------+ - # | | fsprecision | lfprecision | - # +----------------+----------+-------------+-------------+ - # | NUMBER | implicit | 129 | 0 | - # | | explicit | 0 | 129 | - # +----------------+----------+-------------+-------------+ - # | NUMBER(10) | implicit | 0 | 10 | - # | | explicit | 10 | 0 | - # +----------------+----------+-------------+-------------+ - # | NUMBER(10,2) | implicit | 2 | 10 | - # | | explicit | 10 | 2 | - # +----------------+----------+-------------+-------------+ - # | FLOAT | implicit | 129 | 126 | - # | | explicit | 126 | 129 | - # +----------------+----------+-------------+-------------+ - # | FLOAT(10) | implicit | 129 | 10 | - # | | explicit | 10 | 129 | - # +----------------+----------+-------------+-------------+ - [ora80, "NUMBER", :number, nil, true, false, 0, 22, 0, $oracle_version >= ora90 ? -127 : 0, :nc, :nc], - [ora80, "NUMBER(10)", :number, nil, true, false, 0, 22, 10, 0, :nc, :nc], - [ora80, "NUMBER(10,2)", :number, nil, true, false, 0, 22, 10, 2, :nc, :nc], - [ora80, "FLOAT", :number, nil, true, false, 0, 22, 126, -127, :nc, :nc], - [ora80, "FLOAT(10)", :number, nil, true, false, 0, 22, 10, -127, :nc, :nc], + # 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, + ), - [ora101,"BINARY_FLOAT", :binary_float, nil, true, false, 0, 4, 0, 0, 0, 0], - [ora101,"BINARY_DOUBLE", :binary_double, nil, true, false, 0, 8, 0, 0, 0, 0], - [ora80, "DATE", :date, nil, true, false, 0, 7, 0, 0, 0, 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, + ), - # Don't check precision and lfprecision for TIMESTAMP - # - # Oracle 10g XE 10.2.0.1.0 on Linux: - # +----------------------------------------------+-----------+-------------+ - # | | precision | lfprecision | - # +-----------------------------------+----------+-----------+-------------+ - # | TIMESTAMP | implicit | 0 | 0 | - # | | explicit | 6 | 6 | - # +-----------------------------------+----------+-----------+-------------+ - # | TIMESTAMP(9) | implicit | 0 | 0 | - # | | explicit | 9 | 9 | - # +-----------------------------------+----------+-----------+-------------+ - # | TIMESTAMP WITH TIME ZONE | implicit | 0 | 0 | - # | | explicit | 6 | 6 | - # +-----------------------------------+----------+-----------+-------------+ - # | TIMESTAMP(9) WITH TIME ZONE | implicit | 0 | 0 | - # | | explicit | 9 | 9 | - # +-----------------------------------+----------+-----------+-------------+ - # | TIMESTAMP WITH LOCAL TIME ZONE | implicit | 0 | 0 | - # | | explicit | 6 | 6 | - # +-----------------------------------+----------+-----------+-------------+ - # | TIMESTAMP(9) WITH LOCAL TIME ZONE | implicit | 0 | 0 | - # | | explicit | 9 | 9 | - # +-----------------------------------+----------+-----------+-------------+ - [ora90, "TIMESTAMP", :timestamp, nil, true, false, 0, 11, :nc, 6, 6, :nc], - [ora90, "TIMESTAMP(9)", :timestamp, nil, true, false, 0, 11, :nc, 9, 9, :nc], - [ora90, "TIMESTAMP WITH TIME ZONE", :timestamp_tz, nil, true, false, 0, 13, :nc, 6, 6, :nc], - [ora90, "TIMESTAMP(9) WITH TIME ZONE", :timestamp_tz, nil, true, false, 0, 13, :nc, 9, 9, :nc], - [ora90, "TIMESTAMP WITH LOCAL TIME ZONE", :timestamp_ltz, nil, true, false, 0, 11, :nc, 6, 6, :nc], - [ora90, "TIMESTAMP(9) WITH LOCAL TIME ZONE", :timestamp_ltz, nil, true, false, 0, 11, :nc, 9, 9, :nc], + # 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 + ] - # Don't check scale and fsprecision for INTERVAL YEAR TO MONTH - # - # Oracle 10g XE 10.2.0.1.0 on Linux: - # +-----------------------------------------+-----------+-------------+ - # | | scale | fsprecision | - # +------------------------------+----------+-----------+-------------+ - # | INTERVAL YEAR TO MONTH | implicit | 0 | 0 | - # | | explicit | 2 | 2 | - # +------------------------------+----------+-----------+-------------+ - # | INTERVAL YEAR(4) TO MONTH | implicit | 0 | 0 | - # | | explicit | 4 | 4 | - # +------------------------------+----------+-----------+-------------+ - [ora90, "INTERVAL YEAR TO MONTH", :interval_ym, nil, true, false, 0, 5, 2, :nc, :nc, 2], - [ora90, "INTERVAL YEAR(4) TO MONTH", :interval_ym, nil, true, false, 0, 5, 4, :nc, :nc, 4], - - # Don't check precision and scale for INTERVAL DAY TO SECOND - # - # Oracle 10g XE 10.2.0.1.0 on Linux: - # +-----------------------------------------+-----------+-----------+ - # | | precision | scale | - # +------------------------------+----------+-----------+-----------+ - # | INTERVAL DAY TO SECOND | implicit | 2 | 6 | - # | | explicit | 6 | 2 | - # +------------------------------+----------+-----------+-----------+ - # | INTERVAL DAY(4) TO SECOND(9) | implicit | 4 | 9 | - # | | explicit | 9 | 4 | - # +------------------------------+----------+-----------+-----------+ - [ora90, "INTERVAL DAY TO SECOND", :interval_ds, nil, true, false, 0, 11, :nc, :nc, 6, 2], - [ora90, "INTERVAL DAY(4) TO SECOND(9)",:interval_ds, nil, true, false, 0, 11, :nc, :nc, 9, 4], - ] - - coldef.reject! do |c| c[0] > $oracle_version end - - drop_table('test_table') - sql = <<-EOS -CREATE TABLE test_table (#{idx = 0; coldef.collect do |c| idx += 1; "C#{idx} " + c[1]; end.join(',')}) -STORAGE ( - INITIAL 100k - NEXT 100k - MINEXTENTS 1 - MAXEXTENTS UNLIMITED - PCTINCREASE 0) -EOS - @conn.exec(sql) - - @conn.describe_table('test_table').columns.each_with_index do |md, i| - # common - assert_equal("C#{i + 1}", md.name, "'#{coldef[i][1]}': name") - assert_equal(coldef[i][1], md.type_string, "'#{coldef[i][1]}': type_string") - assert_equal(coldef[i][2], md.data_type, "'#{coldef[i][1]}': data_type") - assert_equal(coldef[i][3], md.charset_form, "'#{coldef[i][1]}': charset_form") - assert_equal(coldef[i][4], md.nullable?, "'#{coldef[i][1]}': nullable? ") - # string type - if $oracle_version >= OCI8::ORAVER_9_0 - assert_equal(coldef[i][5], md.char_used?, "'#{coldef[i][1]}': char_used? ") - assert_equal(coldef[i][6], md.char_size, "'#{coldef[i][1]}': char_size") - end - assert_equal(coldef[i][7], md.data_size, "'#{coldef[i][1]}': data_size") if coldef[i][7] != :nc - # number, timestamp and interval type - assert_equal(coldef[i][8], md.precision, "'#{coldef[i][1]}': precision") if coldef[i][8] != :nc - assert_equal(coldef[i][9], md.scale, "'#{coldef[i][1]}': scale") if coldef[i][9] != :nc - if $oracle_version >= OCI8::ORAVER_9_0 - assert_equal(coldef[i][10], md.fsprecision, "'#{coldef[i][1]}': fsprecision") if coldef[i][10] != :nc - assert_equal(coldef[i][11], md.lfprecision, "'#{coldef[i][1]}': lfprecision") if coldef[i][11] != :nc - end - end - - # temporarily change OCI8::BindType::Mapping. - saved_mapping = {} - [OCI8::SQLT_TIMESTAMP_TZ, - OCI8::SQLT_TIMESTAMP_LTZ, - OCI8::SQLT_INTERVAL_YM, - OCI8::SQLT_INTERVAL_DS].each do |sqlt_type| - saved_mapping[sqlt_type] = OCI8::BindType::Mapping[sqlt_type] - OCI8::BindType::Mapping[sqlt_type] = OCI8::BindType::String - end - begin - cursor = @conn.exec("SELECT * FROM test_table") - ensure - saved_mapping.each do |key, val| - OCI8::BindType::Mapping[key] = val - end - end - cursor.column_metadata.each_with_index do |md, i| - # common - assert_equal("C#{i + 1}", md.name, "'#{coldef[i][1]}': name") - assert_equal(coldef[i][1], md.type_string, "'#{coldef[i][1]}': type_string") - assert_equal(coldef[i][2], md.data_type, "'#{coldef[i][1]}': data_type") - assert_equal(coldef[i][3], md.charset_form, "'#{coldef[i][1]}': charset_form") - assert_equal(coldef[i][4], md.nullable?, "'#{coldef[i][1]}': nullable? ") - # string type - if $oracle_version >= OCI8::ORAVER_9_0 - assert_equal(coldef[i][5], md.char_used?, "'#{coldef[i][1]}': char_used? ") - assert_equal(coldef[i][6], md.char_size, "'#{coldef[i][1]}': char_size") - end - assert_equal(coldef[i][7], md.data_size, "'#{coldef[i][1]}': data_size") if coldef[i][7] != :nc - # number, timestamp and interval type - assert_equal(coldef[i][8], md.precision, "'#{coldef[i][1]}': precision") if coldef[i][8] != :nc - assert_equal(coldef[i][9], md.scale, "'#{coldef[i][1]}': scale") if coldef[i][9] != :nc - if $oracle_version >= OCI8::ORAVER_9_0 - assert_equal(coldef[i][10], md.fsprecision, "'#{coldef[i][1]}': fsprecision") if coldef[i][10] != :nc - assert_equal(coldef[i][11], md.lfprecision, "'#{coldef[i][1]}': lfprecision") if coldef[i][11] != :nc - end - end - - drop_table('test_table') - end - def test_error_describe_table drop_table('test_table') begin @@ -1005,4 +1345,52 @@ drop_type('TEST_TYPE_CHILD') drop_type('TEST_TYPE_PARENT') 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 + end + + coldef = @@column_test_data.find_all do |c| + $oracle_version >= c.oraver + 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(',')}) +STORAGE ( + INITIAL 100k + NEXT 100k + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + PCTINCREASE 0) +EOS + @conn.exec(sql) + + [ + @conn.describe_any('test_table').columns, + @conn.describe_table('test_table').columns, + @conn.describe_schema(@conn.username).objects.detect do |obj| + obj.obj_name == 'TEST_TABLE' + 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 + end + end + drop_table('test_table') + end # test_column_metadata + end # TestMetadata From nobody at rubyforge.org Mon Jun 28 06:10:42 2010 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Mon, 28 Jun 2010 06:10:42 -0400 (EDT) Subject: [ruby-oci8-commit] [401] tags/ruby-oci8-2.0.4/: tag 2.0.4 Message-ID: <20100628101042.81DE31858344@rubyforge.org> Revision: 401 Author: kubo Date: 2010-06-28 06:10:41 -0400 (Mon, 28 Jun 2010) Log Message: ----------- tag 2.0.4 Added Paths: ----------- tags/ruby-oci8-2.0.4/