Zjistíte, že k tomu dochází pouze když @status
je NULL
nebo řetězec.
Problém je dvojí:
-
Na rozdíl od místních proměnných , MySQL uživatelské proměnné podporují velmi omezenou sadu datových typů:
Dokumentace nezmiňuje, že skutečné datové typy použité jsou v tomto pořadí
BIGINT
,DECIMAL(65,30)
,DOUBLE
,LONGBLOB
,LONGTEXT
aLONGBLOB
. Pokud jde o poslední, manuál alespoň vysvětluje:Úložiště z prvních tří těchto datových typů (tj. pro celočíselné, desetinné a plovoucí desetinné čárky) vyžadují 8, 30 a 8 bajtů. Ostatní datové typy (tj. pro řetězec a
NULL
hodnoty) vyžadují (až) 4 gigabajty úložiště. -
Protože používáte verzi PHP starší než v5.4.0, výchozí ovladač MySQL je libmysql , se kterým jsou ze serveru po navázání dat k dispozici pouze metadata typu sloupce – takže se MySQLi pokouší alokovat dostatek paměti pro uchování všech možných hodnot (i když není nakonec potřeba plná vyrovnávací paměť); tedy
NULL
- a uživatelské proměnné s hodnotou řetězce, které mají maximální možnou velikost 4GiB, způsobí, že PHP překročí svůj výchozí limit paměti (128MiB od PHP v5.2.0).
Vaše možnosti zahrnují:
-
Přepsání datového typu sloupce v definici tabulky:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table ( status VARCHAR(2) ) SELECT @status AS status;
-
Explicitně casting uživatelskou proměnnou na specifičtější datový typ:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT CAST(@status AS CHAR(2)) AS status;
-
Pomocí lokálních proměnných, které jsou deklarovány s explicitním datovým typem:
DECLARE status VARCHAR(2) DEFAULT @status; DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT status;
-
Problém vyřešíte voláním
mysqli_stmt::store_result()
předmysqli_stmt::bind_result()
, což způsobí, že výsledná sada bude uložena v libmysql (mimo paměťové limity PHP) a PHP poté po načtení alokuje pouze skutečnou paměť potřebnou k udržení záznamu:$stmt->execute(); $stmt->store_result(); $stmt->bind_result( $status ); $stmt->fetch();
-
Zvyšování limitu paměti PHP PHP tak, aby se mohl přizpůsobit alokaci 4GiB vyrovnávacích pamětí (ačkoli by si člověk měl být vědom důsledků na hardwarové zdroje z toho plynoucí) – například za účelem úplného odstranění omezení paměti (ačkoli je třeba si být vědom potenciálních negativních vedlejších účinků tohoto postupu, např. z originálních úniků paměti):
ini_set('memory_limit', '-1');
-
Překompilování PHP, nakonfigurované pro použití nativního ovladače mysqlnd (součástí PHP od verze 5.3.0, ale není nakonfigurováno jako výchozí až do verze PHP v5.4.0) namísto libmysql:
./configure --with-mysqli=mysqlnd
-
Upgrade na PHP v5.4.0 nebo novější, aby se ve výchozím nastavení používal mysqlnd.