1--TEST-- 2PDO PgSQL Bug #33876 (PDO misquotes/miscasts bool(false)) 3--EXTENSIONS-- 4pdo 5pdo_pgsql 6--SKIPIF-- 7<?php 8require __DIR__ . '/config.inc'; 9require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; 10PDOTest::skip(); 11?> 12--FILE-- 13<?php 14require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; 15$db = PDOTest::test_factory(__DIR__ . '/common.phpt'); 16$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); 17 18$db->exec("SET LC_MESSAGES='C'"); 19$db->exec('CREATE TABLE b33876 (foo varchar(5) NOT NULL, bar bool NOT NULL)'); 20$db->exec("INSERT INTO b33876 VALUES('false','f'), ('true', 't')"); 21 22$res = $db->prepare('SELECT foo from b33876 where bar = ?'); 23 24# this is the portable approach to binding a bool 25$res->bindValue(1, false, PDO::PARAM_BOOL); 26if (!$res->execute()) 27 print_r($res->errorInfo()); 28else 29 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 30 31# this is the portable approach to binding a bool 32$res->bindValue(1, true, PDO::PARAM_BOOL); 33if (!$res->execute()) 34 print_r($res->errorInfo()); 35else 36 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 37 38 39# true gets cast to string (because the implied default is string) 40# true-as-string is 1, so this "works" 41if (!$res->execute(array(true))) 42 print_r($res->errorInfo()); 43else 44 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 45 46# Expected to fail; unless told otherwise, PDO assumes string inputs 47# false -> "" as string, which pgsql doesn't like 48if (!$res->execute(array(false))) 49 print_r(normalizeErrorInfo($res->errorInfo())); 50else 51 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 52 53# And now using emulator prepares 54echo "EMUL\n"; 55 56 57$res = $db->prepare('SELECT foo from b33876 where bar = ?', array( 58 PDO::ATTR_EMULATE_PREPARES => true)); 59 60# this is the portable approach to binding a bool 61$res->bindValue(1, false, PDO::PARAM_BOOL); 62if (!$res->execute()) 63 print_r($res->errorInfo()); 64else 65 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 66 67# this is the portable approach to binding a bool 68$res->bindValue(1, true, PDO::PARAM_BOOL); 69if (!$res->execute()) 70 print_r($res->errorInfo()); 71else 72 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 73 74 75# true gets cast to string (because the implied default is string) 76# true-as-string is 1, so this "works" 77if (!$res->execute(array(true))) 78 print_r($res->errorInfo()); 79else 80 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 81 82# Expected to fail; unless told otherwise, PDO assumes string inputs 83# false -> "" as string, which pgsql doesn't like 84if (!$res->execute(array(false))) { 85 print_r(normalizeErrorInfo($res->errorInfo())); 86} else { 87 print_r($res->fetchAll(PDO::FETCH_ASSOC)); 88} 89 90function normalizeErrorInfo(array $err): array { 91 // Strip additional lines outputted by recent PgSQL versions 92 $err[2] = trim(current(explode("\n", $err[2]))); 93 return $err; 94} 95 96?> 97--CLEAN-- 98<?php 99require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; 100$db = PDOTest::test_factory(__DIR__ . '/common.phpt'); 101$db->query('DROP TABLE IF EXISTS b33876 CASCADE'); 102?> 103--EXPECTF-- 104Array 105( 106 [0] => Array 107 ( 108 [foo] => false 109 ) 110 111) 112Array 113( 114 [0] => Array 115 ( 116 [foo] => true 117 ) 118 119) 120Array 121( 122 [0] => Array 123 ( 124 [foo] => true 125 ) 126 127) 128Array 129( 130 [0] => 22P02 131 [1] => 7 132 [2] => %s: %sboolean%s 133) 134EMUL 135Array 136( 137 [0] => Array 138 ( 139 [foo] => false 140 ) 141 142) 143Array 144( 145 [0] => Array 146 ( 147 [foo] => true 148 ) 149 150) 151Array 152( 153 [0] => Array 154 ( 155 [foo] => true 156 ) 157 158) 159Array 160( 161 [0] => 22P02 162 [1] => 7 163 [2] => %s: %sboolean%s 164) 165