dbd perl oracle dbi

perl - dbd:: oracle



Perl DBI: ejecuta SQL Script con mĂșltiples instrucciones (4)

La base de datos controla cuántas sentencias se pueden ejecutar a la vez. No recuerdo si Oracle permite múltiples declaraciones por prepare o no (MySQL lo hace). Prueba esto:

my $dbh = DBI->connect( "dbi:Oracle:dbname", "username", "password", { ChopBlanks => 1, AutoCommit => 1, RaiseError => 1, PrintError => 1, FetchHashKeyName => ''NAME_lc'', } ); $dbh->do(" CREATE TABLE test_dbi1 ( test_dbi_intr_no NUMBER(15), test_dbi_name VARCHAR2(100) ); UPDATE mytable SET col1=1; CREATE TABLE test_dbi2 ( test_dbi_intr_no NUMBER(15), test_dbi_name VARCHAR2(100) ); "); $dbh->disconnect;

Por supuesto, obtendrá un mejor manejo de errores si rompe las declaraciones. Puede usar un analizador simple para dividir la cadena en declaraciones individuales:

#!/usr/bin/perl use strict; use warnings; my $sql = " CREATE TABLE test_dbi1 ( test_dbi_intr_no NUMBER(15), test_dbi_name VARCHAR2(100) ); UPDATE mytable SET col1='';yes;'' WHERE col2=1; UPDATE mytable SET col1=''Don//'t use ;s and //'s together, it is a pain'' WHERE col2=1; CREATE TABLE test_dbi2 ( test_dbi_intr_no NUMBER(15), test_dbi_name VARCHAR2(100) ); "; my @statements = (""); #split the string into interesting pieces (i.e. tokens): # '' delimits strings # / pass on the next character if inside a string # ; delimits statements unless it is in a string # and anything else # NOTE: the grep { ord } is to get rid of the nul # characters the split seems to be adding my @tokens = grep { ord } split /([//';])/, $sql; # NOTE: this '' fixes the stupid SO syntax highlighter #this is true if we are in a string and should ignore ; my $in_string = 0; my $escape = 0; #while there are still tokens to process while (@tokens) { #grab the next token my $token = shift @tokens; #if we are in a string if ($in_string) { #add the token to the last statement $statements[-1] .= $token; #setup the escape if the token is / if ($token eq "//") { $escape = 1; next; } #turn off $in_string if the token is '' and it isn''t escaped $in_string = 0 if not $escape and $token eq "''"; $escape = 0; #turn off escape if it was on #loop again to get the next token next; } #if the token is ; and we aren''t in a string if ($token eq '';'') { #create a new statement push @statements, ""; #loop again to get the next token next; } #add the token to the last statement $statements[-1] .= $token; #if the token is '' then turn on $in_string $in_string = 1 if $token eq "''"; } #only keep statements that are not blank @statements = grep { //S/ } @statements; for my $i (0 .. $#statements) { print "statement $i:/n$statements[$i]/n/n"; }

Tengo un archivo sql test.sql utilizado para ejecutar algunos SQL (crear objeto / actualizar / eliminar / insertar) que se puede ver así

CREATE TABLE test_dbi1 ( test_dbi_intr_no NUMBER(15) , test_dbi_name VARCHAR2(100); UPDATE mytable SET col1=1; CREATE TABLE test_dbi2 ( test_dbi_intr_no NUMBER(15) , test_dbi_name VARCHAR2(100);

Por lo general, solo usaría SQLPLUS (desde dentro de Perl) para ejecutar este test.sql usando este comando: @ test.sql

¿Hay alguna manera de hacer lo mismo usando DBI en Perl? Hasta ahora, he encontrado que DBI solo puede ejecutar una declaración a la vez, y sin el ";" al final.


Oracle puede ejecutar múltiples instrucciones SQL en una preparación usando un bloque PL / SQL anónimo.

p.ej

$dbh->do(" BEGIN UPDATE table_1 SET col_a = col_a -1; DELETE FROM table_2 where id in (select id from table_1 where col_a = 0); END; ");

DDL (creación o eliminación de objetos) es más complicado, sobre todo porque es algo que no debería estar haciendo ad-hoc.


Por favor, eche un vistazo a este nuevo módulo de CPAN: DBIx :: MultiStatementDo

Ha sido concebido precisamente para eso.


Puede agregar otra capa de lógica en Perl que analiza el script SQL, lo divide en sentencias y lo ejecuta uno por uno utilizando la técnica anterior

--sql file -- [statement1] SQLCODE... -- [statement2] SQLCODE... #Gets queries from file. sub sql_q { my ($self) = @_; return $self->{sql_q} if $self->{sql_q}; my $file = $self->{sql_queries_file}; $self->{sql_q} || do { -e $file || croak( ''Queries file '' . $file . '' can not be found.'' ); my $fh = IO::File->new("< $file"); my @lines; ( $fh->binmode and @lines = $fh->getlines and $fh->close ) or croak $!; my ($key); foreach ( 0 .. @lines - 1 ) { next if ( $lines[$_] =~ /^;/ ); if ( $lines[$_] =~ /^--/s*?/[(/w+)/]/ ) { $key = $1; } $self->{sql_q}{$key} .= $lines[$_] if $key; } }; return $self->{sql_q}; } #then in your script #foreach statement something like $dbh->prepare($sql_obj->{sql_q}->{statement_name})->execute(@bindvars);