Module: PLSQL::ProcedureCommon

Included in:
Procedure, Type::TypeProcedure
Defined in:
lib/plsql/procedure.rb

Overview

:nodoc:

Constant Summary collapse

PLSQL_COMPOSITE_TYPES =
['PL/SQL RECORD', 'PL/SQL TABLE', 'TABLE', 'VARRAY', 'REF CURSOR'].freeze
PLSQL_COLLECTION_TYPES =
['PL/SQL TABLE', 'TABLE', 'VARRAY'].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#argument_listObject (readonly)

Returns the value of attribute argument_list.



46
47
48
# File 'lib/plsql/procedure.rb', line 46

def argument_list
  @argument_list
end

#argumentsObject (readonly)

Returns the value of attribute arguments.



46
47
48
# File 'lib/plsql/procedure.rb', line 46

def arguments
  @arguments
end

#out_listObject (readonly)

Returns the value of attribute out_list.



46
47
48
# File 'lib/plsql/procedure.rb', line 46

def out_list
  @out_list
end

#packageObject (readonly)

Returns the value of attribute package.



47
48
49
# File 'lib/plsql/procedure.rb', line 47

def package
  @package
end

#procedureObject (readonly)

Returns the value of attribute procedure.



47
48
49
# File 'lib/plsql/procedure.rb', line 47

def procedure
  @procedure
end

#returnObject (readonly)

Returns the value of attribute return.



46
47
48
# File 'lib/plsql/procedure.rb', line 46

def return
  @return
end

#schemaObject (readonly)

Returns the value of attribute schema.



47
48
49
# File 'lib/plsql/procedure.rb', line 47

def schema
  @schema
end

#schema_nameObject (readonly)

Returns the value of attribute schema_name.



47
48
49
# File 'lib/plsql/procedure.rb', line 47

def schema_name
  @schema_name
end

Class Method Details

.type_to_sql(metadata) ⇒ Object

return type string from metadata that can be used in DECLARE block or table definition



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/plsql/procedure.rb', line 50

def self.type_to_sql() #:nodoc:
  case [:data_type]
  when 'NUMBER'
    precision, scale = [:data_precision], [:data_scale]
    "NUMBER#{precision ? "(#{precision}#{scale ? ",#{scale}": ""})" : ""}"
  when 'VARCHAR2', 'CHAR', 'NVARCHAR2', 'NCHAR'
    length = [:data_length]
    if length && (char_used = [:char_used])
      length = "#{length} #{char_used == 'C' ? 'CHAR' : 'BYTE'}"
    end
    "#{[:data_type]}#{length ? "(#{length})": ""}"
  when 'PL/SQL TABLE', 'TABLE', 'VARRAY', 'OBJECT'
    [:sql_type_name]
  else
    [:data_type]
  end
end

Instance Method Details

#collection_type?(data_type) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


218
219
220
# File 'lib/plsql/procedure.rb', line 218

def collection_type?(data_type) #:nodoc:
  PLSQL_COLLECTION_TYPES.include? data_type
end

#composite_type?(data_type) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


213
214
215
# File 'lib/plsql/procedure.rb', line 213

def composite_type?(data_type) #:nodoc:
  PLSQL_COMPOSITE_TYPES.include? data_type
end

#construct_argument_list_for_overloadsObject

:nodoc:



180
181
182
183
184
185
186
# File 'lib/plsql/procedure.rb', line 180

def construct_argument_list_for_overloads #:nodoc:
  @overloads = @arguments.keys.sort
  @overloads.each do |overload|
    @argument_list[overload] = @arguments[overload].keys.sort {|k1, k2| @arguments[overload][k1][:position] <=> @arguments[overload][k2][:position]}
    @out_list[overload] = @argument_list[overload].select {|k| @arguments[overload][k][:in_out] =~ /OUT/}
  end
end

#ensure_tmp_tables_created(overload) ⇒ Object

:nodoc:



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/plsql/procedure.rb', line 188

def ensure_tmp_tables_created(overload) #:nodoc:
  return if @tmp_tables_created.nil? || @tmp_tables_created[overload]
  @tmp_table_names[overload] && @tmp_table_names[overload].each do |table_name, |
    sql = "CREATE GLOBAL TEMPORARY TABLE #{table_name} (\n"
       = [:element]
      case [:data_type]
      when 'PL/SQL RECORD'
         = [:fields]
        fields_sorted_by_position = .keys.sort_by{|k| [k][:position]}
        sql << fields_sorted_by_position.map do |field|
           = [field]
          "#{field} #{ProcedureCommon.type_to_sql()}"
        end.join(",\n")
      else
        sql << "element #{ProcedureCommon.type_to_sql()}"
      end
      sql << ",\ni__ NUMBER(38)\n"
    sql << ") ON COMMIT PRESERVE ROWS\n"
    sql_block = "DECLARE\nPRAGMA AUTONOMOUS_TRANSACTION;\nBEGIN\nEXECUTE IMMEDIATE :sql;\nEND;\n"
    @schema.execute sql_block, sql
  end
  @tmp_tables_created[overload] = true
end

#get_argument_metadataObject

get procedure argument metadata from data dictionary



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/plsql/procedure.rb', line 69

def  #:nodoc:
  @arguments = {}
  @argument_list = {}
  @out_list = {}
  @return = {}
  @overloaded = false

  # store reference to previous level record or collection metadata
   = {}

  # store tmp tables for each overload for table parameters with types defined inside packages
  @tmp_table_names = {}
  # store if tmp tables are created for specific overload
  @tmp_tables_created = {}

  # subprogram_id column is available just from version 10g
  subprogram_id_column = (@schema.connection.database_version <=> [10, 2, 0, 2]) >= 0 ? 'subprogram_id' : 'NULL'

  @schema.select_all(
    "SELECT #{subprogram_id_column}, object_name, TO_NUMBER(overload), argument_name, position, data_level,
          data_type, in_out, data_length, data_precision, data_scale, char_used,
          type_owner, type_name, type_subname
    FROM all_arguments
    WHERE object_id = :object_id
    AND owner = :owner
    AND object_name = :procedure_name
    ORDER BY overload, sequence",
    @object_id, @schema_name, @procedure
  ) do |r|

    subprogram_id, object_name, overload, argument_name, position, data_level,
        data_type, in_out, data_length, data_precision, data_scale, char_used,
        type_owner, type_name, type_subname = r

    @overloaded ||= !overload.nil?
    # if not overloaded then store arguments at key 0
    overload ||= 0
    @arguments[overload] ||= {}
    @return[overload] ||= nil
    @tmp_table_names[overload] ||= []

    sql_type_name = type_owner && "#{type_owner == 'PUBLIC' ? nil : "#{type_owner}."}#{type_name}#{type_subname ? ".#{type_subname}" : nil}"

    tmp_table_name = nil
    # type defined inside package
    if type_subname
      if collection_type?(data_type)
        raise ArgumentError, "#{data_type} type #{sql_type_name} definition inside package is not supported as part of other type definition," <<
          " use CREATE TYPE outside package" if data_level > 0
        # if subprogram_id was not supported by all_arguments view
        # then generate unique ID from object_name and overload
        subprogram_id ||= "#{object_name.hash % 10000}#{overload}"
        tmp_table_name = "#{Connection::RUBY_TEMP_TABLE_PREFIX}#{@schema.connection.session_id}_#{@object_id}_#{subprogram_id}_#{position}"
      elsif data_type != 'PL/SQL RECORD'
        # raise exception only when there are no overloaded procedure definitions
        # (as probably this overload will not be used at all)
        raise ArgumentError, "Parameter type #{sql_type_name} definition inside package is not supported, use CREATE TYPE outside package" if overload == 0
      end
    end

     = {
      :position => position && position.to_i,
      :data_type => data_type,
      :in_out => in_out,
      :data_length => data_length && data_length.to_i,
      :data_precision => data_precision && data_precision.to_i,
      :data_scale => data_scale && data_scale.to_i,
      :char_used => char_used,
      :type_owner => type_owner,
      :type_name => type_name,
      :type_subname => type_subname,
      :sql_type_name => sql_type_name
    }
    if tmp_table_name
      @tmp_table_names[overload] << [([:tmp_table_name] = tmp_table_name), ]
    end

    if composite_type?(data_type)
      case data_type
      when 'PL/SQL RECORD'
        [:fields] = {}
      end
      [data_level] = 
    end

    # if function has return value
    if argument_name.nil? && data_level == 0 && in_out == 'OUT'
      @return[overload] = 
    # if parameter
    else
      # top level parameter
      if data_level == 0
        # sometime there are empty IN arguments in all_arguments view for procedures without arguments (e.g. for DBMS_OUTPUT.DISABLE)
        @arguments[overload][argument_name.downcase.to_sym] =  if argument_name
      # or lower level part of composite type
      else
        case [data_level - 1][:data_type]
        when 'PL/SQL RECORD'
          [data_level - 1][:fields][argument_name.downcase.to_sym] = 
        when 'PL/SQL TABLE', 'TABLE', 'VARRAY', 'REF CURSOR'
          [data_level - 1][:element] = 
        end
      end
    end
  end
  # if procedure is without arguments then create default empty argument list for default overload
  @arguments[0] = {} if @arguments.keys.empty?

  construct_argument_list_for_overloads
end

#overloaded?Boolean

:nodoc:

Returns:

  • (Boolean)


222
223
224
# File 'lib/plsql/procedure.rb', line 222

def overloaded? #:nodoc:
  @overloaded
end