1--TEST-- 2MySQL PDO->prepare(), emulated PS 3--EXTENSIONS-- 4pdo_mysql 5--SKIPIF-- 6<?php 7require_once __DIR__ . '/inc/mysql_pdo_test.inc'; 8MySQLPDOTest::skip(); 9?> 10--FILE-- 11<?php 12 require_once __DIR__ . '/inc/mysql_pdo_test.inc'; 13 $db = MySQLPDOTest::factory(); 14 $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true); 15 16 function prepex($offset, &$db, $query, $input_params = null, $error_info = null) { 17 try { 18 if (is_array($error_info) && isset($error_info['prepare'])) 19 $stmt = @$db->prepare($query); 20 else 21 $stmt = $db->prepare($query); 22 23 if (is_array($error_info) && isset($error_info['prepare'])) { 24 $tmp = $db->errorInfo(); 25 26 if (isset($error_info['prepare']['sqlstate']) && 27 ($error_info['prepare']['sqlstate'] !== $tmp[0])) { 28 printf("[%03d] prepare() - expecting SQLSTATE '%s' got '%s'\n", 29 $offset, $error_info['prepare']['sqlstate'], $tmp[0]); 30 return false; 31 } 32 33 if (isset($error_info['prepare']['mysql']) && 34 ($error_info['prepare']['mysql'] !== $tmp[1])) { 35 printf("[%03d] prepare() - expecting MySQL Code '%s' got '%s'\n", 36 $offset, $error_info['prepare']['mysql'], $tmp[0]); 37 return false; 38 } 39 40 return false; 41 } 42 43 if (is_null($input_params)) 44 $input_params = array(); 45 46 if (is_array($error_info) && isset($error_info['execute'])) 47 $ret = @$stmt->execute($input_params); 48 else 49 $ret = $stmt->execute($input_params); 50 51 if (!is_bool($ret)) 52 printf("[%03d] PDO::execute() should return a boolean value, got %s/%s\n", 53 var_export($ret, true), $ret); 54 55 if (is_array($error_info) && isset($error_info['execute'])) { 56 $tmp = $stmt->errorInfo(); 57 58 if (isset($error_info['execute']['sqlstate']) && 59 ($error_info['execute']['sqlstate'] !== $tmp[0])) { 60 printf("[%03d] execute() - expecting SQLSTATE '%s' got '%s'\n", 61 $offset, $error_info['execute']['sqlstate'], $tmp[0]); 62 return false; 63 } 64 65 if (isset($error_info['execute']['mysql']) && 66 ($error_info['execute']['mysql'] !== $tmp[1])) { 67 printf("[%03d] execute() - expecting MySQL Code '%s' got '%s'\n", 68 $offset, $error_info['execute']['mysql'], $tmp[0]); 69 return false; 70 } 71 72 return false; 73 } 74 } catch (PDOException $e) { 75 printf("[%03d] %s, [%s} %s\n", 76 $offset, $e->getMessage(), 77 $db->errorCode(), implode(' ', $db->errorInfo())); 78 return false; 79 } 80 81 return $stmt; 82 } 83 84 try { 85 $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1); 86 if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY)) 87 printf("[002] Unable to switch to emulated prepared statements, test will fail\n"); 88 89 try { 90 prepex(3, $db, '', [], ['execute' => ['sqlstate' => '42000']]); 91 } catch (\ValueError $e) { 92 echo $e->getMessage(), \PHP_EOL; 93 } 94 95 // lets be fair and do the most simple SELECT first 96 $stmt = prepex(4, $db, 'SELECT 1 AS "one"'); 97 var_dump($stmt->fetch(PDO::FETCH_ASSOC)); 98 99 prepex(6, $db, sprintf('CREATE TABLE test_prepare_emulated(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE)); 100 prepex(7, $db, "INSERT INTO test_prepare_emulated(id, label) VALUES(1, ':placeholder')"); 101 $stmt = prepex(8, $db, 'SELECT label FROM test_prepare_emulated'); 102 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 103 104 prepex(9, $db, 'DELETE FROM test_prepare_emulated'); 105 prepex(10, $db, "INSERT INTO test_prepare_emulated(id, label) VALUES(1, ':placeholder')", 106 array(':placeholder' => 'first row')); 107 $stmt = prepex(11, $db, 'SELECT label FROM test_prepare_emulated'); 108 109 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 110 prepex(12, $db, 'DELETE FROM test_prepare_emulated'); 111 prepex(13, $db, 'INSERT INTO test_prepare_emulated(id, label) VALUES(1, :placeholder)', 112 array(':placeholder' => 'first row')); 113 prepex(14, $db, 'INSERT INTO test_prepare_emulated(id, label) VALUES(2, :placeholder)', 114 array(':placeholder' => 'second row')); 115 $stmt = prepex(15, $db, 'SELECT label FROM test_prepare_emulated'); 116 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 117 118 // Is PDO fun? 119 prepex(16, $db, 'SELECT label FROM test_prepare_emulated WHERE :placeholder > 1', 120 array(':placeholder' => 'id')); 121 prepex(17, $db, 'SELECT :placeholder FROM test_prepare_emulated WHERE id > 1', 122 array(':placeholder' => 'id')); 123 prepex(18, $db, 'SELECT :placeholder FROM test_prepare_emulated WHERE :placeholder > :placeholder', 124 array(':placeholder' => 'test')); 125 126 for ($num_params = 2; $num_params < 100; $num_params++) { 127 $params = array(':placeholder' => 'a'); 128 for ($i = 1; $i < $num_params; $i++) { 129 $params[str_repeat('a', $i)] = 'some data'; 130 } 131 prepex(19, $db, 'SELECT id, label FROM test_prepare_emulated WHERE label > :placeholder', 132 $params, array('execute' => array('sqlstate' => 'HY093'))); 133 } 134 135 prepex(20, $db, 'DELETE FROM test_prepare_emulated'); 136 prepex(21, $db, 'INSERT INTO test_prepare_emulated(id, label) VALUES (1, :placeholder), (2, :placeholder)', 137 array(':placeholder' => 'row')); 138 $stmt = prepex(22, $db, 'SELECT id, label FROM test_prepare_emulated'); 139 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 140 141 $stmt = prepex(23, $db, 'SELECT id, label FROM test_prepare_emulated WHERE :placeholder IS NOT NULL', 142 array(':placeholder' => 1)); 143 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) 144 printf("[024] '1' IS NOT NULL evaluates to true, expecting two rows, got %d rows\n", $tmp); 145 146 $stmt = prepex(25, $db, 'SELECT id, label FROM test_prepare_emulated WHERE :placeholder IS NULL', 147 array(':placeholder' => 1)); 148 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0) 149 printf("[026] '1' IS NOT NULL evaluates to true, expecting zero rows, got %d rows\n", $tmp); 150 151 } catch (PDOException $e) { 152 printf("[001] %s [%s] %s\n", 153 $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); 154 } 155 156 print "done!"; 157?> 158--CLEAN-- 159<?php 160require_once __DIR__ . '/inc/mysql_pdo_test.inc'; 161$db = MySQLPDOTest::factory(); 162$db->exec('DROP TABLE IF EXISTS test_prepare_emulated'); 163?> 164--EXPECTF-- 165PDO::prepare(): Argument #1 ($query) must not be empty 166array(1) { 167 ["one"]=> 168 string(1) "1" 169} 170array(1) { 171 [0]=> 172 array(1) { 173 ["label"]=> 174 string(12) ":placeholder" 175 } 176} 177 178Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in %s on line %d 179array(0) { 180} 181array(2) { 182 [0]=> 183 array(1) { 184 ["label"]=> 185 string(9) "first row" 186 } 187 [1]=> 188 array(1) { 189 ["label"]=> 190 string(10) "second row" 191 } 192} 193array(2) { 194 [0]=> 195 array(2) { 196 ["id"]=> 197 string(1) "1" 198 ["label"]=> 199 string(3) "row" 200 } 201 [1]=> 202 array(2) { 203 ["id"]=> 204 string(1) "2" 205 ["label"]=> 206 string(3) "row" 207 } 208} 209done! 210