Pregunta

Me encontré con lo que parece ser un problema de alcance variable que no había encontrado antes.Estoy usando el módulo CGI de Perl y una llamada al método do() de DBI.Aquí está la estructura del código, un poco simplificada:

use DBI;
use CGI qw(:cgi-lib);
&ReadParse;
my $dbh = DBI->connect(...............);
my $test = $in{test};
$dbh->do(qq{INSERT INTO events VALUES (?,?,?)},undef,$in{test},"$in{test}",$test);

La variable de marcador de posición n.º 1 se evalúa como si no estuviera inicializada.Las otras dos variables de marcador de posición funcionan.

La pregunta:¿Por qué el hash %in no está disponible en el contexto de do(), a menos que lo incluya entre comillas dobles (marcador de posición n.° 2) o reasigne el valor a una nueva variable (marcador de posición n.° 3)?

Creo que tiene algo que ver con cómo la función ReadParse() del módulo CGI asigna alcance al hash %in, pero no conozco el alcance de Perl lo suficientemente bien como para entender por qué %in está disponible en el nivel superior pero no desde mi dominio. () declaración.

Si alguien comprende el problema del alcance, ¿existe una mejor manera de manejarlo?Envolver todas las referencias %in entre comillas dobles parece un poco complicado.Crear nuevas variables para cada parámetro de consulta no es realista.

Para que quede claro, mi pregunta es sobre la cuestión del alcance variable.Me doy cuenta de que ReadParse() no es el método recomendado para capturar parámetros de consulta con CGI.

Estoy usando Perl 5.8.8, CGI 3.20 y DBI 1.52.Gracias de antemano a cualquiera que lea esto.

@Pi y @Bob, gracias por las sugerencias.Declarar previamente el alcance de %in no tiene ningún efecto (y siempre uso estricto).El resultado es el mismo que antes:en la base de datos, col1 es nula mientras que las columnas 2 y 3 están configuradas en el valor esperado.

Como referencia, aquí está la función ReadParse (ver más abajo).Es una función estándar que forma parte de CGI.pm.Según tengo entendido, no debo inicializar el hash %in (aparte de satisfacer estricto) con el fin de establecer el alcance, ya que me parece que la función maneja eso:

sub ReadParse {
    local(*in);
    if (@_) {
      *in = $_[0];
    } else {
    my $pkg = caller();
      *in=*{"${pkg}::in"};
    }
    tie(%in,CGI);
    return scalar(keys %in);
}

Supongo que mi pregunta es ¿cuál es la mejor manera de obtener el %in hash dentro del contexto de do()?¡Gracias de nuevo!Espero que esta sea la forma correcta de proporcionar información adicional a mi pregunta original.

@dan:Te escucho sobre la sintaxis de &ReadParse.Normalmente usaría CGI::ReadParse() pero en este caso pensé que era mejor ceñirme a cómo la documentación CGI.pm lo tiene exactamente.

¿Fue útil?

Solución

Según la documentación del DBI:Vincular una variable vinculada no funciona actualmente.

DBI es bastante complicado bajo el capó y, desafortunadamente, pasa por algunos cambios para ser eficiente que están causando el problema.Estoy de acuerdo con todos los que dicen que debemos deshacernos del viejo y feo código de estilo cgi-lib.Ya es bastante desagradable hacer CGI sin un buen marco (vaya a Catalyst), y mucho menos algo que ha estado obsoleto durante una década.

Otros consejos

En realidad, no parece que lo estés usando como se describe en los documentos:https://metacpan.org/pod/CGI#COMPATIBILIDAD-CON-CGI-LIB.PL

Si debe usarlo, entonces CGI::ReadParse();Parece una sintaxis más sensata y menos tosca.Aunque no veo que haga mucha diferencia en esta situación, pero es una variable ligada, así que quién diablos sabe lo que está haciendo;)

¿Hay alguna razón particular por la que no puedas usar la sintaxis $cgi->param('foo') más común?Es un poco más limpio y ensucia su espacio de nombres de una manera considerablemente más predecible.

use strict;.Siempre.

Intenta declarar

our %in;

y ver si eso ayuda.Fallando en eso, strict puede producir un error más útil.

No sé qué pasa, pero puedo decirte algunas cosas que no lo están:

  • No es una cuestión de alcance.Si así fuera, entonces ninguno de los casos de $in{test} trabajaría.
  • no es lo arcaico & sintaxis de llamada.(No es "correcto", pero en este caso es inofensivo).

ReadParse es un código desagradable.Munge la tabla de símbolos para crear la variable global %in en el paquete de llamada.Lo peor es que es una variable vinculada, por lo que acceder a ella podría (teóricamente) hacer cualquier cosa.Mirando el código fuente de CGI.pm, el FETCH El método simplemente invoca el params() método para obtener los datos.No tengo idea de por qué la búsqueda en el $dbh->do() no está funcionando.

En primer lugar, eso no está en el contexto/alcance de do.Todavía está en el contexto de principal o global.No sales del contexto hasta que ingresas {} de alguna manera relacionado con subrutinas o diferentes 'clases' en Perl.Dentro de los pares () no estás saliendo del alcance.

La muestra que nos proporcionó es de un hash no inicializado y, como sugirió Pi, el uso estricto ciertamente evitará que esto ocurra.

¿Puedes darnos un ejemplo más representativo de tu código?¿Dónde estás configurando %IN y cómo?

Algo está muy roto allí.El alcance de Perl es relativamente simple y es poco probable que te topes con algo extraño como eso a menos que estés haciendo algo tonto.Como se ha sugerido, active el pragma estricto (y también las advertencias).De hecho, deberías usar ambos de todos modos).

Es bastante difícil saber qué está pasando sin poder ver cómo se define %in (¿tiene algo que ver con esa desagradable llamada ReadParse?¿Por qué lo llamas con el & inicial, por cierto?esa sintaxis se ha considerado muerta y desaparecida durante mucho tiempo).Sugiero publicar un poco más de código para que podamos ver qué está pasando.

¿Qué versión de DBI estás usando?De mirar el Registro de cambios de DBI parece que las versiones anteriores a la 1.00 no admitían el argumento del atributo.Sospecho que el "no inicializado" $in{test} es en realidad el undef que estás pasando a $dbh->do().

Por el ejemplo que diste, esto es no un problema de alcance, o ninguno de los parámetros funcionaría.

Parece que DBI (o un DBD, no estoy seguro de dónde se usan los parámetros de enlace) no respeta la magia del vínculo.La solución alternativa sería encadenar o copiar lo que le pasa, como lo hacen el segundo y tercer parámetro.

Una prueba simple usando SQLite y DBI 1.53 muestra que funciona bien:

$ perl -MDBI -we'sub TIEHASH { bless {} } sub FETCH { "42" } tie %x, "main" or die; my $dbh = DBI->connect("dbi:SQLite:dbname=dbfile","",""); $dbh->do("create table foo (bar char(80))"); $dbh->do("insert into foo values (?)", undef, $x{foo}); print "got: " . $dbh->selectrow_array("select bar from foo") . "\n"; $dbh->do("drop table foo")'
got: 42

¿Le importaría compartir qué base de datos está utilizando?

Bien, prueba esto:

use CGI;
my %in;
CGI::ReadParse(\%in);

Eso podría ayudar, ya que en realidad está usando una variable que usted ha declarado y, por lo tanto, puede controlar el alcance de (además, le permitirá use strict sin otras porquerías que puedan estar enturbiando las aguas)

Como esto está empezando a parecer un tie() problema, intente el siguiente experimento.Guarde esto como foo.pl y ejecútelo como perl foo.pl "x=1"

use CGI;

CGI::ReadParse();
p($in{x}, "$in{x}");

sub p { my @a = @_; print "@a\n" }

debería imprimir 1 1.Si no es así, hemos encontrado al culpable.

Acabo de probar tu código de prueba de http://www.carcomplaints.com/test/test.pl.txt, y funciona de inmediato en mi computadora, sin problemas.Obtengo tres valores como se esperaba.No lo ejecuté como CGI, sino usando:

...
use CGI qw/-debug/;
...

Escribo una variable en la consola (test=test) y sus scripts se insertan sin problemas.

Sin embargo, si omite esto, tt insertará una cadena vacía y dos NULL.Esto se debe a que interpolas un valor en una cadena.Esto creará una cadena con un valor de $in{test} cual es undef en este momento. undef stringifica a una cadena vacía, que es lo que se inserta en la base de datos.

Prueba esto

%en = ReadParse();

pero lo dudo.¿Estás intentando obtener parámetros de consulta o algo así?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top