From 070035617af528dee25f59fce26f746d38dd30ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20G=C4=99bal?= Date: Thu, 17 Sep 2015 22:58:06 +0100 Subject: [PATCH] Added XML support --- lib/plsql/jdbc_connection.rb | 4 +-- lib/plsql/oci_connection.rb | 2 +- lib/plsql/procedure.rb | 2 +- lib/plsql/procedure_call.rb | 23 +++++++++++++++++- lib/plsql/variable.rb | 5 ++-- spec/plsql/procedure_spec.rb | 47 ++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/lib/plsql/jdbc_connection.rb b/lib/plsql/jdbc_connection.rb index 1b930d98..5c5674ce 100644 --- a/lib/plsql/jdbc_connection.rb +++ b/lib/plsql/jdbc_connection.rb @@ -107,7 +107,7 @@ def bind_param(arg, value, metadata) if metadata[:in_out] =~ /OUT/ @out_types[arg] = type || ora_value.class @out_index[arg] = bind_param_index(arg) - if ['TABLE','VARRAY','OBJECT'].include?(metadata[:data_type]) + if ['TABLE','VARRAY','OBJECT','XMLTYPE'].include?(metadata[:data_type]) @statement.registerOutParameter(@out_index[arg], @connection.get_java_sql_type(ora_value,type), metadata[:sql_type_name]) else @@ -277,7 +277,7 @@ def set_bind_variable(stmt, i, value, type=nil, length=nil, metadata={}) when :Time, :'Java::JavaSql::Timestamp' stmt.send("setTimestamp#{key && "AtName"}", key || i, value) when :NilClass - if ['TABLE', 'VARRAY', 'OBJECT'].include?(metadata[:data_type]) + if ['TABLE', 'VARRAY', 'OBJECT','XMLTYPE'].include?(metadata[:data_type]) stmt.send("setNull#{key && "AtName"}", key || i, get_java_sql_type(value, type), metadata[:sql_type_name]) elsif metadata[:data_type] == 'REF CURSOR' diff --git a/lib/plsql/oci_connection.rb b/lib/plsql/oci_connection.rb index 374023d9..e9e3c310 100644 --- a/lib/plsql/oci_connection.rb +++ b/lib/plsql/oci_connection.rb @@ -159,7 +159,7 @@ def plsql_to_ruby_data_type(metadata) [DateTime, nil] when "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE" [Time, nil] - when "TABLE", "VARRAY", "OBJECT" + when "TABLE", "VARRAY", "OBJECT", "XMLTYPE" # create Ruby class for collection klass = OCI8::Object::Base.get_class_by_typename(metadata[:sql_type_name]) unless klass diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 4ad3ff17..f17be90a 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -75,7 +75,7 @@ def self.type_to_sql(metadata) #:nodoc: when 'NVARCHAR2', 'NCHAR' length = metadata[:char_length] "#{metadata[:data_type]}#{length && "(#{length})"}" - when 'PL/SQL TABLE', 'TABLE', 'VARRAY', 'OBJECT' + when 'PL/SQL TABLE', 'TABLE', 'VARRAY', 'OBJECT', 'XMLTYPE' metadata[:sql_type_name] else metadata[:data_type] diff --git a/lib/plsql/procedure_call.rb b/lib/plsql/procedure_call.rb index 74c95c9e..5955fb83 100644 --- a/lib/plsql/procedure_call.rb +++ b/lib/plsql/procedure_call.rb @@ -111,7 +111,7 @@ def get_overload_from_arguments_list(args) MATCHING_TYPES = { :integer => ['NUMBER', 'NATURAL', 'NATURALN', 'POSITIVE', 'POSITIVEN', 'SIGNTYPE', 'SIMPLE_INTEGER', 'PLS_INTEGER', 'BINARY_INTEGER'], :decimal => ['NUMBER', 'BINARY_FLOAT', 'BINARY_DOUBLE'], - :string => ['VARCHAR', 'VARCHAR2', 'NVARCHAR2', 'CHAR', 'NCHAR', 'CLOB', 'BLOB'], + :string => ['VARCHAR', 'VARCHAR2', 'NVARCHAR2', 'CHAR', 'NCHAR', 'CLOB', 'BLOB', 'XMLTYPE'], :date => ['DATE'], :time => ['DATE', 'TIMESTAMP', 'TIMESTAMP WITH TIME ZONE', 'TIMESTAMP WITH LOCAL TIME ZONE'], :boolean => ['PL/SQL BOOLEAN'], @@ -236,6 +236,14 @@ def add_argument(argument, value, argument_metadata=nil) @bind_values[argument] = value.nil? ? nil : (value ? 1 : 0) @bind_metadata[argument] = argument_metadata.merge(:data_type => "NUMBER", :data_precision => 1) "l_#{argument}" + when 'UNDEFINED' + if argument_metadata[:type_name] == 'XMLTYPE' + @declare_sql << "l_#{argument} XMLTYPE;\n" + @assignment_sql << "l_#{argument} := XMLTYPE(:#{argument});\n" if not value.nil? + @bind_values[argument] = value if not value.nil? + @bind_metadata[argument] = argument_metadata.merge(:data_type => "CLOB") + "l_#{argument}" + end else # TABLE or PL/SQL TABLE type defined inside package if argument_metadata[:tmp_table_name] @@ -383,6 +391,15 @@ def add_return_variable(argument, argument_metadata, is_return_value=false) end end "l_#{argument} := " if is_return_value + when 'UNDEFINED' + if argument_metadata[:type_name] == 'XMLTYPE' + @declare_sql << "l_#{argument} XMLTYPE;\n" if is_return_value + bind_variable = :"o_#{argument}" + @return_vars << bind_variable + @return_vars_metadata[bind_variable] = argument_metadata.merge(:data_type => "CLOB") + @return_sql << ":#{bind_variable} := CASE WHEN l_#{argument} IS NOT NULL THEN l_#{argument}.getclobval() END;\n" + "l_#{argument} := " if is_return_value + end when 'PL/SQL BOOLEAN' @declare_sql << "l_#{argument} BOOLEAN;\n" if is_return_value @declare_sql << "o_#{argument} NUMBER(1);\n" @@ -496,6 +513,10 @@ def return_variable_value(argument, argument_metadata) when 'PL/SQL BOOLEAN' numeric_value = @cursor[":o_#{argument}"] numeric_value.nil? ? nil : numeric_value == 1 + when 'UNDEFINED' + if argument_metadata[:type_name] == 'XMLTYPE' + @cursor[":o_#{argument}"] + end else if argument_metadata[:tmp_table_name] is_index_by_table = argument_metadata[:data_type] == 'PL/SQL TABLE' diff --git a/lib/plsql/variable.rb b/lib/plsql/variable.rb index d5243dab..667fc513 100644 --- a/lib/plsql/variable.rb +++ b/lib/plsql/variable.rb @@ -51,7 +51,8 @@ def metadata(type_string) {:data_type => $1, :data_length => $3.to_i, :in_out => 'IN/OUT'} when /^(CLOB|NCLOB|BLOB)$/, /^(NUMBER)(\(.*\))?$/, /^(NATURAL|NATURALN|POSITIVE|POSITIVEN|SIGNTYPE|SIMPLE_INTEGER|PLS_INTEGER|BINARY_INTEGER)$/, - /^(DATE|TIMESTAMP|TIMESTAMP WITH TIME ZONE|TIMESTAMP WITH LOCAL TIME ZONE)$/ + /^(DATE|TIMESTAMP|TIMESTAMP WITH TIME ZONE|TIMESTAMP WITH LOCAL TIME ZONE)$/, + /^(XMLTYPE)$/ {:data_type => $1, :in_out => 'IN/OUT'} when /^INTEGER$/ {:data_type => 'NUMBER', :in_out => 'IN/OUT'} @@ -143,4 +144,4 @@ def call_sql(params_string) end -end \ No newline at end of file +end diff --git a/spec/plsql/procedure_spec.rb b/spec/plsql/procedure_spec.rb index 4bdee21a..12c8c1e3 100644 --- a/spec/plsql/procedure_spec.rb +++ b/spec/plsql/procedure_spec.rb @@ -235,6 +235,53 @@ end + describe "Function or procedure with XMLType parameters" do + before(:all) do + plsql.connect! CONNECTION_PARAMS + plsql.execute <<-SQL + CREATE OR REPLACE FUNCTION test_xmltype + ( p_xml XMLTYPE ) + RETURN XMLTYPE + IS + BEGIN + RETURN p_xml; + END test_xmltype; + SQL + plsql.execute <<-SQL + CREATE OR REPLACE PROCEDURE test_xmltype2 + ( p_xml XMLTYPE, po_xml OUT XMLTYPE ) + IS + BEGIN + po_xml := p_xml; + END test_xmltype2; + SQL + end + + after(:all) do + plsql.execute "DROP FUNCTION test_xmltype" + plsql.execute "DROP PROCEDURE test_xmltype2" + plsql.logoff + end + + it "should process XMLType parameters" do + xml = 'value' + result = plsql.test_xmltype(xml) + expect(result).to eq('value') + end + + it "should work when passing a NULL value" do + result = plsql.test_xmltype(nil) + expect(result).to be_nil + end + + it "should assign input parameter to putput parameter" do + xml = 'value' + result = plsql.test_xmltype2(xml) + expect(result[:po_xml]).to eq('value') + end + end + + describe "Procedure with output parameters" do before(:all) do plsql.connect! CONNECTION_PARAMS