martes, 19 de enero de 2010

PHP y PostgreSQL: Metadatos de una consulta SQL

En la ejecución de una consulta SQL, normalmente se recorren, una a una, las filas (registros o tuplas) obtenidas, y se accede a las columnas (campos) necesarios para obtener un valor concreto. La gestión de estos accesos permiten extraer los datos necesarios para pintarlos en una interfaz, o generar una nueva masa de datos que almacenamos en una nueva tabla, en un servicio Web o en un fichero (por citar sólo algunas aplicaciones comunes).

Pero el resultado de una consulta da muchas más información, y así podemos acceder a información interna de la estructura del resultado: número de registros, número de campos, nombre de campo, tipo de datos, si es nulo, longitud del valor o tamaño del valor, entre otros. A la información de estructura comúnmente se la conoce como metadatos.

Para conocer qué funciones más comunes de PHP obtienen dicha información y cómo funcionan, lo mejor será plantear un código de ejemplo:

<html>
<head>
<title>PHP & PostgreSQL: Metatadatos</title>
</head>
<body>
<?php
  $pfields=$_GET["fields"];
  $ptables=$_GET["tables"];
  
  $dbhost='localhost';
  $dbport='5432';
  $dbname='trazalogic';
  $dbusr='trazalogic';
  $dbpasw='trzlgc';
  $dbcon="host=".$dbhost." port=".$dbport.
   " dbname=".$dbname." user=".$dbusr." password=".$dbpasw;
  
  echo "Cadena de conexion: ".$dbcon."<br>";
  
  $con = pg_pconnect($dbcon);
  
  if (!$con)
    echo 'Se produjo un error al intentar conectar con la base de datos';
  else {
    $qry="SELECT ".$pfields." FROM ".$ptables;
    echo "qry= ".$qry."<br>";

    $result = pg_query($con, $qry);
    $numfields = pg_num_fields($result);
    $reg=0;
    echo "Num filas= ".pg_num_rows($result)."<br>";
    echo "Num campos=".$numfields."<br>";
  
    while ($tuple=pg_fetch_row($result)) {
      echo "<br>Reg num: ".$reg."<br>";
      for ($i=0;$i<$numfields;$i++) {
        echo "#".$i." - ";
        echo "Nombre= ".pg_field_name($result,$i)." - ";
        echo "Valor= ".$tuple[$i]." - ";
        echo "Longitud= ".pg_fieldprtlen($result,pg_field_name($result,$i))." - ";
        echo "Tamaño= ".pg_field_size($result,$i)." - ";
        echo "Tipo= ".pg_field_type($result,$i)."<br>";
      }
      $reg++;
    }
    pg_close($con);
  }

?>
</body>
</html>

Al comenzar la ejecución de este código, las variables "pfields" y "ptables" recogen los parámetros ("fields" y "tables" respectivamente) pasados mediante la URL. Ambos parámetros formarán parte de la consulta a realizar a la base de datos.

A continuación se definen las variables (dbhost, dbport, dbname, dbusr y dbpass) para formar la cadena de conexión (dbcon) a la base de datos. Después, se realiza la conexión a la base de datos (pg_pconnect), y se almacena la misma en el objeto "con".

Una vez obtenida la conexión, se componen la sentencia SQL (variable qry) con la consulta a realizar.

El siguiente paso es ejecutar la consulta, almacenando el resultado en el objeto "result", utilizando la función pg_query. Tras ésto, se accede a diversos metadatos del resultado mediante las siguientes funciones:

- pg_num_fields: Retorna el número de campos retornados por la consulta
- pg_num_rows: Retorna el número de filas retornadas por la consulta

A continuación se recorren todas la filas mediante un bucle while, el cual recupera la siguiente fila mediante la función pg_fetch_row y la almacena en el objeto "tuple", en forma de array (cada elemento del array almacenará el valor de cada uno de los campos de la fila), y se repetirá hasta que no queden filas en el resultado (valor FALSE).

A medida que se recorre cada fila, otro bucle interno (bucle for) recorrerá uno a uno los campos de la fila actual, mostrando otros metadatos que son obtenidos por las siguientes funciones:
- pg_field_name: Nombre del campo
- pg_field_ptrlen: Longitud del valor impreso del campo (tal como se visualiza)
- pg_field_size: Tamaño del campo (tamaño interno, limitado por su tipo)
- pg_field_type Tipo de dato del campo

Una vez finalizado, se libera la conexión mediante la función pg_close.

El resultado final sería similar al siguiente:



Safe Creative #1001195345951