<html>
<head>
   <title>Contas bancarias</title>
</head>

<?php
    include 'db.inc';
    include 'error.inc';

    /* executa um comando sql */
    function db_execute($sql)
    {
      global $db;
      return pg_query($db,$sql);
    }

    /* lista todas as contas */
    function db_lista_contas()
    {
      $sql = "SELECT * FROM conta ORDER BY numero";
      $result = db_execute($sql);
      $nrows = pg_numrows($result);

      printf("<pre>\n");
      printf("<b>numero     nome      saldo</b>\n");
      for($i=0; $i<$nrows; $i++)
      {
         $tuple = pg_fetch_array($result,$i); 
         printf("%s %10s %10s\n", 
                 $tuple['numero'], $tuple['nome'], $tuple['saldo']);
      }
      printf("</pre>\n");
    } 

    /* retorna o saldo da conta $numconta */
    function db_saldo( $numconta ) 
    {
      $sql = "SELECT saldo FROM conta WHERE numero=$numconta";
      $result = db_execute($sql);
      return pg_result($result,0,0);
    }

    /* retorna o saldo da conta $numconta e faz um 'lock' à linha */
    function db_saldo_for_update( $numconta ) 
    {
      $sql = "SELECT saldo FROM conta WHERE numero=$numconta FOR UPDATE";
      $result = db_execute($sql);
      return pg_result($result,0,0);
    }

    /* retorna true se $numconta existe. retorna false caso contrário */
    function db_existe_conta( $numconta ) 
    {
      $sql = "SELECT saldo FROM conta WHERE numero=$numconta";
      $result = db_execute($sql);
      $nrows = pg_numrows($result);
      if( $nrows < 1 )
        return false;
      else
        return true;
    }

    /* transfere $quantidade da $conta1 para $conta2.
       retorna true se a operação tiver sucesso.
       retorna false caso contrario. 
    */
    function db_transfere($conta1,$conta2,$quantidade)
    {
      /* começa a transacção */
      db_execute("BEGIN WORK");
      /* verifica se existe dinheiro suficiente na conta 1 */
      $saldo = db_saldo_for_update($conta1);
      if( $saldo >= $quantidade ) {
         /* transfere o dinheiro */
         db_execute("UPDATE conta SET saldo=saldo+$quantidade 
                   WHERE numero=$conta2");
         sleep(5);  // so para poder testar a concorrencia...
         db_execute("UPDATE conta SET saldo=saldo-$quantidade 
                   WHERE numero=$conta1");
       db_execute("COMMIT WORK");
         return true;
      }
      else {
         db_execute("ROLLBACK WORK");
         return false;
      }
    }
?>


<h1>Tabela 'conta'</h1>

<?php
    $db = dbconnect($connection_string);  

    $numConta1 = $_POST["numConta1"]; 
    $numConta2 = $_POST["numConta2"]; 
    $quantidade = $_POST["quantidade"]; 

    if( isset($numConta1) && isset($numConta2) && isset($quantidade)) {
      // verifica que $quantidade nao e' negativo
      if($quantidade<0) 
	printf("<p>ERRO: quantidade negativa!</p>\n");
      // verifica que as contas existem
      if(!db_existe_conta($numConta1))
	printf("<p>ERRO: Conta $numConta1 nao existe!</p>\n");
      if(!db_existe_conta($numConta2)) 
	printf("<p>ERRO: Conta $numConta2 nao existe!</p>\n");
      // efectua a transaccao 
      if( db_transfere($numConta1,$numConta2,$quantidade) )
         printf("<p>Foi transferido %d da conta %d para a conta %d</p>\n",
                 $quantidade, $numConta1, $numConta2);
      else 
         printf("<p>Saldo insuficiente na conta $numConta1!</p>\n");
    }
    db_lista_contas();
?>

<hr>

<h1>Transferencia de dinheiro</h1>
<form action="<?php echo $PHP_SELF; ?>" method="post">
<table border=0>
  <tr>
     <td align=right>Numero da conta 1:</td>
     <td align=left><input type="text" name="numConta1" size="15"></td>
  </tr>
  <tr>
     <td align=right>Numero da conta 2:</td>
     <td align=left><input type="text" name="numConta2" size="15"></td>
  </tr>
  <tr>
     <td align=right>Quantidade:</td>
     <td align=left><input type="text" name="quantidade" size="15"></td>
  </tr>
  <tr>
     <td align=left><input type="submit" value="transferir"></td>
  </tr>
</table>
</form>  

<?php
    pg_close($db);
?>

</body>
</html>