function try_buffer_size($offset, $buffer_size) { try { $dsn = MySQLPDOTest::getDSN(); $user = PDO_MYSQL_TEST_USER; $pass = PDO_MYSQL_TEST_PASS; /* unsigned overflow possible ? */ $db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MAX_BUFFER_SIZE => $buffer_size, PDO::MYSQL_ATTR_DIRECT_QUERY => 0, PDO::ATTR_EMULATE_PREPARES => 0)); $db->exec('DROP TABLE IF EXISTS test'); $db->exec(sprintf('CREATE TABLE test(id INT, val LONGBLOB) ENGINE = %s', PDO_MYSQL_TEST_ENGINE)); // 10 * (10 * 1024) = 10 * (10 * 1k) = 100k $db->exec('INSERT INTO test(id, val) VALUES (1, REPEAT("01234567890", 10240))'); $stmt = $db->prepare('SELECT id, val FROM test'); $stmt->execute(); $id = $val = NULL; $stmt->bindColumn(1, $id); $stmt->bindColumn(2, $val); while ($row = $stmt->fetch(PDO::FETCH_BOUND)) { printf("[%03d] id = %d, val = %s... (length: %d)\n", $offset, $id, substr($val, 0, 10), strlen($val)); } $db->exec('DROP TABLE IF EXISTS test'); } catch (PDOException $e) { printf("[%03d] %s, [%s] %s\n", $offset, $e->getMessage(), is_object($db) ? $db->errorCode() : 'n/a', is_object($db) ? implode(' ', $db->errorInfo()) : 'n/a'); } }
function test_type(&$db, $offset, $sql_type, $value, $ret_value = NULL, $pattern = NULL, $alternative_type = NULL) { $db->exec('DROP TABLE IF EXISTS test'); $sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine()); @$db->exec($sql); if ($db->errorCode() != 0) { // not all MySQL Server versions and/or engines might support the type return true; } $stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)'); $stmt->bindValue(1, $offset); $stmt->bindValue(2, $value); if (!$stmt->execute()) { printf("[%03d + 1] INSERT failed, %s\n", $offset, var_export($stmt->errorInfo(), true)); return false; } $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); $stmt = $db->query('SELECT id, label FROM test'); $row = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); if (!isset($row['id']) || !isset($row['label'])) { printf("[%03d + 2] Fetched result seems wrong, dumping result: %s\n", $offset, var_export($row, true)); return false; } if ($row['id'] != $offset) { printf("[%03d + 3] Expecting %s got %s\n", $offset, $row['id']); return false; } if (!is_null($pattern)) { if (!preg_match($pattern, $row['label'])) { printf("[%03d + 5] Value seems wrong, accepting pattern %s got %s, check manually\n", $offset, $pattern, var_export($row['label'], true)); return false; } } else { $exp = $value; if (!is_null($ret_value)) { // we expect a different return value than our input value // typically the difference is only the type $exp = $ret_value; } if ($row['label'] !== $exp && !is_null($alternative_type) && gettype($row['label']) != $alternative_type) { printf("[%03d + 4] %s - input = %s/%s, output = %s/%s (alternative type: %s)\n", $offset, $sql_type, var_export($exp, true), gettype($exp), var_export($row['label'], true), gettype($row['label']), $alternative_type); return false; } } $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true); $stmt = $db->query('SELECT id, label FROM test'); $row_string = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); if (is_null($pattern) && $row['label'] != $row_string['label']) { printf("%s - STRINGIGY = %s, NATIVE = %s\n", $sql_type, var_export($row_string['label'], true), var_export($row['label'], true)); return false; } else { if (!is_null($pattern) && !preg_match($pattern, $row_string['label'])) { printf("%s - STRINGIGY = %s, NATIVE = %s, pattern '%s'\n", $sql_type, var_export($row_string['label'], true), var_export($row['label'], true), $pattern); return false; } } return true; }
function pdo_mysql_stmt_bindparam_types_do($db, $offset, $native, $sql_type, $value) { if ($native) { $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0); } else { $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1); } $db->exec('DROP TABLE IF EXISTS test'); $sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine()); if (!($stmt = @$db->prepare($sql)) || !@$stmt->execute()) { // Server might not support column type - skip it return true; } $stmt = $db->prepare('INSERT INTO test(id, label) VALUES (1, ?)'); if (!$stmt->bindParam(1, $value)) { printf("[%03d/%s + 1] %s\n", $offset, $native ? 'native' : 'emulated', var_export($stmt->errorInfo(), true)); return false; } if (!$stmt->execute()) { printf("[%03d/%s + 2] %s\n", $offset, $native ? 'native' : 'emulated', var_export($stmt->errorInfo(), true)); return false; } $stmt = $db->query('SELECT id, label FROM test'); $id = $label = null; if (!$stmt->bindColumn(1, $id)) { printf("[%03d/%s + 3] %s\n", $offset, $native ? 'native' : 'emulated', var_export($stmt->errorInfo(), true)); return false; } if (!$stmt->bindColumn(2, $label)) { printf("[%03d/%s + 4] %s\n", $offset, $native ? 'native' : 'emulated', var_export($stmt->errorInfo(), true)); return false; } if (!$stmt->fetch(PDO::FETCH_BOUND)) { printf("[%03d/%s + 5] %s\n", $offset, $native ? 'native' : 'emulated', var_export($stmt->errorInfo(), true)); return false; } $stmt->closeCursor(); if ($label != $value) { printf("[%03d/%s + 6] Got %s expecting %s - plase check manually\n", $offset, $native ? 'native' : 'emulated', var_export($label, true), var_export($value, true)); // fall through } $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); if (empty($row)) { printf("[%03d/%s + 7] %s\n", $offset, $native ? 'native' : 'emulated', var_export($stmt->errorInfo(), true)); return false; } if ($row['label'] != $value) { printf("[%03d/%s + 8] Got %s expecting %s - plase check manually\n", $offset, $native ? 'native' : 'emulated', var_export($row['label'], true), var_export($value, true)); return false; } if ($row['label'] != $label) { printf("[%03d/%s + 9] Got %s from FETCH_ASSOC and %s from FETCH_BOUND- plase check manually\n", $offset, $native ? 'native' : 'emulated', var_export($row['label'], true), var_export($value, true)); return false; } $db->exec('DROP TABLE IF EXISTS test'); return true; }
function test_meta(&$db, $offset, $sql_type, $value, $native_type, $pdo_type) { $db->exec('DROP TABLE IF EXISTS test'); $sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine()); if (!($stmt = @$db->prepare($sql)) || !@$stmt->execute()) { // Some engines and/or MySQL server versions might not support the data type return true; } if (!$db->exec(sprintf("INSERT INTO test(id, label) VALUES (1, '%s')", $value))) { printf("[%03d] + 1] Insert failed, %d - %s\n", $offset, $db->errorCode(), var_export($db->errorInfo(), true)); return false; } $stmt = $db->prepare('SELECT id, label FROM test'); $stmt->execute(); $meta = $stmt->getColumnMeta(1); $row = $stmt->fetch(PDO::FETCH_ASSOC); if (empty($meta)) { printf("[%03d + 2] getColumnMeta() failed, %d - %s\n", $offset, $stmt->errorCode(), var_export($stmt->errorInfo(), true)); return false; } $elements = array('flags', 'table', 'name', 'len', 'precision', 'pdo_type'); foreach ($elements as $k => $element) { if (!isset($meta[$element])) { printf("[%03d + 3] Element %s missing, %s\n", $offset, $element, var_export($meta, true)); return false; } } if ($meta['table'] != 'test' || $meta['name'] != 'label') { printf("[%03d + 4] Table or field name is wrong, %s\n", $offset, var_export($meta, true)); return false; } if (!is_null($native_type)) { if (!isset($meta['native_type'])) { printf("[%03d + 5] Element native_type missing, %s\n", $offset, var_export($meta, true)); return false; } if (!is_array($native_type)) { $native_type = array($native_type); } $found = false; foreach ($native_type as $k => $type) { if ($meta['native_type'] == $type) { $found = true; break; } } if (!$found) { printf("[%03d + 6] Expecting native type %s, %s\n", $offset, var_export($native_type, true), var_export($meta, true)); return false; } } if (!is_null($pdo_type) && $meta['pdo_type'] != $pdo_type) { printf("[%03d + 6] Expecting PDO type %s got %s (%s)\n", $offset, $pdo_type, var_export($meta, true), var_export($meta['native_type'])); return false; } return true; }
function set_option_and_check($offset, $option, $value, $option_desc, $ignore_diff = false) { $dsn = MySQLPDOTest::getDSN(); $user = PDO_MYSQL_TEST_USER; $pass = PDO_MYSQL_TEST_PASS; try { $db = new PDO($dsn, $user, $pass, array($option => $value)); if (!is_object($db) || !$ignore_diff && $value !== ($tmp = @$db->getAttribute($option))) { printf("[%03d] Execting '%s'/%s got '%s'/%s' for options '%s'\n", $offset, $value, gettype($value), $tmp, gettype($tmp), $option_desc); } } catch (PDOException $e) { printf("[%03d] %s\n", $offset, $e->getMessage()); } }
function pdo_mysql_errorinfo($db, $offset) { try { /* If you create a PDOStatement object through PDO->prepare() or PDO->query() and invoke an error on the statement handle, PDO->errorCode() will not reflect that error. You must call PDOStatement->errorCode() to return the error code for an operation performed on a particular statement handle. */ $code = $db->errorCode(); check_error($offset + 2, $db); $stmt = $db->query('SELECT id, label FROM test'); $stmt2 =& $stmt; check_error($offset + 3, $db); check_error($offset + 4, $stmt); $db->exec('DROP TABLE IF EXISTS test'); @$stmt->execute(); check_error($offset + 5, $db); check_error($offset + 6, $stmt, '42S02'); check_error($offset + 7, $stmt2, '42S02'); @($stmt = $db->query('SELECT id, label FROM unknown')); check_error($offset + 8, $db, '42S02'); MySQLPDOTest::createTestTable($db); $stmt = $db->query('SELECT id, label FROM test'); check_error($offset + 9, $db); check_error($offset + 10, $stmt); $db2 =& $db; $db->exec('DROP TABLE IF EXISTS unknown'); @$db->query('SELECT id, label FROM unknown'); check_error($offset + 11, $db, '42S02'); check_error($offset + 12, $db2, '42S02'); check_error($offset + 13, $stmt); check_error($offset + 14, $stmt2); // lets hope this is an invalid attribute code $invalid_attr = -1 * PHP_INT_MAX + 3; $tmp = @$db->getAttribute($invalid_attr); check_error($offset + 15, $db, 'IM001'); check_error($offset + 16, $db2, 'IM001'); check_error($offset + 17, $stmt); check_error($offset + 18, $stmt2); } catch (PDOException $e) { printf("[%03d] %s [%s] %s\n", $offset + 19, $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); } }
function test_type(&$db, $offset, $sql_type, $value, $ret_value = NULL, $pattern = NULL) { $db->exec('DROP TABLE IF EXISTS test'); $sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine()); @$db->exec($sql); if ($db->errorCode() != 0) { // not all MySQL Server versions and/or engines might support the type return true; } $stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)'); $stmt->bindValue(1, $offset); $stmt->bindValue(2, $value); if (!$stmt->execute()) { printf("[%03d + 1] INSERT failed, %s\n", $offset, var_export($stmt->errorInfo(), true)); return false; } $stmt = $db->query('SELECT id, label FROM test'); $row = $stmt->fetch(PDO::FETCH_ASSOC); var_dump($row); var_dump($value); return true; }
<?php require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; /* Connect to mysql to determine the current charset so we can diffinate it */ $link = MySQLPDOTest::factory(); $charset = $link->query("SHOW VARIABLES LIKE 'character_set_connection'")->fetchObject()->value; /* Make sure that we don't attempt to set the current character set to make this case useful */ $new_charset = $charset == 'latin1' ? 'ascii' : 'latin1'; /* Done with the original connection, create a second link to test the character set being defined */ unset($link); $link = MySQLPDOTest::factory('PDO', false, null, array('charset' => $new_charset)); $conn_charset = $link->query("SHOW VARIABLES LIKE 'character_set_connection'")->fetchObject()->value; if ($charset !== $conn_charset) { echo "done!\n"; } else { echo "failed!\n"; }
set_and_get(6, $db, PDO::MYSQL_ATTR_LOCAL_INFILE, 0); set_and_get(7, $db, PDO::MYSQL_ATTR_LOCAL_INFILE, -1); $tmp = array(); set_and_get(8, $db, PDO::MYSQL_ATTR_LOCAL_INFILE, $tmp); set_and_get(9, $db, PPDO::MYSQL_ATTR_INIT_COMMAND, ''); set_and_get(10, $db, PPDO::MYSQL_ATTR_INIT_COMMAND, 'SOME SQL'); set_and_get(11, $db, PPDO::MYSQL_ATTR_INIT_COMMAND, -1); */ /* PDO::MYSQL_ATTR_READ_DEFAULT_FILE (integer) Read options from the named option file instead of from my.cnf. PDO::MYSQL_ATTR_READ_DEFAULT_GROUP (integer) Read options from the named group from my.cnf or the file specified with MYSQL_READ_DEFAULT_FILE. PDO::MYSQL_ATTR_MAX_BUFFER_SIZE (integer) Maximum buffer size. Defaults to 1 MiB. PDO::MYSQL_ATTR_DIRECT_QUERY (integer) Perform direct queries, don't use prepared statements. */ /* TODO - read only PDO::ATTR_CONNECTION_STATUS PDO::ATTR_SERVER_INFO */ print "done!"; require dirname(__FILE__) . '/mysql_pdo_test.inc'; MySQLPDOTest::dropTestTable();
<?php require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $db = MySQLPDOTest::factory(); MySQLPDOTest::createTestTable($db); printf("Testing native PS...\n"); try { $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0); if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY)) { printf("[002] Unable to turn off emulated prepared statements\n"); } printf("Binding variable...\n"); $stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2'); $in = 0; if (!$stmt->bindValue(1, $in)) { printf("[003] Cannot bind value, %s %s\n", $stmt->errorCode(), var_export($stmt->errorInfo(), true)); } $stmt->execute(); $id = $label = null; if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) { printf("[004] Cannot bind integer column, %s %s\n", $stmt->errorCode(), var_export($stmt->errorInfo(), true)); } if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR)) { printf("[005] Cannot bind string column, %s %s\n", $stmt->errorCode(), var_export($stmt->errorInfo(), true)); } while ($stmt->fetch(PDO::FETCH_BOUND)) { printf("in = %d -> id = %s (%s) / label = %s (%s)\n", $in, var_export($id, true), gettype($id), var_export($label, true), gettype($label)); } printf("Binding value and not variable...\n"); if (!$stmt->bindValue(1, 0)) { printf("[006] Cannot bind value, %s %s\n", $stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2) printf("[074] Expecting two rows, got %d rows\n", $tmp); */ } prepex(57, $db, 'DELETE FROM test'); prepex(58, $db, 'INSERT INTO test(id, label) VALUES (1, ?), (2, ?)', array('row1', 'row2')); /* TODO enable after fix $stmt = prepex(37, $db, 'SELECT id, label FROM \'test WHERE MATCH label AGAINST (:placeholder)', array(':placeholder' => 'row'), array('execute' => array('sqlstate' => '42000', 'mysql' => 1064))); */ $stmt = prepex(59, $db, 'SELECT id, label AS "label" FROM test WHERE label = ?', array('row1')); $tmp = $stmt->fetchAll(PDO::FETCH_ASSOC); $exp = array(0 => array("id" => "1", "label" => "row1")); if (MySQLPDOTest::isPDOMySQLnd()) { // mysqlnd returns native types $exp[0]['id'] = 1; } if ($tmp !== $exp) { printf("[065] Results seem wrong. Please check dumps manually.\n"); var_dump($exp); var_dump($tmp); } $sql = sprintf("SELECT id, label FROM test WHERE (label LIKE %s) AND (id = ?)", $db->quote('%ro%')); $stmt = prepex(60, $db, $sql, array(-1)); if (count($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC)) != 0) { printf("[061] Expecting zero rows, got %d rows\n", $tmp); } $sql = sprintf("SELECT id, label FROM test WHERE (id = ?) OR (label LIKE %s)", $db->quote('%ro%')); $stmt = prepex(61, $db, $sql, array(1));
if (!$db->query('SET autocommit = 0')) { printf("[007] Cannot turn off server autocommit mode, %s\n", var_export($db->errorInfo(), true)); } if (!$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1)) { printf("[008] Cannot turn on autocommit\n"); } $row = $db->query('SELECT @@autocommit AS _autocommit')->fetch(PDO::FETCH_ASSOC); if (!$row['_autocommit']) { printf("[009] Server autocommit mode should be on, got '%s'\n", var_export($row['_autocommit'])); } if (1 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT))) { printf("[010] Expecting int/1 got %s\n", var_export($tmp, true)); } if (MySQLPDOTest::detect_transactional_mysql_engine($db)) { // nice, we have a transactional engine to play with MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db)); $row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC); $num = $row['_num']; $db->query("INSERT INTO test(id, label) VALUES (100, 'z')"); $num++; $row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC); if ($row['_num'] != $num) { printf("[011] Insert has failed, test will fail\n"); } // autocommit is on, no rollback possible $db->query('ROLLBACK'); $row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC); if ($row['_num'] != $num) { printf("[012] ROLLBACK should not have undone anything\n"); } if (!$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 0)) {
function pdo_mysql_stmt_closecursor($db) { // This one should fail. I let it fail to prove that closeCursor() makes a difference. // If no error messages gets printed do not know if proper usage of closeCursor() makes any // difference or not. That's why we need to cause an error here. $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC'); // query() shall fail! $stmt2 = $db->query('SELECT id, label FROM test ORDER BY id ASC'); $stmt1->closeCursor(); // This is proper usage of closeCursor(). It shall prevent any further error messages. if (MySQLPDOTest::isPDOMySQLnd()) { $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC'); } else { // see pdo_mysql_stmt_unbuffered_2050.phpt for an explanation unset($stmt1); $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC'); } // fetch only the first rows and let closeCursor() clean up $row1 = $stmt1->fetch(PDO::FETCH_ASSOC); $stmt1->closeCursor(); $stmt2 = $db->prepare('UPDATE test SET label = ? WHERE id = ?'); $stmt2->bindValue(1, "z"); $stmt2->bindValue(2, $row1['id']); $stmt2->execute(); $stmt2->closeCursor(); $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); // check if changing the fetch mode from unbuffered to buffered will // cause any harm to a statement created prior to the change $stmt1->execute(); $row2 = $stmt1->fetch(PDO::FETCH_ASSOC); $stmt1->closeCursor(); if (!isset($row2['label']) || 'z' !== $row2['label']) { printf("Expecting array(id => 1, label => z) got %s\n", var_export($row2, true)); } unset($stmt1); $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC'); // should work $stmt2 = $db->query('SELECT id, label FROM test ORDER BY id ASC'); $stmt1->closeCursor(); $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC'); // fetch only the first rows and let closeCursor() clean up $row3 = $stmt1->fetch(PDO::FETCH_ASSOC); $stmt1->closeCursor(); assert($row3 == $row2); $stmt2 = $db->prepare('UPDATE test SET label = ? WHERE id = ?'); $stmt2->bindValue(1, "a"); $stmt2->bindValue(2, $row1['id']); $stmt2->execute(); $stmt2->closeCursor(); $stmt1->execute(); $row4 = $stmt1->fetch(PDO::FETCH_ASSOC); $stmt1->closeCursor(); assert($row4 == $row1); $offset = 0; $stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2'); $in = 0; if (!$stmt->bindParam(1, $in)) { printf("[%03d + 1] Cannot bind parameter, %s %s\n", $offset, $stmt->errorCode(), var_export($stmt->errorInfo(), true)); } $stmt->execute(); $id = $label = null; if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) { printf("[%03d + 2] Cannot bind integer column, %s %s\n", $offset, $stmt->errorCode(), var_export($stmt->errorInfo(), true)); } if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR)) { printf("[%03d + 3] Cannot bind string column, %s %s\n", $offset, $stmt->errorCode(), var_export($stmt->errorInfo(), true)); } while ($stmt->fetch(PDO::FETCH_BOUND)) { printf("in = %d -> id = %s (%s) / label = %s (%s)\n", $in, var_export($id, true), gettype($id), var_export($label, true), gettype($label)); } $stmt->closeCursor(); $stmt->execute(); }
public function serialize() { printf("%s()\n", __METHOD__); return 'Data from serialize'; } public function unserialize($data) { printf("%s(%s)\n", __METHOD__, var_export($data, true)); } } $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0); if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY)) { printf("[002] Unable to turn off emulated prepared statements\n"); } $db->exec('DROP TABLE IF EXISTS test'); $db->exec(sprintf('CREATE TABLE test(id INT, myobj BLOB) ENGINE=%s', MySQLPDOTest::getTableEngine())); printf("Creating an object, serializing it and writing it to DB...\n"); $id = 1; $obj = myclass::singleton('Creating object'); $myobj = serialize($obj); $stmt = $db->prepare('INSERT INTO test(id, myobj) VALUES (?, ?)'); $stmt->bindValue(1, $id); $stmt->bindValue(2, $myobj); $stmt->execute(); printf("\nUnserializing the previously serialized object...\n"); var_dump(unserialize($myobj)); printf("\nUsing PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE to fetch the object from DB and unserialize it...\n"); $stmt = $db->prepare('SELECT myobj FROM test'); $stmt->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_SERIALIZE, 'myclass', array('PDO shall not call __construct()')); $stmt->execute(); var_dump($stmt->fetch());
<?php if (getenv('REDIR_TEST_DIR') === false) { putenv('REDIR_TEST_DIR=' . dirname(__FILE__) . '/../../pdo/tests/'); } require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; $db = PDOTest::factory(); if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') { require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $suf = ' ENGINE=' . MySQLPDOTest::detect_transactional_mysql_engine($db); } else { $suf = ''; } $db->exec('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, val VARCHAR(10))' . $suf); $db->exec("INSERT INTO test VALUES(1, 'A')"); $db->exec("INSERT INTO test VALUES(2, 'B')"); $db->exec("INSERT INTO test VALUES(3, 'C')"); $delete = $db->prepare('DELETE FROM test'); function countRows($action) { global $db; $select = $db->prepare('SELECT COUNT(*) FROM test'); $select->execute(); $res = $select->fetchColumn(); return "Counted {$res} rows after {$action}.\n"; } echo countRows('insert'); $db->beginTransaction(); $delete->execute(); echo countRows('delete'); $db->rollBack();
if (1 === $db->getAttribute(PDO::ATTR_AUTOCOMMIT)) { printf("[028] I'm confused, how can autocommit be on? Didn't I say I want to manually control transactions?\n"); } if (!$db->beginTransaction()) { printf("[029] Cannot start a transaction, [%d] %s\n", $db->errorCode(), implode(' ', $db->errorInfo())); } try { if (false !== $db->beginTransaction()) { printf("[030] No false and no exception - that's wrong.\n"); } } catch (PDOException $e) { assert($e->getMessage() != ''); } // TODO: What about an engine that does not support transactions? $db = MySQLPDOTest::factory(); MySQLPDOTest::createTestTable($db, 'MyISAM'); if (false == $db->beginTransaction()) { printf("[031] Cannot start a transaction, [%s] [%s]\n", $db->errorCode(), implode(' ', $db->errorInfo())); } if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT)) { printf("[032] Autocommit should be on my default, beginTransaction() should not change that\n"); } if (0 == $db->exec('DELETE FROM test')) { printf("[033] No rows deleted, can't be true.\n"); } if (!$db->commit()) { printf("[034] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo())); } if (false == $db->beginTransaction()) { printf("[035] Cannot start a transaction, [%s] [%s]\n", $db->errorCode(), implode(' ', $db->errorInfo())); }
<?php require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $found = false; $values = ini_get_all(); foreach ($values as $name => $dsn) { if ('pdo.dsn.mysql' == $name) { printf("pdo.dsn.mysql=%s\n", $dsn); $found = true; break; } } if (!$found) { $dsn = ini_get('pdo.dsn.mysql'); $found = $dsn !== false; } if (!$found) { printf("pdo.dsn.mysql cannot be accessed through ini_get_all()/ini_get()\n"); } if (MySQLPDOTest::getDSN() == $dsn) { // we are lucky, we can run the test try { $user = PDO_MYSQL_TEST_USER; $pass = PDO_MYSQL_TEST_PASS; $db = new PDO('mysql', $user, $pass); } catch (PDOException $e) { printf("[001] %s, [%s] %s\n", $e->getMessage(), is_object($db) ? $db->errorCode() : 'n/a', is_object($db) ? implode(' ', $db->errorInfo()) : 'n/a'); } } print "done!";
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $expected = array('MYSQL_ATTR_USE_BUFFERED_QUERY' => true, 'MYSQL_ATTR_LOCAL_INFILE' => true, 'MYSQL_ATTR_DIRECT_QUERY' => true, 'MYSQL_ATTR_FOUND_ROWS' => true, 'MYSQL_ATTR_IGNORE_SPACE' => true, 'MYSQL_ATTR_INIT_COMMAND' => true, "MYSQL_ATTR_SSL_KEY" => true, "MYSQL_ATTR_SSL_CERT" => true, "MYSQL_ATTR_SSL_CA" => true, "MYSQL_ATTR_SSL_CAPATH" => true, "MYSQL_ATTR_SSL_CIPHER" => true, "MYSQL_ATTR_COMPRESS" => true); if (!MySQLPDOTest::isPDOMySQLnd()) { $expected['MYSQL_ATTR_MAX_BUFFER_SIZE'] = true; $expected['MYSQL_ATTR_READ_DEFAULT_FILE'] = true; $expected['MYSQL_ATTR_READ_DEFAULT_GROUP'] = true; } if (extension_loaded('mysqlnd')) { $expected['MYSQL_ATTR_SERVER_PUBLIC_KEY'] = true; } else { if (extension_loaded('mysqli')) { if (mysqli_get_client_version() > 50605) { $expected['MYSQL_ATTR_SERVER_PUBLIC_KEY'] = true; } } else { if (MySQLPDOTest::getClientVersion(MySQLPDOTest::factory()) > 50605) { /* XXX the MySQL client library version isn't exposed with any constants, the single possibility is to use the PDO::getAttribute(). This however will fail with no connection. */ $expected['MYSQL_ATTR_SERVER_PUBLIC_KEY'] = true; } } } /* TODO MYSQLI_OPT_CONNECT_TIMEOUT != PDO::ATTR_TIMEOUT (integer) Sets the timeout value in seconds for communications with the database. ^ Potential BUG, PDO::ATTR_TIMEOUT is used in pdo_mysql_handle_factory MYSQLI_SET_CHARSET_NAME -> DSN/charset=<charset_name>
<?php require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $pdo = MySQLPDOTest::factory(); $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $attrs = array(PDO::ATTR_EMULATE_PREPARES => array(null, 1, 0), PDO::MYSQL_ATTR_DIRECT_QUERY => array(null, 0, 1), PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => array(null, 0, 1), PDO::ATTR_AUTOCOMMIT => array(null), PDO::ATTR_PREFETCH => array(null), PDO::ATTR_TIMEOUT => array(null), PDO::ATTR_ERRMODE => array(null), PDO::ATTR_SERVER_VERSION => array(null), PDO::ATTR_CLIENT_VERSION => array(null), PDO::ATTR_SERVER_INFO => array(null), PDO::ATTR_CONNECTION_STATUS => array(null), PDO::ATTR_CASE => array(null), PDO::ATTR_CURSOR_NAME => array(null), PDO::ATTR_CURSOR => array(null), PDO::ATTR_ORACLE_NULLS => array(null), PDO::ATTR_PERSISTENT => array(null), PDO::ATTR_STATEMENT_CLASS => array(null), PDO::ATTR_FETCH_TABLE_NAMES => array(null), PDO::ATTR_FETCH_CATALOG_NAMES => array(null), PDO::ATTR_DRIVER_NAME => array(null), PDO::ATTR_STRINGIFY_FETCHES => array(null), PDO::ATTR_MAX_COLUMN_LEN => array(null), PDO::ATTR_DEFAULT_FETCH_MODE => array(null)); foreach ($attrs as $a => $vals) { foreach ($vals as $v) { try { if (!isset($v)) { var_dump($pdo->getAttribute($a)); } else { $pdo->setAttribute($a, $v); if ($pdo->getAttribute($a) === $v) { echo "OK\n"; } else { throw new \Exception('KO'); } } } catch (\Exception $e) { if ($e->getCode() == 'IM001') { echo "ERR\n"; } else { echo "ERR {$e->getMessage()}\n"; } } } }
} $stmt2 = $db->query('SELECT id, label FROM test WHERE id = 1'); $row = $stmt2->fetch(PDO::FETCH_ASSOC); if ($row['label'] != $blob) { printf("[%03d + 10] INSERT and/or SELECT has failed, dumping data.\n", $offset); var_dump($row); var_dump($blob); return false; } return true; } $db = MySQLPDOTest::factory(); $blob = 'I am a mighty BLOB!' . chr(0) . "I am a binary thingie!"; $tmp = MySQLPDOTest::getTempDir(); $file = $tmp . DIRECTORY_SEPARATOR . 'pdoblob.tst'; try { printf("Emulated PS...\n"); $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1); blob_from_stream(10, $db, $file, $blob); printf("Native PS...\n"); $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0); blob_from_stream(30, $db, $file, $blob); } catch (PDOException $e) { printf("[001] %s [%s] %s\n", $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); } print "done!"; require dirname(__FILE__) . '/mysql_pdo_test.inc'; $db = MySQLPDOTest::factory(); $db->exec('DROP TABLE IF EXISTS test'); @unlink(MySQLPDOTest::getTempDir() . DIRECTORY_SEPARATOR . 'pdoblob.tst');
if (!isset($rows[0]['label']) || $rows[0]['label'] != 'z') { printf("[006] Record data is strange, dumping rows\n"); var_dump($rows); } // Ok, lets check MyISAM resp. any other non-transactional engine // pdo_mysql_begin_transaction has more on this, quick check only $db = MySQLPDOTest::factory(); MySQLPDOTest::createTestTable($db, 'MyISAM'); if (true !== ($tmp = $db->beginTransaction())) { printf("[007] Expecting true, got %s/%s\n", gettype($tmp), $tmp); } $db->exec("INSERT INTO test(id, label) VALUES (100, 'z')"); if (true !== ($tmp = $db->commit())) { printf("[008] No commit allowed? [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo())); } // a weak test without unicode etc. - lets leave that to dedicated tests $stmt = $db->query('SELECT id, label FROM test WHERE id = 100'); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!isset($rows[0]['label']) || $rows[0]['label'] != 'z') { printf("[009] Record data is strange, dumping rows\n"); var_dump($rows); } } catch (PDOException $e) { printf("[002] %s, [%s] %s\n", $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); } print "done!"; require dirname(__FILE__) . '/mysql_pdo_test.inc'; $db = MySQLPDOTest::factory(); $db->exec('DROP TABLE IF EXISTS test_commit'); MySQLPDOTest::dropTestTable($db);
exec_and_count(11, $db, "REPLACE INTO test(id, col1) VALUES (6, 'g')", 1); exec_and_count(12, $db, 'DELETE FROM test WHERE id > 2', 4); exec_and_count(13, $db, 'DROP TABLE test', 0); exec_and_count(14, $db, 'SET @myvar = 1', 0); exec_and_count(15, $db, 'THIS IS NOT VALID SQL, I HOPE', false); printf("[016] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo())); exec_and_count(36, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0); exec_and_count(37, $db, "INSERT INTO test(id, col1) VALUES (1, 'a')", 1); // Results may vary. Typically you will get 1. But the MySQL 5.1 manual states: Truncation operations do not return the number of deleted rows. // Don't rely on any return value! exec_and_count(38, $db, 'TRUNCATE TABLE test', NULL); } catch (PDOException $e) { printf("[001] %s, [%s] %s\n", $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); } /* CREATE, DROP, CALL SP and SF */ if (MySQLPDOTest::getServerVersion($db) > 50000) { // let's try to play with stored procedures try { $ignore_exception = true; exec_and_count(18, $db, 'DROP PROCEDURE IF EXISTS p', 0); exec_and_count(19, $db, 'CREATE PROCEDURE p(OUT ver_param VARCHAR(255)) BEGIN SELECT VERSION() INTO ver_param; END;', 0); // we got this far without problems. If there's an issue from now on, its a failure $ignore_exception = false; exec_and_count(20, $db, 'CALL p(@version)', 0); $stmt = $db->query('SELECT @version AS p_version'); $tmp = $stmt->fetchAll(PDO::FETCH_ASSOC); if (count($tmp) > 1 || !isset($tmp[0]['p_version'])) { printf("[022] Data seems wrong, dumping\n"); var_dump($tmp); } else { $p_version = $tmp[0]['p_version'];
} return true; } require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; putenv('PDOTEST_ATTR=' . serialize([PDO::MYSQL_ATTR_LOCAL_INFILE => true])); $db = MySQLPDOTest::factory(); MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db)); /* affected rows related */ try { exec_and_count(2, $db, 'DROP TABLE IF EXISTS test', 0); exec_and_count(3, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0); $stmt = $db->query("SHOW VARIABLES LIKE 'secure_file_priv'"); if (($row = $stmt->fetch(PDO::FETCH_ASSOC)) && $row['value'] != '') { $filename = $row['value'] . DIRECTORY_SEPARATOR . "pdo_mysql_exec_load_data.csv"; } else { $filename = MySQLPDOTest::getTempDir() . DIRECTORY_SEPARATOR . "pdo_mysql_exec_load_data.csv"; } $fp = fopen($filename, "w"); fwrite($fp, "1;foo\n"); fwrite($fp, "2;bar"); fclose($fp); $sql = sprintf("LOAD DATA LOCAL INFILE %s INTO TABLE test FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n'", $db->quote($filename)); if (exec_and_count(4, $db, $sql, 2)) { $stmt = $db->query('SELECT id, col1 FROM test ORDER BY id ASC'); $expected = array(array("id" => 1, "col1" => "foo"), array("id" => 2, "col1" => "bar")); $ret = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($expected as $offset => $exp) { foreach ($exp as $key => $value) { if ($ret[$offset][$key] != $value) { printf("Results seem wrong, check manually\n"); var_dump($ret);
<?php require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $dsn = MySQLPDOTest::getDSN(); $user = PDO_MYSQL_TEST_USER; $pass = PDO_MYSQL_TEST_PASS; $table = sprintf("test_%s", md5(mt_rand(0, PHP_INT_MAX))); $db = new PDO($dsn, $user, $pass); $db->exec(sprintf('DROP TABLE IF EXISTS %s', $table)); $create = sprintf('CREATE TABLE %s(id INT)', $table); var_dump($create); $db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => $create)); $info = $db->errorInfo(); var_dump($info[0]); $db->exec(sprintf('INSERT INTO %s(id) VALUES (1)', $table)); $stmt = $db->query(sprintf('SELECT id FROM %s', $table)); var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); $db->exec(sprintf('DROP TABLE IF EXISTS %s', $table)); print "done!";
$have_latin2 = empty($tmp) ? false : true; if ($have_latin1 && $have_latin2) { // very likely we do have both of them... try { $dsn = MySQLPDOTest::getDSN(array('charset' => 'latin1')); $db = new PDO($dsn, $user, $pass); $stmt = $db->query('SELECT @@character_set_connection AS _charset'); $tmp = $stmt->fetch(PDO::FETCH_ASSOC); if ($tmp['_charset'] != 'latin1') { printf("[031] DSN = %s, Character sets has not been set, @@character_set_connection reports '%s', expecting '%s'", $dsn, $tmp['_charset'], 'latin1'); } } catch (PDOException $e) { printf("[032] %s\n", $e->getMessage()); } try { $dsn = MySQLPDOTest::getDSN(array('charset' => 'latin2')); $db = new PDO($dsn, $user, $pass); $stmt = $db->query('SELECT @@character_set_connection AS _charset'); $tmp = $stmt->fetch(PDO::FETCH_ASSOC); if ($tmp['_charset'] != 'latin2') { printf("[033] DSN = %s, character sets has not been set, @@character_set_connection reports '%s', expecting '%s'", $dsn, $tmp['_charset'], 'latin2'); } } catch (PDOException $e) { printf("[034] %s\n", $e->getMessage()); } } } } catch (PDOException $e) { printf("[001] %s, [%s] %s\n", $e->getMessage(), is_object($db) ? $db->errorCode() : 'n/a', is_object($db) ? implode(' ', $db->errorInfo()) : 'n/a'); } print "done!";
<?php require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $db = MySQLPDOTest::factory(); function fetch($offset, &$db, $query, $expect = null) { try { $stmt = $db->query('SELECT 1'); $num = $stmt->fetch(PDO::FETCH_NUM); $stmt = $db->query('SELECT 1'); $assoc = $stmt->fetch(PDO::FETCH_ASSOC); $stmt = $db->query('SELECT 1'); $both = $stmt->fetch(PDO::FETCH_BOTH); $computed_both = array_merge($num, $assoc); if ($computed_both != $both) { printf("[%03d] Suspicious FETCH_BOTH result, dumping\n", $offset); var_dump($computed_both); var_dump($both); } if (!is_null($expect) && $expect != $both) { printf("[%03d] Expected differs from returned data, dumping\n", $offset); var_dump($expect); var_dump($both); } } catch (PDOException $e) { printf("[%03d] %s, [%s] %s\n", $offset, $e->getMessage(), $db->errroCode(), implode(' ', $db->errorInfo())); } } try { fetch(2, $db, 'SELECT 1', array(0 => '1', '1' => '1')); } catch (PDOException $e) {
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)'); $stmt->bindParam(1, $id); $stmt->bindParam(2, $blob); if (true !== $stmt->execute()) { printf("[%03d + 9] %s\n", $offset, var_export($stmt->errorInfo(), true)); } $stmt2 = $db->query('SELECT id, label FROM test WHERE id = 1'); $row = $stmt2->fetch(PDO::FETCH_ASSOC); if ($row['label'] != $blob) { printf("[%03d + 10] INSERT and/or SELECT has failed, dumping data.\n", $offset); var_dump($row); var_dump($blob); return false; } return true; } $db = MySQLPDOTest::factory(); $blob = 'I am a mighty BLOB!' . chr(0) . "I am a binary thingie!"; $tmp = MySQLPDOTest::getTempDir(); $file = $tmp . DIRECTORY_SEPARATOR . 'pdoblob.tst'; try { printf("Emulated PS...\n"); $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1); blob_from_stream(10, $db, $file, $blob); printf("Native PS...\n"); $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0); blob_from_stream(30, $db, $file, $blob); } catch (PDOException $e) { printf("[001] %s [%s] %s\n", $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); } print "done!";