Scoprirai che questo sta accadendo solo quando @status
è NULL
o una stringa.
Il problema è duplice:
-
A differenza di variabili locali , MySQL variabili utente supporta un insieme molto limitato di tipi di dati:
La documentazione non menziona che i tipi di dati effettivi utilizzati sono rispettivamente
BIGINT
,DECIMAL(65,30)
,DOUBLE
,LONGBLOB
,LONGTEXT
eLONGBLOB
. Per quanto riguarda l'ultimo, il manuale spiega almeno:Archiviazione dei primi tre di questi tipi di dati (cioè per valori interi, decimali e in virgola mobile) richiedono rispettivamente 8, 30 e 8 byte. Gli altri tipi di dati (ad esempio per string e
NULL
valori) richiedono (fino a) 4 gigabyte di archiviazione. -
Poiché stai utilizzando una versione di PHP precedente alla v5.4.0, il driver MySQL predefinito è libmysql , con il quale solo i metadati del tipo di colonna sono disponibili dal server al momento dell'associazione dei dati, quindi MySQLi tenta di allocare memoria sufficiente per contenere ogni possibile valore (anche se alla fine non è necessario il buffer completo); quindi
NULL
- e le variabili utente con valori di stringa, che hanno una dimensione massima possibile di 4GiB, fanno sì che PHP superi il suo limite di memoria predefinito (di 128MiB da PHP v5.2.0).
Le tue opzioni includono:
-
Sovrascrivere il tipo di dati della colonna nella definizione della tabella:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table ( status VARCHAR(2) ) SELECT @status AS status;
-
Esplicitamente casting la variabile utente a un tipo di dati più specifico:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT CAST(@status AS CHAR(2)) AS status;
-
Utilizzando variabili locali, dichiarate con un tipo di dati esplicito:
DECLARE status VARCHAR(2) DEFAULT @status; DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT status;
-
Risolvere il problema chiamando
mysqli_stmt::store_result()
primamysqli_stmt::bind_result()
, che fa sì che il set di risultati venga archiviato in libmysql (al di fuori dei limiti di memoria di PHP) e quindi PHP allocherà solo la memoria effettiva necessaria per conservare il record al momento del recupero:$stmt->execute(); $stmt->store_result(); $stmt->bind_result( $status ); $stmt->fetch();
-
Aumento del limite di memoria di PHP in modo che possa accogliere l'allocazione di buffer da 4GiB (sebbene si dovrebbe essere consapevoli delle implicazioni sulle risorse hardware in questo modo), ad esempio, per rimuovere completamente i vincoli di memoria (sebbene essere consapevoli dei potenziali effetti collaterali negativi di farlo, ad esempio da vere perdite di memoria):
ini_set('memory_limit', '-1');
-
Ricompilazione di PHP, configurato per utilizzare il driver mysqlnd nativo (incluso in PHP dalla v5.3.0, ma non configurato come predefinito fino alla v5.4.0) invece di libmysql:
./configure --with-mysqli=mysqlnd
-
Aggiornamento a PHP v5.4.0 o successivo in modo che mysqlnd venga utilizzato per impostazione predefinita.