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(). Я также пробовал с именем placeholders (вместо?) С тем же результатом.
Затем я попытался:
$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES ("TEST",0)') ;
$statement->execute() ;
Что работало правильно (TestBool имеет значение 0). Также работает штамповка в SQL непосредственно в MySQL.
Обратите внимание, что вставка 1 всегда работает.
Итак, почему заполнители не вставляют значение 0? (и как я на самом деле это делаю?)
Ответы
Ответ 1
Столбец 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.
Ответ 2
pdo по умолчанию не использует подготовленные операторы для драйвера mysql, он имитирует их, создавая динамический sql за кулисами для вас. Sql, отправленный в mysql, заканчивается как одиночный кавычек 0, такой как "0", который mysql интерпретирует как строку, а не число.
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Теперь он должен работать, и вы также будете фактически использовать реальные подготовленные заявления.
Ответ 3
Поскольку prepare
добавляет '
к вашему параметру, вы должны добавить b
перед именем параметра
$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES (?, b?)');
$statement->execute(array("TEST", 1 /* or TRUE */));
Примечание: вы можете использовать 1, 0
или TRUE, FALSE
.
Ответ 4
вы можете попробовать это без параметра
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")) ;
и без проблем безопасности