Передать XML-файл в качестве параметра хранимой процедуре Oracle

#xml #oracle #perl #stored-procedures

#xml #Oracle #perl #хранимые процедуры

Вопрос:

Я пытаюсь передать XML-файл в качестве параметра в качестве XMLType в хранимую процедуру Oracle с помощью скрипта Perl.

Я использую Perl DBI и DBD::Oracle модули.

Я провел свое исследование и нашел, как это сделать по частям, но я не уверен, как собрать все вместе, чтобы достичь того, чего я хочу.

Должен ли я передавать XML-данные, содержащиеся в файле, в $xml виде строки или CLOB?

Большая часть синтаксического анализа XML и обновлений таблиц выполняется в хранимой процедуре.

Вот как далеко я продвинулся. Я не пытался выполнить сценарий, поскольку знаю, что он неполный.

 #!/usr/local/bin/perl

###############################################################################
# File Name:            load_data.pl
# Description:          Reads an input XML file and populates data into tables


use strict;

use Getopt::Std;
use DBI;
use DBD::Oracle qw(:ora_types);

# Properties file parser
#
use util::File;
use use util::DotConfigProperties;

# Generic Utilities
#
use util::GenericUtils qw(getEnv isPath isFile trim );

# Flush output buffers
#
$| = 1;

#############################################################################
# Local Variables

my %args = (
 AutoCommit => 0,
 RaiseError => 1,
 PrintError => 1
);


my $aConfig = amp;isFile( amp;getEnv('aConfig') );

# Get the DB properties and open the database connection
#

my $propObj     = new util::DotConfigProperties;
my $a_prop      = new util::File($aConfig);
$propObj->load($a_prop);

my $dbSid       = trim($propObj->getProperty('Database'));
my $user        = trim($propObj->getProperty('Username'));
my $password        = trim($propObj->getProperty('Password'));

my $dbh = DBI->connect("dbi:Oracle:$dbSid", $user, $password, %args) or croak("Couldn't connect to database: $dbSid" . DBI->errstr);

#############################################################################
# Input file
open(RFILE,"@ARGV[0]") or die("Unable to open read file");

#
# Read in the data from input file
# 
while (<RFILE>) {

$sth = $dbh->prepare( "BEGIN My_Procedure (p_xml in xmltype,
                                           p_out_xml out xmltype,
                                           p_message out varchar2,
                                           p_result out integer); END;" );

$sth->bind_param("p_xml", **$xml**, { ora_type => ORA_XMLTYPE });
$sth->bind_param_inout( ?, $p_out_xml, ? ); --**I am not sure what to put in place of the question marks?**
$sth->bind_param_inout( ?, $p_message, ? );
$sth->bind_param_inout( ?, $p_result, ? );
$sth->execute(  );
}

$dbh->commit();

###############################################################################
# Close anything open and exit

$dbh->disconnect();

exit;
  


Обновить

Я внес изменения, упомянутые @MichaelPiankov, и внес некоторые изменения. Это результат

 my $xml; 
while (<RFILE>) {
  $xml.= $_;
}

my $sth = $dbh->prepare( "BEGIN My_Procedure(:p_xml,
                                           :p_out_xml,
                                           :p_message,
                                           :p_result); END;" );
$sth->bind_param(":p_xml", $xml, { ora_type => ORA_XMLTYPE });

my $p_out_xml; 
my $p_message; 
my $p_resu< 

$sth->bind_param_inout(":p_out_xml", $p_out_xml, { ora_type => ORA_XMLTYPE } ); 
$sth->bind_param_inout(":p_message", $p_message, { ora_type => ORA_VARCHAR2 }  );
$sth->bind_param_inout(":p_result", $p_result, { ora_type => ORA_NUMBER } );

$sth->execute(  );

print "Out_XML: $p_out_xmln";
print "Message: $p_messagen";
print "Result: $p_resultn";

$dbh->commit();    
###############################################################################
# Close anything open and exit
$dbh->disconnect();
exit;
  

ошибка

 DBD::Oracle::st execute failed: ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'My_Procedure'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored (DBD ERROR: error possibly near <*> indicator at char 6 in 'BEGIN <*>My_Procedure(:p_xml,
                                           :p_out_xml,
                                           :p_message,
                                           :p_result); END;') [for Statement "BEGIN My_Procedure(:p_xml,
                                           :p_out_xml,
                                           :p_message,
                                           :p_result); END;" with ParamValues: :p_xml=OCIXMLTypePtr=SCALAR(0x9085170), :p_message=undef, :p_out_xml=undef, :p_result=undef] at load_tables.pl line 45, <RFILE> line 46947.
Out_XML:
Message:
Result:
commit ineffective with AutoCommit enabled at load_tables.pl line 51, <RFILE> line 46947.
  

2-е обновление

В итоге я удалил параметры out и успешно загрузил XML-файл, что и было моей целью, поскольку это было частью тестирования некоторого кода хранимой процедуры. Я хочу отдать должное @MichaelPiankov, поскольку его код помог мне загрузить файл.

 my $xml; 
while (<RFILE>) {
  $xml.= $_;
}

my $sth = $dbh->prepare( "BEGIN My_Procedure(:p_xml); END;" );
$sth->bind_param(":p_xml", $xml, { ora_type => ORA_XMLTYPE });

$sth-> execute();
  

Комментарии:

1. Вы не должны использовать амперсанды amp; для вызова подпрограмм Perl; это не было хорошей практикой уже около двадцати лет. Все, чему вы научились, устарело, и вам следует найти более свежий источник. Вы также должны use warnings 'all' в дополнение к use strict , и имена ваших пакетов и связанных с ними файлов должны быть заглавными буквами, так util::File должно быть и т.д. Util::File

2. Спасибо, Бородин, за ваше предложение, я обязательно внесу эти изменения.

Ответ №1:

Я думаю, что прежде всего вы должны записать файл в переменную, если он не такой большой. Далее вы должны указать привязки, которые я назвал их параметрами процедуры:p_xml, :p_out_xml, :p_message, :p_result, но вы можете использовать любые имена. И вы должны создать переменную для выходных значений $p_out_xml, $p_message $p_result

 ...
my $xml; 
while (<RFILE>) {
  $xml.= $_;
}

$sth = $dbh->prepare( "BEGIN My_Procedure (:p_xml,
                                           :p_out_xml,
                                           :p_message,
                                           :p_result); END;" );
$sth->bind_param("p_xml", $xml, { ora_type => ORA_XMLTYPE });

my $p_out_xml; 
my $p_message; 
my $p_resu< 

$sth->bind_param_inout("p_out_xml", $p_out_xml, { ora_type => ORA_XMLTYPE } ); 
$sth->bind_param_inout("p_message", $p_message );
$sth->bind_param_inout("p_result", $p_result);

$sth->execute(  );
...