sqlserver activar php pdo odbc teradata

activar - php pdo sql



PDO devuelve el nombre de propiedad vacío (2)

Tengo un problema extraño con pdo_odbc y PDO :: FETCH_OBJ (y PDO :: FETCH_CLASS) que da como resultado el siguiente mensaje de error:

PHP Fatal error: Cannot access empty property

Aquí está el código:

$dbh = new PDO("odbc:FOO"); $sth = $dbh->query(" SELECT rolename FROM dbc.allrolerights WHERE databasename = ''BAR'' "); $result = $sth->fetch(PDO::FETCH_OBJ);

El DSN de FOO, como referencia, es un origen de datos de Teradata que utiliza el controlador tdata.so, provisto por el paquete tdodbc.

Creo que esto está sucediendo porque el nombre de campo (como se devuelve de la consulta ODBC) está en blanco cuando PDO llama a zend_API.h: object_init_ex () para crear una instancia del objeto stdClass. Si cambio a PDO :: FETCH_LAZY y var_dump () la fila, obtengo lo siguiente:

object(PDORow)#3 (2) { ["queryString"]=> string(95) " SELECT rolename FROM dbc.allrolerights WHERE databasename = ''BAR'' " [""]=> string(30) "FNAR " }

Lo cual parece respaldarlo. He intentado varias combinaciones de atributos PDO diferentes y un montón de ángulos diferentes para evitar el problema. Una solución es buscar una matriz asociativa y pasarla al constructor de la clase. Sin embargo, esto no funciona para ciertos marcos y ORM que usan PDO :: FETCH_CLASS directamente, detrás de las escenas.

Quiero agregar que otros métodos de búsqueda parecen hacer lo correcto, por ejemplo, PDO :: FETCH_NAMED:

array(1) { ["RoleName"]=> string(30) "FNAR " }

Estoy buscando algo que pueda poner en la definición de dbh o sth de PDO, o en el odbc.ini u odbcinst.ini para el origen de datos o el controlador, para resolver este problema. Gracias de antemano.

Actualización: odbc_fetch_object () (es decir, no PDO) funciona muy bien con el mismo todo exacto. Solo quería mencionarlo. Claramente, no parece haber problemas serios con PHP, unixODBC o el controlador ODBC. Es algo en el código PDO. Es hora de abrir un informe de error ... opened

$dbh = odbc_connect("FOO", NULL, NULL) or die(odbc_error_msg()); $sth = odbc_exec($dbh, " SELECT rolename FROM dbc.allrolerights WHERE databasename = ''BAR'' "); $result = odbc_fetch_object($sth); var_dump($result);

Y el resultado:

object(stdClass)#1 (1) { ["RoleName"]=> string(30) "FNAR " }

Actualización 2: La situación continúa creciendo más y más extraña. Puedo hacer un PDO :: FETCH_LAZY y ver el nombre de la columna en blanco como se ve en var_dump () arriba, pero si trato de acceder a la propiedad por su nombre (ej. $ Result-> RoleName), ¡funciona! ¿Qué hacen estos métodos de búsqueda de forma tan diferente que algunos de ellos a veces pueden acceder a los nombres de campo y otros no?

Las comparaciones lado a lado de las trazas ODBC ("trabajo", "no funciona") no muestran diferencias (a excepción de las diferentes direcciones de puntero). PDO :: FETCH_BOUND funciona con columnas numeradas y con nombre. PDO :: FETCH_INTO un objeto con una propiedad RoleName no lo hace.


Creo que una "solución" ahora sería utilizar el estilo fetch PDO :: FETCH_NAMED y luego convertir el conjunto devuelto y poblar la clase dinámica:

function arrayToObject(array $array){ $obj = new stdClass(); foreach($array as $k => $v) $obj->$k = $v; return $obj; }


Tu pregunta describe dos problemas:

  1. ¿Por qué los objetos no se pueden crear con propiedades que tengan nombres de cadenas vacías cuando se usa PDO::FETCH_OBJ , pero aparentemente pueden usarse otros métodos?

    Como se documenta en Estructuras internas e implementación en el Libro de PHP Internals, las " properties dinámicas " (es decir, las variables miembro de un objeto que no están declaradas en su definición de clase, sino que se crean en tiempo de ejecución) se implementan como una tabla hash.

    Si uno desea llenar un objeto estándar recién instanciado con un conjunto de propiedades que actualmente se mantienen en una tabla hash, simplemente puede apuntar la variable de properties del objeto a esa tabla hash existente: la función object_and_properties_init() PHP, que es llamada por odbc_fetch_object() , hace exactamente eso sin realizar ninguna comprobación de cordura en las teclas de la tabla . En consecuencia, uno puede instanciar un objeto con nombres de propiedad extraños (como la cadena vacía).

    Por otro lado, si uno ya tiene un objeto instanciado y necesita establecer un valor de propiedad (conservando otros que ya existen), uno debe copiar ese valor en la tabla hash del objeto: el método zend_std_write_property() PHP, que maneja esta acción para objetos estándar, hace exactamente eso después de haber realizado primero un control de cordura en el nombre de la propiedad . En consecuencia, no se puede agregar una propiedad con un nombre extraño (como la cadena vacía) a un objeto existente.

    Esta discrepancia en la comprobación de la cordura entre los dos enfoques parece, en mi opinión, ser un error: cualquier restricción en los nombres de propiedades dinámicas debe aplicarse independientemente del método por el cual se crean tales propiedades. Si se deben permitir nombres extraños de este tipo (y, por lo tanto, la verificación de la cordura se debe eliminar del último método), o no (y por lo tanto, se debe agregar alguna comprobación de cordura al método anterior), es una decisión que dejaré al Desarrolladores PHP

    ¿Cómo encaja PDO en todo esto?

    PDOStatement::fetch() prepara primero el destino en el que se almacenarán los resultados y luego itera sobre las columnas que almacenan cada campo: imagino que hace esto para simplificar la base de código, ya que cada estilo de búsqueda puede implementarse dentro del mismo estructura. Sin embargo, esto significa que cuando se llama utilizando el estilo PDO::FETCH_OBJ (y también tanto PDO::FETCH_CLASS como PDO::FETCH_INTO , como ha observado), un objeto se instancia primero y sus propiedades se completan posteriormente . En consecuencia, los nombres de propiedad extraños (como la cadena vacía) dan como resultado la falla observada.

    Los otros estilos de búsqueda que ha probado no experimentan el mismo problema porque:

    • PDO::FETCH_BOUND en las variables que fueron especificadas por una llamada previa a PDOStatement::bindColumn() , por lo que PHP nunca intenta escribir en una propiedad que tenga un nombre vacío;

    • PDO::FETCH_LAZY omite todo el shebang y hace cosas similares a odbc_fetch_object() arriba.

    De forma similar, los estilos de búsqueda basados ​​en arrays no sufrirán problemas similares porque las claves de cadena vacía son perfectamente válidas en esas tablas hash.

  2. ¿Por qué es que PDO piensa que los nombres de columna en este conjunto de registros ODBC son cadenas vacías?

    La respuesta a esto es mucho menos obvia para mí.

    Vimos anteriormente que, para poblar propiedades, PDO utiliza stmt->columns[i].name como el nombre de la propiedad. Esto debería haberse llenado correctamente en un punto anterior , cuando se llamó a pdo_stmt_describe_columns() . Esta función, a su vez, había llamado al método describer del controlador para cada columna en el conjunto de resultados: en el caso de PDO_ODBC, eso es odbc_stmt_describe() que sí asigna un valor a ese campo .

    Por lo tanto, todo se ve bien en el lado de PHP. Sería interesante saber si la llamada a la función SQLDescribeCol() del controlador SQLDescribeCol() correctamente el nombre de columna en el búfer proporcionado como su tercer argumento: uno no imagina, lo que sugeriría que el problema radica en el controlador ODBC mismo. Usted mencionó que está usando Teradata: ¿pero está seguro de que está utilizando el mismo controlador para PDO_ODBC (que no funciona) y ext / odbc (que es)?

    En particular, documento de Teradata en Funciones de nivel de extensión :

    De forma predeterminada, SQLDescribeCol y SQLColAttribute devuelven el nombre de la columna en lugar del título de la columna de Teradata. Si una aplicación desea que el controlador ODBC para Teradata devuelva el título de la columna en lugar del nombre real de la columna, la opción Usar nombres de columna en el cuadro de diálogo Opciones del controlador ODBC de Teradata no debe seleccionarse para el DSN utilizado o establecer DontUseTitles = No en el Sistema operativo UNIX.

    Devolver el título de la columna en lugar del nombre real de la columna puede causar problemas para ciertas aplicaciones, como Crystal Reports, porque esperan obtener el nombre de la columna y no el título de la columna.