2011-12-21 5 views
10

He aprendido que no siempre odbc_execute() desencadenar un error de ODBC adecuado cuando vuelve FALSE (no al menos con el conductor de Oracle) y no puedo confiar plenamente odbc_error() o odbc_errormsg(). Esta situación es fácil de detectar cuando no había un error anterior porque odbc_error() devuelve una cadena vacía. Sin embargo, cuando devuelve algo, no sé si pertenece a la última operación fallida o es un remanente de un error anterior.truco para restablecer odbc_error()

La solución más sencilla sería la de restablecer la odbc_error()odbc_errormsg() y funciones cuando hay un error tan próximos llamadas comenzarían a partir de cero, pero no pude encontrar una forma compatible de hacerlo. ¿Puedes encontrar una manera de hacerlo?

Antecedentes: estoy mejorando una aplicación heredada con una clase que encapsula las llamadas a la base de datos. Es por eso que necesito hacer todo lo más genérico posible.

Respuesta

1

odbc_error a veces se vuelve confuso. la cadena sql ejecutada y el mensaje de error pueden ser diferentes. Para evitar esto, podemos mantener todos los sqls ejecutados en una matriz, y después de que finalice la ejecución, podemos verificar cuáles son los mensajes de error.

En primer lugar vamos a definir una clase executedSQL que ejercerá la información sqls ejecutada:

class executedSQL 
{ 
    public sql; 
    public result; 
    public error; 
    public message; 
} 

Esta clase tendrá toda la información de SQL y su resultado y regresado mensajes.

Si usamos una clase para conectar la base de datos ODBC:

class myODBC 
{ 
    //holds the connection 
    public $connection; 

    //all executed sql string are added to this array as executedSQL object. 
    public $executedSQLs = array(); 


    public function connect() 
    { 
     $this->connection = dbc_connect(" ", " ","") or die(odbc_errormsg()); 
    } 

    public function execute($sql) 
    { 
     $execution = odbc_exec($this->connection, $sql); //execute it 

     //put all the results to executedSQL object 
     $executed = new executedSQL(); 
     $executed->sql = $sql; 
     $executed->result = $execution; 
     $executed->error = odbc_error(); 
     $executed->message = odbc_errormsg(); 

     //push to executedSQLs var. 
     array_push($this->executedSQLs, $executed); 

     return $execution; 
    } 
} 

Si ejecutamos nuestros sqls:

$db = new myODBC(); 

$db->connect(); 

$db->execute("select * from table1"); 
$db->execute("this is gonna be failed sql"); 
$db->execute("select * from table2"); 

print_r($db->executedSQLs); 

Esto va a imprimir todos los sqls y sus resultados. En este punto, podemos ver el sql ejecutado y su mensaje de error relacionado. Así que, literalmente, no estamos restableciendo odbc_error, pero lo dejamos más claro. Si un mensaje de error se repite dos veces, es más probable que pertenezca a sql ejecutado previamente. De esta manera la depuración se vuelve más fácil.

+0

Gracias por la respuesta. Sin embargo, su respuesta solo está bien para el caso de que uno necesite los mensajes de error solo para depuración. En una aplicación del mundo real, uno debería poder confiar en los mensajes de error para tomar decisiones (comportamiento diferente según el error, o traducir el mensaje de manera que tenga sentido para el usuario final). Esta es la razón por la cual necesitaba una respuesta completa y ofrecí una recompensa. –

+0

El error de la plataforma raíz de la pregunta es que 'odbc_errormsg()' puede devolver felizmente el mensaje de una declaración anterior. El problema no es detectar si su consulta tiene éxito (eso es fácil), el problema es asegurarse de que el mensaje de error no pertenezca a una consulta previa.A menos que me falta algo, su código no hace nada para resolver eso. –

+0

En este enfoque, podemos detectar si un mensaje de error de una declaración anterior o no. Por ejemplo, digamos que estamos ejecutando tres consultas. El primero es exitoso, el segundo falla y devuelve "mensaje de falla 1". Y el tercero tampoco devuelve el "mensaje de error 1". Con este enfoque, podemos aprender que "mensaje de error 1" pertenece a la consulta 2. – isa

2

no es NECESARIO para restablecer la función He resuelto de esta manera:

function foo($sql){ 
    $res = odbc_exec($this->dbconn, $sql); 
    if (odbc_error() and $res===false) { 
     return $this->catchException(odbc_errormsg($this->dbconn)); 

    } 
    return $res; 
} 
+0

Si decide detectar la excepción e ignorar el error (por ejemplo, porque es una clave duplicada que su lógica de código puede manejar), su mensaje de error podría terminar asociado a los siguientes errores. Eso es contra lo que quiero protegerme. –

+0

¿Qué hace '$ this-> catchException()' hacer? –

+0

función pública catchException ($ odbc_errormsg) { // echo "Funciona en catch
"; $ patron_error = "/ SQL \ d + /"; if (preg_match ($ patron_error, $ odbc_errormsg, $ coincidencias)) { throw new Exception ($ coincidencias [0]. ";". $ Odbc_errormsg); } } Por ahora, solo es útil con los mensajes de error de DB2. Espero encontrar una manera de gestionar los errores de otras bases de datos con el controlador php odbc – vteran93

0

errores odbc_errormsg no pueden ponerse a cero durante la escritura. Entonces, en realidad, una manera fácil de separar los errores odbc_errormsg es asignarle a cada obdc_connect un identificador único. Los ejemplos muestran $ db = @ odbc_connect ($ somefile, ......) pero usando nombres aleatorios o únicos => $ db900 = @ odbc_connect ($ somefile, ......) o $ myuniquename = @ odbc_connect ($ somefile, ......) separará los mensajes de error. Entonces usar odbc_errormsg ($ myuniquename) solo devolverá el error para esa identificación.