class OCI8::TDO

@private

def self.check_metadata(con, metadata)

def self.check_metadata(con, metadata)
  case metadata.typecode
  when :char, :varchar, :varchar2
    [ATTR_STRING,    nil, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
  when :raw
    [ATTR_RAW,       nil, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
  when :number, :decimal
    [ATTR_OCINUMBER, nil, SIZE_OF_OCINUMBER, 2, ALIGNMENT_OF_OCINUMBER]
  when :integer, :smallint
    [ATTR_INTEGER,   nil, SIZE_OF_OCINUMBER, 2, ALIGNMENT_OF_OCINUMBER]
  when :real, :double, :float
    [ATTR_FLOAT,     nil, SIZE_OF_OCINUMBER, 2, ALIGNMENT_OF_OCINUMBER]
  when :date
    [ATTR_OCIDATE,   nil, SIZE_OF_OCIDATE, 2, ALIGNMENT_OF_OCIDATE,
     Proc.new do |val| datetime_to_array(val, :date) end, # set_proc
     Proc.new do |val| array_to_time(val, :local) end, # get_proc
    ]
  when :timestamp
    [ATTR_TIMESTAMP, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
     Proc.new do |val| datetime_to_array(val, :timestamp) end, # set_proc
     Proc.new do |val| array_to_time(val, :local) end, # get_proc
    ]
  when :timestamp_tz
    [ATTR_TIMESTAMP_TZ, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
     Proc.new do |val| datetime_to_array(val, :timestamp_tz) end, # set_proc
     Proc.new do |val| array_to_time(val, nil) end, # get_proc
    ]
  when :binary_double
    [ATTR_BINARY_DOUBLE, nil, SIZE_OF_DOUBLE, 2, ALIGNMENT_OF_DOUBLE]
  when :binary_float
    [ATTR_BINARY_FLOAT, nil, SIZE_OF_FLOAT, 2, ALIGNMENT_OF_FLOAT]
  when :named_type
    tdo = con.get_tdo_by_metadata(metadata.type_metadata)
    [ATTR_NAMED_TYPE, tdo, tdo.val_size, tdo.ind_size, tdo.alignment]
  when :named_collection
    #datatype, typeinfo, = OCI8::TDO.check_metadata(con, metadata.type_metadata.collection_element)
    #[ATTR_NAMED_COLLECTION, [datatype, typeinfo], SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
    tdo = con.get_tdo_by_metadata(metadata.type_metadata)
    [ATTR_NAMED_COLLECTION, tdo, tdo.val_size, tdo.ind_size, tdo.alignment]
  when :clob
    if metadata.charset_form != :nchar
      [ATTR_CLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
    else
      [ATTR_NCLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
    end
  when :blob
    [ATTR_BLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
  when :bfile
    [ATTR_BFILE, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
  else
    raise "unsupported typecode #{metadata.typecode}"
  end
end

def initialize(con, metadata, klass)

def initialize(con, metadata, klass)
  @ruby_class = klass
  @typename = metadata.schema_name + '.' + metadata.name
  setup(con, metadata)
  con.instance_variable_get(:@id_to_tdo)[metadata.tdo_id] = self
  con.instance_variable_get(:@name_to_tdo)[@typename] = self
  con.instance_variable_get(:@name_to_tdo)[klass.typename] = self
  if metadata.schema_name == con.username
    con.instance_variable_get(:@name_to_tdo)[metadata.name] = self
  end
  case metadata.typecode
  when :named_type
    @is_final_type = metadata.is_final_type?
    initialize_named_type(con, metadata)
  when :named_collection
    @is_final_type = true
    initialize_named_collection(con, metadata)
  end
end

def initialize_named_collection(con, metadata)

def initialize_named_collection(con, metadata)
  @val_size = SIZE_OF_POINTER
  @ind_size = 2
  @alignment = ALIGNMENT_OF_POINTER
  @coll_attr = Attr.new(con, metadata.collection_element, 0, 0)
end

def initialize_named_type(con, metadata)

def initialize_named_type(con, metadata)
  @val_size = 0
  @ind_size = 2
  @alignment = 1
  @attributes = metadata.type_attrs.collect do |type_attr|
    attr = Attr.new(con, type_attr, @val_size, @ind_size)
    @val_size, @ind_size = attr.next_offset
    if @alignment < attr.alignment
      @alignment = attr.alignment
    end
    attr
  end
  # fix alignment
  @val_size = (@val_size + @alignment - 1) & ~(@alignment - 1)
  # setup attr_getters and attr_setters
  @attr_getters = {}
  @attr_setters = {}
  @attributes.each do |attr|
    @attr_getters[attr.name] = attr
    @attr_setters[(attr.name.to_s + '=').intern] = attr
  end
  # set class_methods and instance_methods
  @class_methods = {}
  @instance_methods = {}
  metadata.type_methods.each_with_index do |type_method, i|
    next if type_method.is_constructor? or type_method.is_destructor?
    result_type = nil
    if type_method.has_result?
      # function
      con.exec_internal("select result_type_owner, result_type_name from all_method_results where OWNER = :1 and TYPE_NAME = :2 and METHOD_NO = :3", metadata.schema_name, metadata.name, i + 1) do |r|
        if r[0].nil?
          result_type = @@result_type_to_bindtype[r[1]]
        else
          result_type = con.get_tdo_by_metadata(con.describe_type("#{r[0]}.#{r[1]}"))
        end
      end
    else
      # procedure
      result_type = :none
    end
    if result_type
      if type_method.is_selfish?
        @instance_methods[type_method.name.downcase.intern] = result_type
      else
        @class_methods[type_method.name.downcase.intern] = result_type
      end
    else
      warn "unsupported return type (#{metadata.schema_name}.#{metadata.name}.#{type_method.name})" if $VERBOSE
    end
  end
end

def inspect

def inspect
  "#<#{self.class}:#@typename>"
end

def is_collection?

def is_collection?
  @coll_attr ? true : false
end