为什么PDO for Postgres为布尔字段返回整数

时间:2015-04-23 13:22:55

标签: php postgresql pdo

我试图将数据从一个数据库复制到另一个数据库。两者都具有100%相同的结构。

当我通过PDO获取一行时,对于布尔字段,我得到整数0/1而不是本机false / true。当我尝试使用PDO将数据插入第二个数据库时导致此错误消息,这是一个问题:

column "disabled" is of type boolean but expression is of type integer

有一个简单的方法吗?我不知道的选项?因为我在这里谈论数百个不同的布尔字段。单独施放它们是不可能的。如果没有简单的方法,我将不得不阅读列类型并采取行动。但我觉得PDO为什么会这样做。

我正在使用Postgres 9.0.1和PHP 5.5.6

其他信息:

以下是一些相关的代码片段。对不起,代码太复杂了,无法显示所有内容。 适用于所有字段,但布尔

        $db = new PDO(
                "pgsql:host=$host;port=$port;dbname=$name",
                $user,
                $pass,
                array(
                    PDO::ATTR_PERSISTENT => $persistent,
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
                )
        );
        $sql = 'SELECT * FROM ...' 

        $sth = $db->query($sql);

        $row = $sth->fetch(PDO::FETCH_ASSOC);

        $sql = "INSERT INTO $tableName (".implode(', ',$cols).") VALUES (:".implode(', :', $cols).")";

        $sthInsert = $dbInsert->prepare($sql);

        foreach ($row as $k=>&$v) {
            $sthInsert->bindParam($k, $v);
        }

        $sthInsert->execute();

4 个答案:

答案 0 :(得分:3)

不是正确处理布尔值的列的检索,而是后续绑定值。

您可以通过简单的选择来检查:

$result = $db->query('Select true as test_truth, false as test_falsehood;');
foreach ( $x as $row ) { var_dump($row); }
/*
array(2) {
  ["test_truth"]=>
  bool(true)
  ["test_falsehood"]=>
  bool(false)
}
*/

问题是当在后续准备好的查询中绑定变量时,PDO会将其强制转换为字符串,因为$data_typePDOStatement::bindParam的默认值为PDO::PARAM_STR({{ 3}})。

(string)true'1'(string)false''。然后将这些传递给Postgres连接,该连接无法将它们转换回布尔值,从而产生错误。

因此,解决方法不需要任何有关预期数据类型的元数据,只需要传入的值的实际类型。一种方法是:

 if ( is_bool($value) ) {
     $value = ( $value ? 't' : 'f' );
 }
 $statement->bindParam($k, $value);

这有效地使用't''f'创建了对字符串的替代广告,这些广告分别是Postgres的默认代表truefalse

或者,您可以根据PHP变量类型设置参数类型:

switch ( gettype($param) ) {
     case 'boolean':
          $param_type = PDO::PARAM_BOOL;
     break;
     // other cases here as necessary
     // see http://php.net/gettype and http://php.net/manual/en/pdo.constants.php
     default:
          $param_type = PDO_PARAM_STR;
     break;
}
$statement->bindParam($k, $param, $param_type);

答案 1 :(得分:2)

不回答您的问题,而是提出一种更直接的方法,并在SQL中完成所有操作,避免insert into t (col1, col2) select a, b from dblink('dbname=the_other_db', 'select a, b from t') as t_other(a integer, b boolean) 过境:

PHP

http://www.postgresql.org/docs/current/static/dblink.html

如果在SQL中进行了一些您不知道该怎么做的处理ssh jenkins@host "-Xmx6g -verbose:gc -Xloggc:/path/to/GC.lo /path/to/java -jar /path/to/slave.jar" 在另一个问题中询问它。

答案 2 :(得分:0)

好的,这似乎是最快捷的方式。它有效,但我认为这是一个错误,直到有人能解释为什么需要这样做:

$sql = "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '$tableName'";

$typeRows = DBH::fetchAll($sql);

foreach ($typeRows as &$tr) {
     $columnTypes[$tr['column_name']] = $tr['data_type'];
} unset($tr);

...

switch ($columnTypes[$k]) {
    case 'boolean' :
         $v = $v==1;
         $sthInsert->bindParam($k, $v, PDO::PARAM_BOOL);
         break;
    default :
         $sthInsert->bindParam($k, $v);
}

答案 3 :(得分:0)

你有一个数组$cols我不知道那是什么,但我已经提出了一个解决方案,如果你不想从另一个答案中提出的数据库中获取信息,如何定义它。此外,我还认为您需要将:添加到bindParam键值。

$cols = array('col1' => 's', 'col2' => 'b');

    $sql = "INSERT INTO $tableName (".implode(', ',array_keys($cols)).") VALUES (:".implode(', :', array_keys($cols)).")";

    $sthInsert = $dbInsert->prepare($sql);

    foreach ($row as $k=>&$v) {
        switch($cols[$k]){
            // null
            case 'n':
                $sthInsert->bindParam(':' . $k, $v, PDO::PARAM_NULL);
                break;
            // bool
            case 'b':
                $sthInsert->bindParam(':' . $k, $v, PDO::PARAM_BOOL);
                break;
            // int
            case 'i':
                $sthInsert->bindParam(':' . $k, $v, PDO::PARAM_INT);
                break;
            // str
            case 's':
                $sthInsert->bindParam(':' . $k, $v, PDO::PARAM_STR);
                break;
            // lob
            case 'l':
                $sthInsert->bindParam(':' . $k, $v, PDO::PARAM_LOB);
                break;
            default:
                $sthInsert->bindParam(':' . $k, $v);
                break;
        }
    }