Przekonasz się, że dzieje się tak tylko kiedy @status
jest NULL
lub ciąg.
Problem jest dwojaki:
-
W przeciwieństwie do zmiennych lokalnych , MySQL zmienne użytkownika obsługuje bardzo ograniczony zestaw typów danych:
Dokumentacja nie wspomina, że rzeczywiste typy danych używane są odpowiednio
BIGINT
,DECIMAL(65,30)
,DOUBLE
,LONGBLOB
,LONGTEXT
iLONGBLOB
. Jeśli chodzi o ostatnią, instrukcja przynajmniej wyjaśnia:Przechowywanie pierwszych trzech z tych typów danych (tj. dla wartości całkowitych, dziesiętnych i zmiennoprzecinkowych) wymaga odpowiednio 8, 30 i 8 bajtów. Inne typy danych (np. dla string i
NULL
wartości) wymagają (maksymalnie) 4 gigabajty pamięci. -
Ponieważ używasz wersji PHP przed 5.4.0, domyślnym sterownikiem MySQL jest libmysql , z którym tylko metadane typu kolumny są dostępne z serwera po powiązaniu danych — więc MySQLi próbuje przydzielić wystarczającą ilość pamięci do przechowywania każdej możliwej wartości (nawet jeśli pełny bufor nie jest ostatecznie wymagany); stąd
NULL
- a zmienne użytkownika o wartościach łańcuchowych, które mają maksymalny możliwy rozmiar 4GiB, powodują przekroczenie domyślnego limitu pamięci PHP (wynoszącego 128 MB od wersji 5.2.0 PHP).
Twoje opcje obejmują:
-
Zastępowanie typu danych kolumny w definicji tabeli:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table ( status VARCHAR(2) ) SELECT @status AS status;
-
Jawnie przesyłanie zmienną użytkownika do bardziej konkretnego typu danych:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT CAST(@status AS CHAR(2)) AS status;
-
Używając zmiennych lokalnych, które są zadeklarowane z określonym typem danych:
DECLARE status VARCHAR(2) DEFAULT @status; DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT status;
-
Obejście problemu przez wywołanie
mysqli_stmt::store_result()
przedmysqli_stmt::bind_result()
, co powoduje, że zestaw wyników jest przechowywany w libmysql (poza limitami pamięci PHP), a następnie PHP przydzieli tylko rzeczywistą pamięć wymaganą do przechowywania rekordu po jego pobraniu:$stmt->execute(); $stmt->store_result(); $stmt->bind_result( $status ); $stmt->fetch();
-
Zwiększenie limitu pamięci PHP tak, aby mógł pomieścić alokację buforów 4GiB (chociaż należy być świadomym konsekwencji dla zasobów sprzętowych z tego powodu) — na przykład, aby całkowicie usunąć ograniczenia pamięci (chociaż należy być świadomym potencjalnych negatywnych skutków ubocznych takiego postępowania, np. z prawdziwych wycieków pamięci):
ini_set('memory_limit', '-1');
-
Ponowna kompilacja PHP, skonfigurowana do korzystania z natywnego sterownika mysqlnd (dołączony do PHP od v5.3.0, ale nie skonfigurowany jako domyślny do PHP v5.4.0) zamiast libmysql:
./configure --with-mysqli=mysqlnd
-
Aktualizacja do PHP w wersji 5.4.0 lub nowszej, tak aby mysqlnd był używany domyślnie.