Visualizzazione dei risultati da 1 a 5 su 5
  1. #1
    Utente di HTML.it L'avatar di strae
    Registrato dal
    Apr 2008
    Messaggi
    407

    Postgresql - PHP: problema con transazioni e prepared statement

    Ciao ragazzi, sono alle prime armi con postgresql e con i PDO...
    Premesso questo, mi sono 'arenato' facendo qualche prova con delle prepared statement all'interno delle transazioni.

    Per le mie prove, ho creato un ambiente così:

    5 tabelle: customer, p_orders, p_items, h_orders, h_items.

    Le tabelle h_* sono gemelle di p_orders e p_items (fatta eccezione per le sequenze sugli indici), perchè le tabelle h_* sono lo storico delle tabelle p_* (quando queste raggiungono X righe, sposto tutte le righe nelle tabelle 'storico')

    Quindi, la mia prima prova è creare una transazione che sposta 50 righe dalle tabelle p_* alle tabelle h_*:

    1. Inizio la transazione
    2. Copio il dato da p_* a h_*
    3. Lo elimino da p_*
    4. Se anche solo 1 oggetto o un ordine ha dato errore, faccio il rollback
    5. stampo a video 'finito'
    6. Commit.

    E il codice che ho scritto è (scusate i commenti in inglese ma cerco di abituarmi a scrivere il codice in inglese):
    Codice PHP:
    <?php
    $dbh 
    = new PDO('pgsql:host=127.0.0.1;dbname=test''myuser''xxxx');

    $rollback false;

    $dbh->beginTransaction();

    //create the prepared statements
    $insert_order $dbh->prepare('INSERT INTO h_orders (id, id_customer, date, code) VALUES (?, ?, ?, ?)');
    $insert_items $dbh->prepare('INSERT INTO h_items (id, id_order, descr, price) VALUES (?, ?, ?, ?)');
    $delete_order $dbh->prepare('DELETE FROM p_orders WHERE id = ?');

    //move the orders from p_orders to h_orders (history)
    $qeOrders $dbh->query("SELECT id, id_customer, date, code FROM p_orders LIMIT 1");
    while(
    $rayOrder $qeOrders->fetch(PDO::FETCH_ASSOC)){
        
    //h_orders already contain a row with id 293
        //lets make the query fail
        
    $insert_order->execute(array('293'$rayOrder['id_customer'], $rayOrder['date'], $rayOrder['code']));
        
    //this is the real execute
        //$insert_order->execute(array($rayOrder['id'], $rayOrder['id_customer'], $rayOrder['date'], $rayOrder['code']));
        //for each order, i move the items too
        
    $qeItems $dbh->query("SELECT id, id_order, descr, price FROM p_items WHERE id_order = '" $rayOrder['id'] . "'");
        while(
    $rayItem $qeItems->fetch(PDO::FETCH_ASSOC)){
            
    $insert_items->execute(array($rayItem['id'], $rayItem['id_order'], $rayItem['descr'], $rayItem['price']));
        }
        
    //if everything is ok, delete the order from p_orders
        
    $delete_order->execute(array($rayOrder['id']));
    }
    //in here i'll use a bool var to see if anythings gone wrong and i need to rollback,
    //or all good and commit
    $dbh->rollBack();
    echo 
    'finito';
    $dbh->commit();
    ?>
    Il problema è che, quando faccio fallire la query inserendo un id duplicato (293), viene lanciato un errore (logico), ma mi termina anche la transazione.
    Infatti l'output che mi viene fuori da questa pagina è:
    Fatal error: Call to a member function fetch() on a non-object in /srv/www/test-db/test-db-pgsql-08.php on line 23


    Sbaglio qualcosa?
    You HAVE to assume your visitor is a maniac serial killer, out to destroy your application. And you have to prevent it.
    I can accept failure, everyone fails at something - But I can't accept not trying.

  2. #2
    Utente di HTML.it L'avatar di strae
    Registrato dal
    Apr 2008
    Messaggi
    407
    up?
    credo che la problematica sia anche utilizzando mysql, non solo postgres
    You HAVE to assume your visitor is a maniac serial killer, out to destroy your application. And you have to prevent it.
    I can accept failure, everyone fails at something - But I can't accept not trying.

  3. #3
    Utente di HTML.it L'avatar di Pastore12
    Registrato dal
    Oct 2008
    Messaggi
    1,051
    Io non vedo errori... http://it.php.net/manual/en/pdostatement.fetch.php

    Se esegui le query senza usare le transazioni, funziona tutto?
    "Ethics are to me something private. Whenever you use it as an argument for why somebody_else should do something, you’re no longer being ethical, you’re just being a sanctimonious dick-head"
    Linus Torvalds

  4. #4
    Utente di HTML.it L'avatar di luca200
    Registrato dal
    Apr 2002
    Messaggi
    4,120
    L'errore è che chiami un metodo su una variabile che non è un oggetto. Evidentemente una delle due SELECT non restituisce un oggetto, magari per un errore.
    Controllare l'esito delle istruzioni mysql SAREBBE sempre una buona idea

  5. #5
    Utente di HTML.it L'avatar di strae
    Registrato dal
    Apr 2008
    Messaggi
    407
    Grazie per le risposte, ma ho già trovato la soluzione, il nostro amico PDO non gestisce le transazioni 'nested', e nemmeno i savepoint.
    Googlando un pò ho trovato un'estensione MyPDO che lo fà (ce ne sono perecchie di estensioni chiamate MyPdo, se ritrovo il link lo posto)

    Cmq ho risolto evitando di usare pdo, ma solo i comandi pg_*.. per il codice sopra (che cmq è solo un mio esempio per capire il funzionamento) ho risolto aggiungendo un savepoint prima del ciclo while.

    Codice PHP:
    pg_query("SAVEPOINT inizio");
    while(...){
        
    //qualsiasi query fallisca faccio rollback a inizio
        
    pg_query("ROLLBACK TO inizio");
    }
    //prima si controlla che la transazione sia ancora attiva
    pg_query("COMMIT"); 
    L'errore è che chiami un metodo su una variabile che non è un oggetto. Evidentemente una delle due SELECT non restituisce un oggetto, magari per un errore.
    Controllare l'esito delle istruzioni mysql SAREBBE sempre una buona idea
    Si ma infatti quello era un test, la query falliva e, oltre a non restituire l'oggetto alla variabile, chideva proprio la transazione.

    Cmq ho già deciso di lasciar perdere pdo, se non supporta i savepoint e le transazioni concatenate (una dentro l'altra) è già una bella limitazione per me...
    Poi anche per i prepared statements il metodo bindParam non esegue praticamente nessun controllo sul tipo di valore passato (se specifichi che un parametro deve essere intero e poi gli passi una stringa, non dà nessun errore e va avanti lo stesso).. comincio a dubitare sull'utilità di Pdo onestamente..
    You HAVE to assume your visitor is a maniac serial killer, out to destroy your application. And you have to prevent it.
    I can accept failure, everyone fails at something - But I can't accept not trying.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.