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