web-dev-qa-db-ja.com

PDOstatement(MySQL):値0をbit(1)フィールドに挿入すると、1がテーブルに書き込まれます

私はbit(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)) ;

そのコードを実行すると、TestBoolの下に値1の行が表示されます。そして、bindValue()とbindParm()を使用した同じこと。 (?の代わりに)名前付きプレースホルダーも試しましたが、同じ結果になりました。

それから私は試しました:

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

これは正しく機能しました(TestBoolの値は0です)。 SQLをMySQLに直接パンチすることもできます。

1を挿入すると常に機能することに注意してください。

では、なぜプレースホルダーは値0を挿入できないのでしょうか。 (そして私は実際にそれをどのように行うのですか?)

22
Peter

BIT列はmysqlのバイナリ型であり(数値型として文書化されていますが、正確には正しくありません)、クライアントライブラリの問題(PDOの問題で証明されています)のために回避することをお勧めします。列のタイプをTINYINT(1)に変更すると、多くの問題を回避できます。

もちろん、TINYINT(1)はすべての行で1バイトのストレージを消費しますが、mysqlのドキュメントによると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に変更することをお勧めします。

31

pdoは、デフォルトではmysqlドライバー用のプリペアドステートメントを使用せず、バックグラウンドで動的SQLを作成することによってそれらをエミュレートします。 mysqlに送信されるSQLは、最終的に「0」のように一重引用符で囲まれた0になります。これは、mysqlが数値ではなく文字列として解釈します。

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

これで機能するはずです。また、実際に準備されたステートメントを使用することになります。

5
goat

prepareはパラメータに'を追加するため、パラメータ名の前にbを追加するだけで済みます。

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

1, 0またはTRUE, FALSEを使用できます。

3
wajih

あなたはパラメータなしでこれを試すことができます

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

セキュリティ上の問題はありません

1
saeed