2012-05-10 15 views
21

Używam pola bitowego (1) do przechowywania wartości logicznych i wpisywania do tabeli za pomocą instrukcji przygotowanych przez PDO.PDOstatement (MySQL): wstawienie wartości 0 do bitu (1) powoduje wyświetlenie 1 w tabeli

Jest to tabela testu:

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

Jest to kod testowy:

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

Uruchomienie tego kodu daje mi wiersz o wartości 1 pod TestBool. I to samo przy użyciu bindValue() i bindParm(). Próbowałem również nazwanych placeholders (zamiast?) Z tym samym wynikiem.

Potem próbowałem:

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

działał poprawnie (TestBool ma wartość 0). Wdrażanie SQL bezpośrednio do MySQL również działa.

Pamiętaj, że wstawianie 1 zawsze działa.

Dlaczego więc placeholders nie wstawią wartości 0? (i jak faktycznie to zrobić?)

+0

Już używasz PDO, to dobrze. Dlaczego nie skorzystać z wymienionej funkcji zastępczej dla ChNP? Zobacz samouczek: http://www.phpeveryday.com/articles/PDO-Positional-and-Named-Placeholders- P551.html –

+0

Na potrzeby tego pytania spróbowałem i nie ma to znaczenia. W przypadku ogólnego zapytania czy jest jakaś korzyść z używania go, a nie wygody? (Jest to część DAL, więc i tak zostanie wygenerowane) – Peter

+0

Tak, nie musisz pamiętać kolejności zmiennych. Zwiększasz abstrakcję kodu. –

Odpowiedz

26

Kolumna BIT jest typem binarnym w mysql (chociaż jest to udokumentowane jako typ numeryczny - to nie jest dokładnie prawda) i radzę jej unikać z powodu problemów z bibliotekami klienta (co dowodzi problem PDO). Oszczędź sobie dużo kłopotów, jeśli zmodyfikujesz typ kolumny na TINYINT (1)

TINYINT (1) oczywiście zużyje pełny bajt pamięci dla każdego wiersza, ale według dokumentów mysql BIT (1) zrobi także.

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

wymogu magazynowania bit jest: w przybliżeniu (M + 7)/8 bajtów, która sugeruje, że bit (aM) są również bajtowi.

Również znalazłem to: https://bugs.php.net/bug.php?id=50757

więc można sprawdzić, czy następujący kod działa zgodnie z oczekiwaniami:

$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(); 

Można również próbować z różnymi odcieniami typu niż PARAM_INT, nadal nawet jeśli się go pracuję, radzę zmienić na TINYINT.

+3

To działało. Nawiasem mówiąc, właśnie odkryłem, że używanie wartości true/false (zamiast 1/0) również działa w moim przypadku. – Peter

+1

Należy pamiętać, że po powiązaniu łańcucha jako wartości, nawet jeśli użyjesz 'PDO :: PARAM_INT', to nie będzie działać zgodnie z oczekiwaniami. Oprócz 'PDO :: PARAM_INT' musisz również rzucić ciąg na liczbę całkowitą:' $ instrukcja-> bindValue (': testBool', (int) $ _ POST ['zero'], PDO :: PARAM_INT); 'albo inaczej wartość zawsze będzie równa 1. – Mike

5

pdo domyślnie nie używa przygotowanych instrukcji dla sterownika mysql, emuluje je, tworząc dynamiczny sql za kulisami. Sql wysłany do mysql kończy się jako pojedynczy cytowany 0, taki jak "0", który mysql interpretuje jako ciąg, a nie jako liczbę.

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

Powinno to teraz działać, a Ty będziesz także używać rzeczywiście przygotowanych wyciągów.

+1

Próbowałem go i nadal nie działa. Czy jest możliwe, że sterownik mysql po prostu nie obsługuje natywnych przygotowanych instrukcji? Używam php 5.4.0, jeśli to robi różnicę. – Peter

1

można spróbować bez parametru

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")) ; 

i bez problemu bezpieczeństwa

3

Ponieważ prepare dodaje ' do parametru, trzeba tylko dodać b przed nazwą parametru

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

Uwaga: można użyć 1, 0 lub TRUE, FALSE.

Powiązane problemy