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