Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: PDO - problem z unbuffered queries
Forum PHP.pl > Forum > PHP
DeyV
Witam

Aż dziwnie się czuję - cały czas piszę na forum, ale strasznie dawno nie zadawałem pytań:)

Podczas pracy z PDO natrafiłem dziś na jednym z serwerów klienta, na nietypowy problem. Zaprezentuję go na przykładzie.

  1. <?php
  2. $Db = new PDO('mysql:host='.$GLOBALS['CONFIG']['db']['host'].'; dbname='.$GLOBALS['CONFIG']['db']['name'],
  3. $GLOBALS['CONFIG']['db']['user'], $GLOBALS['CONFIG']['db']['haslo'] );
  4. $Db -> setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  5.  
  6.  
  7. $query = ' SELECT * FROM session LIMIT 1';
  8. $rWynik = $Db -> query( $query );
  9. $a1 = $rWynik->fetch();
  10.  
  11. var_dump( $a1 );
  12.  
  13. $query = ' SELECT 1 ';
  14. $rWynik2 = $Db -> query( $query );
  15. $a2 = $rWynik2->fetch();
  16.  
  17. var_dump( $a2 );
  18. ?>


Pierwsze zapytanie wykonuje się poprawnie, i zwracana jest (var_dump) tablica zawierająca 1 rekord. (zgodnie z oczekiwaniami smile.gif )

Niestety - 2 zapytanie się nie wykonuje, wyrzucając wyjątek o treści:
Cytat
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2014
Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll().
Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.' in /test/test.php:35
Stack trace:
#0 /test/test.php(35): PDO->query(' SELECT 1 ')
#1 {main}
thrown in /test/test.php on line 35


I wszystko wydawałoby się jasne, gdyby nie to, że błąd taki pojawia się tylko na jednym z serwerów na których pracuję.
Co więcej - jest to o tyle ciekawe, że błąd nie pojawia się za każdym razem, a po drugie - przecież wyraźnie widać, że 1 zapytanie może zwrócić tylko 1 rekord, a wiec fetch() powinno opróżnić bufer do końca.

Oczywiście - mógłbym rozwiązać ten problem tak jak radzi komunikat, ale po pierwsze - po to jest fetch by z niego korzystać, i nie zawsze wydaje się konieczne korzystanie z fetchAll, a ustawianie PDO::MYSQL_ATTR_USE_BUFFERED_QUERY też wygląda raczej na leczenie objawów niż przyczyn.

Czy spotkaliście się z taką sytuacją? I czy można poradzić coś adminowi w celu usunięcia tego problemu?


ps. proszę się nie śmiać z $GLOBALS - to na potrzeby testu winksmiley.jpg
SongoQ
Za to globals mialem juz pisac ale na koncu zobaczylem tongue.gif.

Ta odpowiedz moze Cie nie zadowoli ale ale stosuje sie petle while w celu wyczyszczenie bufora, lub np powtorne uzycie fetch()

  1. <?php
  2. while($a1 = $rWynik->fetch())
  3. print_r($a1);
  4. ?>


Naprawde fetch wykonuje sie 2x wiec ostatnie uzycie powoduje czysczenie bufora. Mozesz tam wywolac 2x fetch i spowoduje wyczysczenie. Dlaczego nieraz nie wysypuje sie, mozliwe ze cos innego ma wplyw na to, jakies inne zapytanie lub zupelnie cos innego. Jesli chodzi o fetchAll to z tego co wyczytalem to wyciaga wszystkie wyniki i laduje do pamieci wiec ten problem nie bedzie wystepowal.
DeyV
Cały kod zaprezentowałem tutaj. A jednak - problem, tak jak napisałem, pojawia się tylko raz na parę razy.
To naprawdę nie wygląda normalnie...

Tak - metodę z while znam. Można również skorzystać z jakieś specjalnej metody do zamykania kursora w pdo. Ale pytanie - czy zawsze trzeba tak robić?
SongoQ
Cytat
Ale pytanie - czy zawsze trzeba tak robić?

No wlasnie nic na ten temat nie znalazlem. Przegladalem manual po tym jak napisales tego posta i nic na ten temat nie znalazlem. Co do tego ze ten blad czasami wystepuje to troche dziwne, testowalem na 2 maszynach i u mnie zawsze ten blad wystepuje. Moze tak jak pisalem cos innego czysci buffor. Jak znajdziesz jakies informacje to napisz bardzo jestem ciekaw czemu tak jest.
DeyV
hmm Już ktoś wcześniej na to wpadł smile.gif

http://bugs.php.net/bug.php?id=33833
> ... but this is not a bug.

Nie ma wyjścia - trzeba extendować PDO z własna metodą fetchRow() sad.gif
A szkoda.
juzwa
mam pytanie?

czy ewentualnie mógłbyś - jeśli byś znalazł - pokazać rozwiązanie - bo ja coś takiego mam (błąd 2014) gdy w funkcji jest procedura na pierwszym miejscu - jeśli jest jedna procedura to OK można przeżyć - ale gdy są dwie lub więcej albo gdy jest procedura -> cokolwiek sqelowego potem - to własnie mam problem z buforem

i nie wiem do tej pory jak to rozwiązać
SongoQ
@juzwa Zasada jest prosta ilosc zwroconych rekordow + 1 razy wywolanie fetch();
DeyV
Ja zdecyduję się chyba na takie rozwiązanie:
  1. <?php
  2. class PDOStatementE extends PDOStatement{
  3. public function fetchRow( $fetch_style, $cursor_orientation , $cursor_offset ){
  4. $aRow = $this->fetch( $fetch_style, $cursor_orientation , $cursor_offset );
  5. $this->closeCursor();
  6. return $aRow;
  7. }
  8. }
  9.  
  10. $Db = new PDO('mysql:host='.$GLOBALS['CONFIG']['db']['host'].'; dbname='.$GLOBALS['CONFIG']['db']['name'],
  11. $GLOBALS['CONFIG']['db']['user'], $GLOBALS['CONFIG']['db']['haslo']
  12. );
  13. $Db -> setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  14. $Db -> setAttribute( PDO::ATTR_STATEMENT_CLASS, array( 'PDOStatementE', array( $this ) ) );
  15. ?>


Oczywiście oznacza to, że z fetchRow będę korzystał tylko wtedy, gdy wiem, że będzie zwrócony co najwyżej 1 rekord.
L00zak
Błąd jest kozak, pojawia mi się tylko gdy w polu formularza wpisuję 'Wait a minute' jeśli mienię to już na 'Wait a minuta' to przechodzi bez problemu, zupełnie jak by interpretował to zdanie, że ma poczekać minute. Ostatnio z PDO jak z dzieckiem:D
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.