PDOstatement (MySQL): вставка значения 0 в бит (1) поле приводит к 1 записи в таблице

Я использую поле бит (1) для хранения логических значений и записи в таблицу с помощью подготовленных инструкций PDO.

Это тестовая таблица:

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

Это тестовый код:

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

Запуск этого кода дает мне строку со значением 1 в TestBool. И то же самое, используя bindValue () и bindParm (). Я также попробовал названные заполнители (вместо?) С тем же результатом.

Затем я попробовал:

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

Что работало правильно (TestBool имеет значение 0). Также работает штамповка в SQL непосредственно в MySQL.

Обратите внимание, что вставка 1 всегда работает.

Итак, почему заполнители не вставляют значение 0? (и как я на самом деле это делаю?)

Столбец BIT является двоичным типом в mysql (хотя он документирован как числовой тип – это не совсем верно), и я советую избегать его из-за проблем с клиентскими библиотеками (что доказывает проблема PDO). Вы избавитесь от многих проблем, если вы измените тип столбца на TINYINT (1)

TINYINT (1), разумеется, потребляет полный байт памяти для каждой строки, но в соответствии с mysql docs BIT (1) также будет работать.

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

бит: приблизительно (M + 7) / 8 байтов, что говорит о том, что столбец BIT (M) также выровнен по байтам.

Также я нашел это: https://bugs.php.net/bug.php?id=50757

Таким образом, вы можете проверить, работает ли следующий код, как вы ожидаете:

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

Вы также можете попробовать с подсказками типа типа PARAM_INT, но даже если вы заработаете, я советую перейти на TINYINT.

По умолчанию pdo не использует подготовленные операторы для драйвера mysql, он имитирует их, создавая динамический sql за кулисами для вас. Sql, отправленный в mysql, заканчивается как одиночный кавычек 0, такой как «0», который mysql интерпретирует как строку, а не число.

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

Он должен работать сейчас, и вы также будете фактически использовать реальные подготовленные заявления.

Поскольку prepare добавляет ' к вашему параметру, вам нужно только добавить b до имени параметра

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

Примечание : вы можете использовать 1, 0 или TRUE, FALSE .

вы можете попробовать это без параметра

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

и никакой проблемы безопасности