2012-05-10 24 views
21

Sto usando un campo bit (1) per memorizzare valori booleani e scrivere nella tabella utilizzando istruzioni preparate PDO.PDOstatement (MySQL): inserendo il valore 0 in un campo bit (1) risulta 1 scritto nella tabella

Questa è la tabella di prova:

CREATE TABLE IF NOT EXISTS `test` (
    `SomeText` varchar(255) NOT NULL, 
    `TestBool` bit(1) NOT NULL DEFAULT b'0' 
) ENGINE=MEMORY DEFAULT CHARSET=latin1; 

Questo è il codice di prova:

$pdo = new PDO("connection string etc") ; 
$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES (?,?)') ; 
$statement->execute(array("TEST",0)) ; 

Esecuzione di codice che mi dà una riga con il valore 1 in TestBool. E la stessa cosa con bindValue() e bindParm(). Ho anche provato i segnaposti denominati (anziché?) Con lo stesso risultato.

Poi ho provato:

$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES ("TEST",0)') ; 
$statement->execute() ; 

che ha funzionato correttamente (TestBool ha valore 0). Funziona anche il punch in SQL direttamente in MySQL.

Si noti che l'inserimento di 1 funziona sempre.

Quindi perché i segnaposto non inseriscono il valore 0? (e come faccio a farlo?)

+0

Si sta già utilizzando PDO, va bene. Perché non sfruttare la caratteristica dei segnaposti denominati di PDO? Vedi un tutorial: http://www.phpeveryday.com/articles/PDO-Positional-and-Named-Placeholders-P551.html –

+0

Ai fini di questa domanda, l'ho provato e non fa differenza. Per un'inchiesta generale, c'è qualche vantaggio nell'usarlo diverso dalla convenienza? (Questo fa parte di un DAL quindi verrà generato comunque) – Peter

+0

Sì, non è necessario ricordare l'ordine delle variabili. Aumenta l'astrazione del codice. –

risposta

26

La colonna BIT è un tipo binario in mysql (anche se è documentato come tipo numerico - non è esattamente vero) e consiglio di evitarlo a causa di problemi con le librerie client (il problema relativo al PDO lo dimostra). Potrai risparmiare un sacco di problemi se si modifica il tipo di colonna per TINYINT (1)

TINYINT (1) sarà ovviamente consumare piena di byte di spazio di archiviazione per ogni riga, ma secondo documenti mysql BIT (1) farà anche.

da: http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html

requisito stoccaggio bit è: circa (M + 7)/8 byte che suggerisce che colonna BIT (M) è anche byte-allineati.

Inoltre ho trovato questo: https://bugs.php.net/bug.php?id=50757

così da poter controllare se seguente codice funziona come ci si aspetta:

$pdo = new PDO("connection string etc") ; 
$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES (:someText,:testBool)') ; 
$statement->bindValue(':someText', "TEST"); 
$statement->bindValue(':testBool', 0, PDO::PARAM_INT); 
$statement->execute(); 

Si può anche provare con diversi suggerimenti tipo di PARAM_INT, comunque, anche se si rendono lavoro consiglio di cambiare in TINYINT.

+3

Ha funzionato. Per inciso, ho appena scoperto che usare true/false (anziché 1/0) sembra funzionare anche per il mio caso. – Peter

+1

Si noti che quando si associa una stringa come valore, anche se si utilizza 'PDO :: PARAM_INT', non funzionerà come previsto. Oltre a 'PDO :: PARAM_INT', devi anche eseguire il cast della stringa su un numero intero:' $ statement-> bindValue (': testBool', (int) $ _ POST ['zero'], PDO :: PARAM_INT); 'altrimenti il ​​valore sarà sempre 1. – Mike

5

pdo di default non usa istruzioni preparate per il driver mysql, le emula creando sql dinamico dietro le quinte per te. Lo sql inviato a mysql finisce per essere un singolo quotato 0 come '0', che mysql interpreta come una stringa, non un numero.

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 

Dovrebbe funzionare ora, e in effetti userete anche istruzioni preparate.

+1

L'ho provato e non funziona ancora. È possibile che il driver mysql semplicemente non supporti le istruzioni preparate in modo nativo? Sto usando php 5.4.0 se questo fa la differenza. – Peter

1

si potrebbe provare questo senza parametro

if($_POST['bool'] == 1) 
{ 
$bool = "b'1'"; 
} 
else 
{ 
$bool = "b'0'"; 
} 
$statement = $pdo->prepare("INSERT INTO `test` (SomeText,TestBool) VALUES (?,$bool)") ; 
$statement->execute(array("TEST")) ; 

e nessun problema di sicurezza

3

Perché prepare aggiunge ' al parametro, Basta aggiungere b prima del nome del parametro

$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES (?, b?)'); 
$statement->execute(array("TEST", 1 /* or TRUE */)); 

Nota: è possibile utilizzare 1, 0 o TRUE, FALSE.

Problemi correlati