# Funciones de acceso a las tablas en el Mysql.

# Incluimos las librerias de Perl para DBI.

use DBI;

######################################################
# Definiciones.
#
# Deben definirse en el módulo que llama a éste (BD.pl), diferentes cadenas
# denominadas xxxx_defecto, con la forma:
#
# $xxx_defecto="cadena1=''&entero1=0&real1=0.0&cadena2=''&entero2=0&real2=0.0"
#
# ya que este módulo lo necesita y, por generalidad, no se incluye aquí.

$database = "orche1";
$driver = "mysql";
$port = 3306;
$hostname = "orchestra.es";
$DBuser = "orche1";
$DBpassword = "nfnc+nlbhf";

$dsn = "DBI:$driver:database=$database;host=$hostname;port=$port";

########################################################
#
# NuevoRegistro
#
# Inserta (INSERT) un registro en una tabla.
#
# Como primer parámetro el nombre de la tabla. El segundo parámetro es un
# hash que asocia nombres de campos a sus valores, de la siguiente forma:
#
#       campo=valor&campo=valor&...&campo=valor
#

sub NuevoRegistro
{
	local($tablaDB, %datos) = @_;

# Lo primero que hacemos es conectarnos a nuestra base de datos.

   $dbh = DBI->connect($dsn, $DBuser, $DBpassword);

   $consulta = "INSERT INTO ".$tablaDB." VALUES (";

   $primero="1";
   $defecto = $tablaDB."_defecto";
   @pairs = split(/&/, ${$defecto});

   foreach $pair (@pairs) {
      ($name, $value) = split(/=/, $pair);
      if ($datos{$name}) {
         # Hay que comprobar si el campo es alfanumérico, porque, si es 
         # así, hay que encerrar el valor entre comillas simples.
         if ($value eq "''") {
            $value = "'".$datos{$name}."'";
         } else {
            $value = $datos{$name};
         }
      }
      if ($primero eq "0") {
         $consulta = $consulta.", ";
      }
      $primero="0";
      $consulta = $consulta.$value;
   }

   $consulta=$consulta.")";

   if ($debug eq 1) {print "BD.pl::NuevoRegistro: Consulta: ".$consulta."<br>";}

   $sth = $dbh->prepare($consulta);
   $sth->execute();

   # Devolvemos el resultado, para que la funci¢n llamante sepa qu‚ ha pasado.
   return $sth;
}


########################################################
#
# ModificarRegistro
#
# Modifica (UPDATE) un registro de una tabla.
#
# Como primer parámetro el nombre de la tabla. El segundo parámetro es un
# hash que asocia nombres de campos a sus valores, de la siguiente forma:
#
#       campo=valor&campo=valor&...&campo=valor
#
# Si el nombre del campo viene precedido por WHERE_, significa que ese campo va
# a entrar dentro de la cláusula WHERE. Lo he tenido que hacer así al final, 
# porque el Perl junta en una sola variable los distintos hashs que se le pasan
# como parámetros, y no se consiguen distinguir.
#

sub ModificarRegistro
{
        local($tablaDB, %datos) = @_;

# Lo primero que hacemos es conectarnos a nuestra base de datos.

   $dbh = DBI->connect($dsn, $DBuser, $DBpassword);

   $consulta = "UPDATE ".$tablaDB." SET ";
   $elwhere = " WHERE ";

   $primero="1";
   $priwhere="1";
   $defecto = $tablaDB."_defecto";
   @pairs = split(/&/, ${$defecto});

   foreach $pair (@pairs) {
      ($name, $value) = split(/=/, $pair);
      # Esta es la parte de fijar los nuevos valores.
      if ($datos{$name}) {
         # Hay que comprobar si el campo es alfanumérico, porque, si es 
         # así, hay que encerrar el valor entre comillas simples.
         if ($value eq "''") {
            $value = "'".$datos{$name}."'";
         } else {
            $value = $datos{$name};
         }
         if ($primero eq "0") {
            $consulta = $consulta.", ";
         }
         $primero="0";
         $consulta = $consulta.$name."=".$value;
      }
      # Esta es la parte de la cl usula WHERE.
      if ($datos{"WHERE_".$name}) {
         # Hay que comprobar si el campo es alfanumérico, porque, si es 
         # así, hay que encerrar el valor entre comillas simples.
         if ($value =~ /'$/) {
            $value = "'".$datos{"WHERE_".$name}."'";
         } else {
            $value = $datos{"WHERE_".$name};
         }
         if ($priwhere eq "0") {
            $elwhere = $elwhere."AND ";
         }
         $priwhere="0";
         $elwhere = $elwhere.$name."=".$value;
      }
   }

   $consulta=$consulta.$elwhere;

   if ($debug eq 1) {print "BD.pl::ModificarRegistro: Consulta: ".$consulta."<br>";}

   $sth = $dbh->prepare($consulta);
   $sth->execute();

   # Devolvemos el resultado, para que la funci¢n llamante sepa qu‚ ha pasado.
   return $sth;
}

########################################################
#
# ActualizarTabla
#
# Funci¢n que comprueba si existe un registro que cumpla la parte de WHERE_,
# si es así lo actualiza y, sino, lo crea nuevo. Aunque lo más lógico parece
# intentar actualizarlo y, sólo si falla, crearlo, como con el Msql.pm no puedo
# distinguir cuándo falla un UPDATE (siempre devuelve -1), tengo que hacerlo
# así. Llama a las funciones ConsultarTabla, NuevoRegistro y ModificarRegistro.
#
# Como primer parámetro el nombre de la tabla. El segundo parámetro es un hash 
# que asocia nombres de campos a sus valores, de la siguiente forma:
#
#       campo=valor&campo=valor&...&campo=valor
#
# Si el nombre del campo viene precedido por WHERE_, significa que ese campo va
# a entrar dentro de la cláusula WHERE. Lo he tenido que hacer así al final, 
# porque el Perl junta en una sola variable los distintos hashs que se le pasan
# como parámetros, y no se consiguen distinguir.
#
# Para que esta función sepa que se está intentando formar una cláusula WHERE,
# hay que definir en el hash el elemento $datos{WHERE_}.
#

sub ActualizarTabla
{
   local($tablaDB, %datos) = @_;
   local ($tmp, %datos_tmp, @array_tmp);

   # A ver si nos pasan un filtro, con lo que intentamos actualizar un registro.
   if ($datos{WHERE_}) {
      # A ver si tenemos un registro que cumpla el filtro.
      # Lo primero, sacamos el filtro de todo el hash que hemos recibido, en el
      # que está mezclado parte de filtro y parte de datos.
      foreach $key (keys %datos) {
         if ($key =~ /WHERE_(.*)/) {
            $datos_tmp{$1} = $datos{$key};
         }
      }

      @array_tmp = &ConsultarTabla ($tablaDB, %datos_tmp);

      # Si al hacer la consulta, devuelve un registro, tenemos que hacer una
      # actualización.
      if ($array_tmp[0]) {
         $tmp = &ModificarRegistro ($tablaDB, %datos);
         return $tmp;
      } else {
         # Para que la función NuevoRegistro no se haga un lío con los
         # campos WHERE_, indefinimos WHERE_, y pasamos los WHERE_x a x.
         undef ($datos{WHERE_});
         foreach $key (keys %datos) {
            if ($key =~ /WHERE_(.*)/) {
               $datos{$1} = $datos{$key};
               undef ($datos{$key});
            }
         }
         $tmp = &NuevoRegistro ($tablaDB, %datos);
         return $tmp;
      }
   } else {
      # Si no nos han pasado un filtro, vamos a intentar crear el registro.
      $tmp = &NuevoRegistro ($tablaDB, %datos);
      return $tmp;
   }
}


###########################################################
#
# ConsultarTabla
#
# Esta función espera un hash, en el que las claves son los nombres de los
# campos y su valor el valor de los campos por los que se desea filtrar. Se
# devuelve un array en el que cada elemento es una línea con la forma:
#
#	campo1=valor1|campo2=valor2|...|campon=valorn
#

sub ConsultarTabla {
	local($tablaDB, %el_filtro) = @_;
	local(@los_datos, $ref) = ();

# Nos conectamos a la base de datos.

   $dbh = DBI->connect($dsn, $DBuser, $DBpassword);

   $consulta = "SELECT * FROM ".$tablaDB;

   $primero="1";
   $defecto = $tablaDB."_defecto";
   @pairs = split(/&/, ${$defecto});
   foreach $pair (@pairs) {
      ($name, $value) = split(/=/, $pair);

      if ($el_filtro{$name}) {
         if ($primero eq "0") {
            $consulta=$consulta." AND ";
         } else {
            $consulta=$consulta." WHERE ";
         }
         $primero="0";

         # Si en el filtro viene el operador de comparaci¢n para este campo,
         # lo usamos; sino, suponemos que es '='.
         $opComp = "=";
         $str_opComp = $name."_opComp";
         if ($el_filtro{$str_opComp}) {
            $opComp = $el_filtro{$str_opComp}
         }

         # Hay que comprobar si el campo es alfanumérico, porque, si es 
         # así, hay que encerrar el valor entre comillas simples.
         if ($value eq "''") {
            $consulta=$consulta.$name.$opComp."'".$el_filtro{$name}."'";
         } else {
            $consulta=$consulta.$name.$opComp.$el_filtro{$name};
         }
      }
   }

   if ($debug eq 1) {print "BD.pl::ConsultarTabla: Consulta: ".$consulta."<br>";}

   $sth = $dbh->prepare($consulta);
   $sth->execute();

   # Si la consulta anterior no encontró ningún registro, $sth queda
   # indefinido.
   if ($sth) {
      $ref = $sth->fetchrow_hashref();
      $fila = 0;

      while ($ref) {
         # Nos recorremos todos los valores por defecto, para sacar los nombres de
         # los campos, y sacamos del resultado de la consulta los valores.

         $cuenta=0;
         @pairs = split(/&/, ${$defecto});
         foreach $pair (@pairs) {
            if ($cuenta!=0) {
               $los_datos[$fila].="|";
            }

            ($name, $value) = split(/=/, $pair);
            $los_datos[$fila].=$name."=".$ref->{$name};
            $cuenta++;
         }
         if ($debug eq 1) {print "BD.pl::ConsultarTabla: Respuesta: ".$los_datos[$fila]."<br>";}
         $fila++;
         $ref = $sth->fetchrow_hashref();
      }
   }

   return @los_datos;
}


###########################################################
#
# EliminarRegistro
#
# Esta función espera un hash, en el que las claves son los nombres de los
# campos y su valor el valor de los campos por los que se desea filtrar. La
# función elimina de la tabla indicada todos los registros que pasan el filtro.
#

sub EliminarRegistro {
	local($tablaDB, %el_filtro) = @_;

# Nos conectamos a la base de datos.

   $dbh = DBI->connect($dsn, $DBuser, $DBpassword);

   $consulta = "DELETE FROM ".$tablaDB;

   $primero="1";
   $defecto = $tablaDB."_defecto";
   @pairs = split(/&/, ${$defecto});
   foreach $pair (@pairs) {
      ($name, $value) = split(/=/, $pair);

      if ($el_filtro{$name}) {
         if ($primero eq "0") {
            $consulta=$consulta." AND ";
         } else {
            $consulta=$consulta." WHERE ";
         }
         $primero="0";

         # Si en el filtro viene el operador de comparaci¢n para este campo,
         # lo usamos; sino, suponemos que es '='.
         $opComp = "=";
         $str_opComp = $name."_opComp";
         if ($el_filtro{$str_opComp}) {
            $opComp = $el_filtro{$str_opComp}
         }

         # Hay que comprobar si el campo es alfanumérico, porque, si es 
         # así, hay que encerrar el valor entre comillas simples.
         if ($value eq "''") {
            $consulta = $consulta.$name.$opComp."'".$el_filtro{$name}."'";
         } else {
            $consulta=$consulta.$name.$opComp.$el_filtro{$name};
         }
      }
   }

   if ($debug eq 1) {print "BD.pl::EliminarRegistro: Consulta: ".$consulta."<br>";}

   $sth = $dbh->prepare($consulta);
   $sth->execute();

   return;
}

1;
