2012-05-10 2 views
21

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

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

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? (и как я на самом деле это делаю?)

+0

Вы уже используете PDO, это хорошо. Почему бы вам не воспользоваться преимуществами названной функции заполнителей PDO? См. Учебное пособие: http://www.phpeveryday.com/articles/PDO-Positional-and-Named-Placeholders-P551.html –

+0

Для этого вопроса я попробовал, и это не имеет значения. Для общего запроса есть ли какое-то преимущество в использовании его другого удобства? (Это часть DAL, поэтому она будет генерироваться в любом случае) – Peter

+0

Да, вам не нужно запоминать порядок ваших переменных. Вы увеличиваете абстракцию кода. –

ответ

26

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

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

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

требования битого хранения является: около (М + 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.

+3

Это сработало. Кстати, я просто обнаружил, что использование true/false (вместо 1/0) также, похоже, работает для моего случая. – Peter

+1

Обратите внимание, что при привязке строки в качестве значения, даже если вы используете 'PDO :: PARAM_INT', она не будет работать должным образом. В дополнение к 'PDO :: PARAM_INT' вам также нужно передать строку целому числу:' $ statement-> bindValue (': testBool', (int) $ _ POST ['zero'], PDO :: PARAM_INT); 'или иначе значение всегда будет 1. – Mike

5

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

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

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

+1

Я пробовал, и он все еще не работает. Возможно ли, что драйвер mysql просто не поддерживает собственные подготовленные заявления? Я использую php 5.4.0, если это имеет значение. – Peter

1

вы могли бы попробовать это без параметра

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

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

3

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

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

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