1--TEST-- 2MySQL PDO->prepare(), emulated PS 3--SKIPIF-- 4<?php 5require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc'); 6require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); 7MySQLPDOTest::skip(); 8$db = MySQLPDOTest::factory(); 9?> 10--FILE-- 11<?php 12 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); 13 $db = MySQLPDOTest::factory(); 14 15 function prepex($offset, &$db, $query, $input_params = null, $error_info = null) { 16 17 try { 18 19 if (is_array($error_info) && isset($error_info['prepare'])) 20 $stmt = @$db->prepare($query); 21 else 22 $stmt = $db->prepare($query); 23 24 if (is_array($error_info) && isset($error_info['prepare'])) { 25 $tmp = $db->errorInfo(); 26 27 if (isset($error_info['prepare']['sqlstate']) && 28 ($error_info['prepare']['sqlstate'] !== $tmp[0])) { 29 printf("[%03d] prepare() - expecting SQLSTATE '%s' got '%s'\n", 30 $offset, $error_info['prepare']['sqlstate'], $tmp[0]); 31 return false; 32 } 33 34 if (isset($error_info['prepare']['mysql']) && 35 ($error_info['prepare']['mysql'] !== $tmp[1])) { 36 printf("[%03d] prepare() - expecting MySQL Code '%s' got '%s'\n", 37 $offset, $error_info['prepare']['mysql'], $tmp[0]); 38 return false; 39 } 40 41 return false; 42 } 43 44 if (is_null($input_params)) 45 $input_params = array(); 46 47 if (is_array($error_info) && isset($error_info['execute'])) 48 $ret = @$stmt->execute($input_params); 49 else 50 $ret = $stmt->execute($input_params); 51 52 if (!is_bool($ret)) 53 printf("[%03d] PDO::execute() should return a boolean value, got %s/%s\n", 54 var_export($ret, true), $ret); 55 56 if (is_array($error_info) && isset($error_info['execute'])) { 57 $tmp = $stmt->errorInfo(); 58 59 if (isset($error_info['execute']['sqlstate']) && 60 ($error_info['execute']['sqlstate'] !== $tmp[0])) { 61 printf("[%03d] execute() - expecting SQLSTATE '%s' got '%s'\n", 62 $offset, $error_info['execute']['sqlstate'], $tmp[0]); 63 return false; 64 } 65 66 if (isset($error_info['execute']['mysql']) && 67 ($error_info['execute']['mysql'] !== $tmp[1])) { 68 printf("[%03d] execute() - expecting MySQL Code '%s' got '%s'\n", 69 $offset, $error_info['execute']['mysql'], $tmp[0]); 70 return false; 71 } 72 73 return false; 74 } 75 76 } catch (PDOException $e) { 77 printf("[%03d] %s, [%s} %s\n", 78 $offset, $e->getMessage(), 79 $db->errorCode(), implode(' ', $db->errorInfo())); 80 return false; 81 } 82 83 return $stmt; 84 } 85 86 try { 87 $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1); 88 if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY)) 89 printf("[002] Unable to switch to emulated prepared statements, test will fail\n"); 90 91 // TODO - that's PDO - you can prepare empty statements! 92 prepex(3, $db, '', 93 array(), array('execute' => array('sqlstate' => '42000'))); 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(5, $db, 'DROP TABLE IF EXISTS test'); 100 prepex(6, $db, sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE)); 101 prepex(7, $db, "INSERT INTO test(id, label) VALUES(1, ':placeholder')"); 102 $stmt = prepex(8, $db, 'SELECT label FROM test'); 103 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 104 105 prepex(9, $db, 'DELETE FROM test'); 106 prepex(10, $db, "INSERT INTO test(id, label) VALUES(1, ':placeholder')", 107 array(':placeholder' => 'first row')); 108 $stmt = prepex(11, $db, 'SELECT label FROM test'); 109 110 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 111 prepex(12, $db, 'DELETE FROM test'); 112 prepex(13, $db, 'INSERT INTO test(id, label) VALUES(1, :placeholder)', 113 array(':placeholder' => 'first row')); 114 prepex(14, $db, 'INSERT INTO test(id, label) VALUES(2, :placeholder)', 115 array(':placeholder' => 'second row')); 116 $stmt = prepex(15, $db, 'SELECT label FROM test'); 117 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 118 119 // Is PDO fun? 120 prepex(16, $db, 'SELECT label FROM test WHERE :placeholder > 1', 121 array(':placeholder' => 'id')); 122 prepex(17, $db, 'SELECT :placeholder FROM test WHERE id > 1', 123 array(':placeholder' => 'id')); 124 prepex(18, $db, 'SELECT :placeholder FROM test WHERE :placeholder > :placeholder', 125 array(':placeholder' => 'test')); 126 127 for ($num_params = 2; $num_params < 100; $num_params++) { 128 $params = array(':placeholder' => 'a'); 129 for ($i = 1; $i < $num_params; $i++) { 130 $params[str_repeat('a', $i)] = 'some data'; 131 } 132 prepex(19, $db, 'SELECT id, label FROM test WHERE label > :placeholder', 133 $params, array('execute' => array('sqlstate' => 'HY093'))); 134 } 135 136 prepex(20, $db, 'DELETE FROM test'); 137 prepex(21, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder), (2, :placeholder)', 138 array(':placeholder' => 'row')); 139 $stmt = prepex(22, $db, 'SELECT id, label FROM test'); 140 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 141 142 $stmt = prepex(23, $db, 'SELECT id, label FROM test WHERE :placeholder IS NOT NULL', 143 array(':placeholder' => 1)); 144 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) 145 printf("[024] '1' IS NOT NULL evaluates to true, expecting two rows, got %d rows\n", $tmp); 146 147 $stmt = prepex(25, $db, 'SELECT id, label FROM test WHERE :placeholder IS NULL', 148 array(':placeholder' => 1)); 149 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0) 150 printf("[026] '1' IS NOT NULL evaluates to true, expecting zero rows, got %d rows\n", $tmp); 151 152 prepex(27, $db, 'DROP TABLE IF EXISTS test'); 153 prepex(28, $db, 'CREATE TABLE test(id INT, label CHAR(255)) ENGINE=MyISAM'); 154 if (is_object(prepex(29, $db, 'CREATE FULLTEXT INDEX idx1 ON test(label)'))) { 155 prepex(30, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder)', 156 array(':placeholder' => 'MySQL is the best database in the world!')); 157 prepex(31, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder)', 158 array(':placeholder' => 'If I have the freedom to choose, I would always go again for the MySQL Server')); 159 $stmt = prepex(32, $db, 'SELECT id, label FROM test WHERE MATCH label AGAINST (:placeholder)', 160 array(':placeholder' => 'mysql')); 161 /* 162 Lets ignore this 163 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) 164 printf("[033] Expecting two rows, got %d rows\n", $tmp); 165 */ 166 } 167 prepex(34, $db, 'DELETE FROM test'); 168 prepex(35, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder), (2, :placeholder)', 169 array(':placeholder' => 'row')); 170/* 171 $stmt = prepex(36, $db, 'SELECT id, label FROM "test WHERE MATCH label AGAINST (:placeholder)', 172 array(':placeholder' => 'row'), 173 array('execute' => array('sqlstate' => '42000', 'mysql' => 1064))); 174*/ 175 $stmt = prepex(37, $db, 'SELECT id, label FROM \'test WHERE MATCH label AGAINST (:placeholder)', 176 array(':placeholder' => 'row'), 177 array('execute' => array('sqlstate' => '42000', 'mysql' => 1064))); 178 179 $stmt = prepex(38, $db, 'SELECT id, label AS "label" FROM test WHERE label = :placeholder', 180 array(':placeholder' => 'row')); 181 182 $sql = sprintf("SELECT id, label FROM test WHERE (label LIKE %s) AND (id = :placeholder)", 183 $db->quote('%ro%')); 184 $stmt = prepex(39, $db, $sql, array('placeholder' => -1)); 185 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0) 186 printf("[040] Expecting zero rows, got %d rows\n", $tmp); 187 188 189 $sql = sprintf("SELECT id, label FROM test WHERE (id = :placeholder) OR (label LIKE %s)", 190 $db->quote('%ro%')); 191 $stmt = prepex(41, $db, $sql, array('placeholder' => 1)); 192 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) 193 printf("[042] Expecting two rows, got %d rows\n", $tmp); 194 195 $sql = "SELECT id, label FROM test WHERE id = :placeholder AND label = (SELECT label AS 'SELECT' FROM test WHERE id = :placeholder)"; 196 $stmt = prepex(43, $db, $sql, array('placeholder' => 1)); 197 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 1) 198 printf("[044] Expecting onw row, got %d rows\n", $tmp); 199 200 // and now, the same with anonymous placeholders... 201 prepex(45, $db, 'DROP TABLE IF EXISTS test'); 202 prepex(46, $db, sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE)); 203 prepex(47, $db, "INSERT INTO test(id, label) VALUES(1, '?')"); 204 $stmt = prepex(48, $db, 'SELECT label FROM test'); 205 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 206 207 prepex(49, $db, 'DELETE FROM test'); 208 prepex(50, $db, "INSERT INTO test(id, label) VALUES(1, '?')", 209 array('first row')); 210 $stmt = prepex(51, $db, 'SELECT label FROM test'); 211 212 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 213 prepex(52, $db, 'DELETE FROM test'); 214 prepex(53, $db, 'INSERT INTO test(id, label) VALUES(1, ?)', 215 array('first row')); 216 prepex(54, $db, 'INSERT INTO test(id, label) VALUES(2, ?)', 217 array('second row')); 218 $stmt = prepex(55, $db, 'SELECT label FROM test'); 219 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 220 221 // Is PDO fun? 222 prepex(56, $db, 'SELECT label FROM test WHERE ? > 1', 223 array('id')); 224 prepex(57, $db, 'SELECT ? FROM test WHERE id > 1', 225 array('id')); 226 prepex(58, $db, 'SELECT ? FROM test WHERE ? > ?', 227 array('test'), array('execute' => array('sqlstate' => 'HY093'))); 228 229 prepex(59, $db, 'SELECT ? FROM test WHERE ? > ?', 230 array('id', 'label', 'value')); 231 232 for ($num_params = 2; $num_params < 100; $num_params++) { 233 $params = array('a'); 234 for ($i = 1; $i < $num_params; $i++) { 235 $params[] = 'some data'; 236 } 237 prepex(60, $db, 'SELECT id, label FROM test WHERE label > ?', 238 $params, array('execute' => array('sqlstate' => 'HY093'))); 239 } 240 241 prepex(61, $db, 'DELETE FROM test'); 242 prepex(62, $db, 'INSERT INTO test(id, label) VALUES (1, ?), (2, ?)', 243 array('row', 'row')); 244 $stmt = prepex(63, $db, 'SELECT id, label FROM test'); 245 var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); 246 247 $stmt = prepex(64, $db, 'SELECT id, label FROM test WHERE ? IS NOT NULL', 248 array(1)); 249 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) 250 printf("[065] '1' IS NOT NULL evaluates to true, expecting two rows, got %d rows\n", $tmp); 251 252 $stmt = prepex(66, $db, 'SELECT id, label FROM test WHERE ? IS NULL', 253 array(1)); 254 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0) 255 printf("[067] '1' IS NOT NULL evaluates to true, expecting zero rows, got %d rows\n", $tmp); 256 257 prepex(68, $db, 'DROP TABLE IF EXISTS test'); 258 prepex(69, $db, 'CREATE TABLE test(id INT, label CHAR(255)) ENGINE=MyISAM'); 259 if (is_object(prepex(70, $db, 'CREATE FULLTEXT INDEX idx1 ON test(label)'))) { 260 prepex(71, $db, 'INSERT INTO test(id, label) VALUES (1, ?)', 261 array('MySQL is the best database in the world!')); 262 prepex(72, $db, 'INSERT INTO test(id, label) VALUES (1, ?)', 263 array('If I have the freedom to choose, I would always go again for the MySQL Server')); 264 $stmt = prepex(73, $db, 'SELECT id, label FROM test WHERE MATCH label AGAINST (?)', 265 array('mysql')); 266 /* 267 Lets ignore that 268 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) 269 printf("[074] Expecting two rows, got %d rows\n", $tmp); 270 */ 271 } 272 273 prepex(74, $db, 'DELETE FROM test'); 274 prepex(75, $db, 'INSERT INTO test(id, label) VALUES (1, ?), (2, ?)', 275 array('row', 'row')); 276 277 $stmt = prepex(76, $db, 'SELECT id, label FROM "test WHERE MATCH label AGAINST (?)', 278 array('row'), 279 array('execute' => array('sqlstate' => '42000', 'mysql' => 1064))); 280 281 /* 282 TODO enable after fix 283 $stmt = prepex(37, $db, 'SELECT id, label FROM \'test WHERE MATCH label AGAINST (:placeholder)', 284 array(':placeholder' => 'row'), 285 array('execute' => array('sqlstate' => '42000', 'mysql' => 1064))); 286 */ 287 288 $stmt = prepex(78, $db, 'SELECT id, label AS "label" FROM test WHERE label = ?', 289 array('row')); 290 291 $sql = sprintf("SELECT id, label FROM test WHERE (label LIKE %s) AND (id = ?)", 292 $db->quote('%ro%')); 293 $stmt = prepex(79, $db, $sql, array(-1)); 294 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0) 295 printf("[080] Expecting zero rows, got %d rows\n", $tmp); 296 297 298 $sql = sprintf("SELECT id, label FROM test WHERE (id = ?) OR (label LIKE %s)", 299 $db->quote('%ro%')); 300 $stmt = prepex(81, $db, $sql, array(1)); 301 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) 302 printf("[082] Expecting two rows, got %d rows\n", $tmp); 303 304 $sql = "SELECT id, label FROM test WHERE id = ? AND label = (SELECT label AS 'SELECT' FROM test WHERE id = ?)"; 305 $stmt = prepex(83, $db, $sql, array(1, 1)); 306 if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 1) 307 printf("[084] Expecting one row, got %d rows\n", $tmp); 308 309 $sql = "SELECT id, label FROM test WHERE id = :placeholder AND label = (SELECT label AS 'SELECT' FROM test WHERE id = ?)"; 310 $stmt = prepex(85, $db, $sql, array(1, 1), array('execute' => array('sqlstate' => 'HY093'))); 311 if (is_object($stmt) && count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0) 312 printf("[086] Expecting no rows, got %d rows\n", $tmp); 313 314 } catch (PDOException $e) { 315 printf("[001] %s [%s] %s\n", 316 $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); 317 } 318 319 print "done!"; 320?> 321--CLEAN-- 322<?php 323require __DIR__ . '/mysql_pdo_test.inc'; 324$db = MySQLPDOTest::factory(); 325$db->exec('DROP TABLE IF EXISTS test'); 326?> 327--XFAIL-- 328PDO's PS parser has some problems with invalid SQL and crashes from time to time 329(check with valgrind...) 330--EXPECT-- 331array(1) { 332 ["one"]=> 333 string(1) "1" 334} 335array(1) { 336 [0]=> 337 array(1) { 338 ["label"]=> 339 string(12) ":placeholder" 340 } 341} 342array(1) { 343 [0]=> 344 array(1) { 345 ["label"]=> 346 string(12) ":placeholder" 347 } 348} 349array(2) { 350 [0]=> 351 array(1) { 352 ["label"]=> 353 string(9) "first row" 354 } 355 [1]=> 356 array(1) { 357 ["label"]=> 358 string(10) "second row" 359 } 360} 361array(2) { 362 [0]=> 363 array(2) { 364 ["id"]=> 365 string(1) "1" 366 ["label"]=> 367 string(3) "row" 368 } 369 [1]=> 370 array(2) { 371 ["id"]=> 372 string(1) "2" 373 ["label"]=> 374 string(3) "row" 375 } 376} 377array(1) { 378 [0]=> 379 array(1) { 380 ["label"]=> 381 string(1) "?" 382 } 383} 384array(1) { 385 [0]=> 386 array(1) { 387 ["label"]=> 388 string(1) "?" 389 } 390} 391array(2) { 392 [0]=> 393 array(1) { 394 ["label"]=> 395 string(9) "first row" 396 } 397 [1]=> 398 array(1) { 399 ["label"]=> 400 string(10) "second row" 401 } 402} 403array(2) { 404 [0]=> 405 array(2) { 406 ["id"]=> 407 string(1) "1" 408 ["label"]=> 409 string(3) "row" 410 } 411 [1]=> 412 array(2) { 413 ["id"]=> 414 string(1) "2" 415 ["label"]=> 416 string(3) "row" 417 } 418} 419done! 420