diff options
author | Davey Shafik <me@daveyshafik.com> | 2015-12-06 23:38:45 -0500 |
---|---|---|
committer | Davey Shafik <me@daveyshafik.com> | 2015-12-06 23:38:45 -0500 |
commit | 5f20827302d32a08cfcafe3b0cc9be0dc0a1c14c (patch) | |
tree | 69dfaf670fe3c8d754a98c602b3edec83c107dac | |
parent | 5e627ae629712983518ce836ae5e1766fc5b536e (diff) | |
download | php7-mysql-shim-5f20827302d32a08cfcafe3b0cc9be0dc0a1c14c.zip php7-mysql-shim-5f20827302d32a08cfcafe3b0cc9be0dc0a1c14c.tar.gz php7-mysql-shim-5f20827302d32a08cfcafe3b0cc9be0dc0a1c14c.tar.bz2 |
Add more tests and fixes
-rw-r--r-- | lib/mysql.php | 269 | ||||
-rw-r--r-- | tests/MySqlShimTest.php | 274 |
2 files changed, 377 insertions, 166 deletions
diff --git a/lib/mysql.php b/lib/mysql.php index 693799b..af92240 100644 --- a/lib/mysql.php +++ b/lib/mysql.php @@ -154,15 +154,19 @@ namespace { { $link = \Dshafik\MySQL::getConnection($link); $result = mysql_query( - "SHOW FULL COLUMNS FROM " . + "SHOW COLUMNS FROM " . mysqli_real_escape_string($link, $databaseName) . "." . mysqli_real_escape_string($link, $tableName), $link ); + if ($result instanceof \mysqli_result) { $result->table = $tableName; + return $result; } - return $result; + + trigger_error("mysql_list_fields(): Unable to save MySQL query result", E_USER_WARNING); + return false; } function mysql_list_processes(\mysqli $link = null) @@ -193,18 +197,51 @@ namespace { function mysql_result(\mysqli_result $result, $row, $field = 0) { if (!mysqli_data_seek($result, $row)) { + trigger_error( + sprintf( + "mysql_result(): Unable to jump to row %d on MySQL result index %s", + $row, + spl_object_hash($result) + ), + E_USER_WARNING + ); + // @codeCoverageIgnoreStart return false; + // @codeCoverageIgnoreEnd } - if ($row = mysqli_fetch_array($result) === false) { - return false; + $found = true; + if (strpos($field, ".") !== false) { + list($table, $name) = explode(".", $field); + $i = 0; + $found = false; + while ($column = mysqli_fetch_field($result)) { + if ($column->table == $table && $column->name == $name) { + $field = $i; + $found = true; + break; + } + $i++; + } } - if (isset($row[$field])) { + $row = mysql_fetch_array($result); + if ($found && isset($row[$field])) { return $row[$field]; } + trigger_error( + sprintf( + "%s(): %s not found in MySQL result index %s", + __FUNCTION__, + $field, + spl_object_hash($result) + ), + E_USER_WARNING + ); + // @codeCoverageIgnoreStart return false; + // @codeCoverageIgnoreEnd } function mysql_num_rows(\mysqli_result $result) @@ -322,7 +359,7 @@ namespace { if (\Dshafik\MySQL::checkValidResult($result, __FUNCTION__)) { return false; } - return \Dshafik\MySQL::mysqlFieldInfo($result, $field, 'length'); + return \Dshafik\MySQL::mysqlFieldInfo($result, $field, 'len'); } function mysql_field_type($result, $field) @@ -518,10 +555,13 @@ namespace Dshafik { public static function mysqlFieldInfo(\mysqli_result $result, $field, $what) { - if (!\mysqli_data_seek($result, $field)) { + try { + $field = mysqli_fetch_field_direct($result, $field); + } catch (\Exception $e) { trigger_error( sprintf( - "mysql_field_name(): Field %d is invalid for MySQL result index %s", + "mysql_field_%s(): Field %d is invalid for MySQL result index %s", + $what, $field, spl_object_hash($result) ), @@ -533,60 +573,20 @@ namespace Dshafik { // @codeCoverageIgnoreEnd } - $field = \mysql_fetch_assoc($result); - - switch ($what) { - case "name": - return $field['Field']; - case "table": - return $result->table; - case "length": - case "type": - $matches = []; - preg_match("/(?<type>[a-z]+)(?:\((?<length>.+)\))?/", $field['Type'], $matches); - if (!isset($matches[$what])) { - $matches[$what] = null; - } - if ($what == 'length') { - return static::getFieldLength($matches[$what], $field['Type']); - } - return static::getFieldType($matches[$what]); - case "flags": - $flags = []; - if ($field['Null'] == "NO") { - $flags[] = "not_null"; - } - - if ($field['Key'] == 'PRI') { - $flags[] = "primary_key"; - } - - if (strpos($field['Extra'], "auto_increment") !== false) { - $flags[] = "auto_increment"; - } - - if ($field['Key'] == 'UNI') { - $flags[] = "unique_key"; - } - - if ($field['Key'] == 'MUL') { - $flags[] = "multiple_key"; - } - - $type = strtolower($field['Type']); - if (in_array(substr($type, -4), ["text", "blob"])) { - $flags[] = "blob"; - } + if ($what == 'name' || $what == 'table') { + return $field->{$what}; + } - if (substr($type, 0, 4) == "enum") { - $flags[] = "enum"; - } + if ($what == 'len') { + return $field->length; + } - if (substr($type, 0, 3) == "set") { - $flags[] = "set"; - } + if ($what == 'type') { + return static::getFieldType($field->type); + } - return implode(" ", $flags); + if ($what == 'flags') { + return static::getFieldFlags($field->flags); } return false; @@ -603,88 +603,105 @@ namespace Dshafik { } } - protected static function getFieldLength($what, $type) + protected static function getFieldFlags($what) { - if (is_numeric($what)) { - return (int) $what; + // Order of flags taken from http://lxr.php.net/xref/PHP_5_6/ext/mysql/php_mysql.c#2507 + + $flags = []; + if ($what & MYSQLI_NOT_NULL_FLAG) { + $flags[] = "not_null"; } - switch ($type) { - case "text": - case "blob": - return 65535; - case "longtext": - case "longblob": - return 4294967295; - case "tinytext": - case "tinyblob": - return 255; - case "mediumtext": - case "mediumblob": - return 16777215; + if ($what & MYSQLI_PRI_KEY_FLAG) { + $flags[] = "primary_key"; } - if (strtolower(substr($type, 0, 3)) == "set") { - return (int)strlen($what) - - 2 // Remove open and closing quotes - - substr_count($what, "'") // Remove quotes - + substr_count($what, "'''") // Re-add escaped quotes - + ( - substr_count( - str_replace("'''", "'", $what), // Remove escaped quotes - "'" - ) - / 2 // We have two quotes per value - ) - - 1; // But we have one less comma than values + if ($what & MYSQLI_UNIQUE_KEY_FLAG) { + $flags[] = "unique_key"; } - if (strtolower(substr($type, 0, 4) == "enum")) { - $values = str_getcsv($what, ",", "'", "'"); - return (int) max(array_map('strlen', $values)); + if ($what & MYSQLI_MULTIPLE_KEY_FLAG) { + $flags[] = "multiple_key"; } + + if ($what & MYSQLI_BLOB_FLAG) { + $flags[] = "blob"; + } + + if ($what & MYSQLI_UNSIGNED_FLAG) { + $flags[] = "unsigned"; + } + + if ($what & MYSQLI_ZEROFILL_FLAG) { + $flags[] = "zerofill"; + } + + if ($what & MYSQLI_BINARY_FLAG) { + $flags[] = "binary"; + } + + if ($what & MYSQLI_ENUM_FLAG) { + $flags[] = "enum"; + } + + if ($what & MYSQLI_SET_FLAG) { + $flags[] = "set"; + } + + + if ($what & MYSQLI_AUTO_INCREMENT_FLAG) { + $flags[] = "auto_increment"; + } + + if ($what & MYSQLI_TIMESTAMP_FLAG) { + $flags[] = "timestamp"; + } + + return implode(" ", $flags); } protected static function getFieldType($what) { - switch (strtolower($what)) { - case "char": - case "varchar": - case "binary": - case "varbinary": - case "enum": - case "set": + switch ($what) { + case MYSQLI_TYPE_STRING: + case MYSQLI_TYPE_VAR_STRING: + case MYSQLI_TYPE_ENUM: + case MYSQLI_TYPE_SET: return "string"; - case "text": - case "tinytext": - case "mediumtext": - case "longtext": - case "blob": - case "tinyblob": - case "mediumblob": - case "longblob": - return "blob"; - case "integer": - case "bit": - case "int": - case "smallint": - case "tinyint": - case "mediumint": - case "bigint": + case MYSQLI_TYPE_LONG: + case MYSQLI_TYPE_TINY: + case MYSQLI_TYPE_SHORT: + case MYSQLI_TYPE_INT24: + case MYSQLI_TYPE_CHAR: + case MYSQLI_TYPE_LONGLONG: return "int"; - case "decimal": - case "numeric": - case "float": - case "double": + case MYSQLI_TYPE_DECIMAL: + case MYSQLI_TYPE_FLOAT: + case MYSQLI_TYPE_DOUBLE: + case MYSQLI_TYPE_NEWDECIMAL: return "real"; - case "date": - case "time": - case "timestamp": - case "year": - case "datetime": - case "null": - case "geometry": - return $what; + case MYSQLI_TYPE_DATETIME: + return "datetime"; + case MYSQLI_TYPE_TIMESTAMP: + return "timestamp"; + case MYSQLI_TYPE_NEWDATE: + case MYSQLI_TYPE_DATE: + return "date"; + case MYSQLI_TYPE_TIME: + return "time"; + case MYSQLI_TYPE_YEAR: + return "year"; + case MYSQLI_TYPE_TINY_BLOB: + case MYSQLI_TYPE_MEDIUM_BLOB: + case MYSQLI_TYPE_LONG_BLOB: + case MYSQLI_TYPE_BLOB: + return "blob"; + case MYSQLI_TYPE_NULL: + return "null"; + case MYSQLI_TYPE_GEOMETRY: + return "geometry"; + case MYSQLI_TYPE_INTERVAL: + case MYSQLI_TYPE_BIT: default: return "unknown"; } diff --git a/tests/MySqlShimTest.php b/tests/MySqlShimTest.php index 8365251..19fa72e 100644 --- a/tests/MySqlShimTest.php +++ b/tests/MySqlShimTest.php @@ -59,6 +59,10 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase public function test_mysql_connect_multi() { + if(defined('HHVM_VERSION')) { + $this->markTestSkipped("HHVM Behavior differs from PHP"); + } + $conn = mysql_connect(static::$host, 'root'); $conn2 = mysql_connect(static::$host, 'root'); @@ -87,33 +91,7 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase public function test_mysql_query_ddl() { $conn = mysql_connect(static::$host, 'root'); - $result = mysql_query("CREATE DATABASE shim_test CHARACTER SET latin1;"); - $this->assertTrue($result); - $result = mysql_select_db('shim_test'); - $this->assertTrue($result); - $result = mysql_query( - "CREATE TABLE testing ( - id int AUTO_INCREMENT, - one varchar(255), - two varchar(255), - three varchar(255), - four varchar(255), - five varchar(255), - six varchar(255), - seven varchar(255), - eight varchar(255), - nine ENUM('one', 'two', '\'three'), - ten SET('one', 'two', '\'\'three'), - eleven MEDIUMTEXT, - INDEX one_idx (one), - UNIQUE INDEX two_unq (two), - INDEX three_four_idx (three, four), - UNIQUE INDEX four_five_unq (four, five), - INDEX seven_eight_idx (seven, eight), - UNIQUE INDEX seven_eight_unq (seven, eight), - PRIMARY KEY (id) - ) CHARACTER SET latin1;" - ); + $result = mysql_query("CREATE DATABASE IF NOT EXISTS shim_test"); $this->assertTrue($result, mysql_error()); } @@ -122,12 +100,12 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase $this->getConnection("shim_test"); $result = mysql_query( "INSERT INTO - testing (one, two, three, four, five, six, seven, eight) + testing (one, two, three, four, five, six, seven, eight, nine, ten, eleven) VALUES - ('1', '1', '1', '1', '1', '1', '1', '1'), - ('2', '2', '2', '2', '2', '2', '2', '2'), - ('3', '3', '3', '3', '3', '3', '3', '3'), - ('4', '4', '4', '4', '4', '4', '4', '4')" + ('1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'), + ('2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2'), + ('3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3'), + ('4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4')" ); $this->assertTrue($result, mysql_error()); @@ -240,6 +218,18 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase $this->assertFalse($result); } + public function test_mysql_insert_id() + { + $this->getConnection("shim_test"); + $result = mysql_query( + "INSERT INTO + testing (id, one, two, three, four, five, six, seven, eight, nine, ten, eleven) + VALUES + (5, '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5')"); + $this->assertTrue($result); + $this->assertEquals(5, mysql_insert_id()); + } + public function test_mysql_list_dbs() { $this->getConnection(); @@ -273,6 +263,38 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase $result = mysql_list_fields("shim_test", "testing"); $this->assertResult($result); + while ($row = mysql_fetch_assoc($result)) { + $this->assertEquals( + [ + 'Field', + 'Type', + 'Null', + 'Key', + 'Default', + 'Extra' + ], + array_keys($row) + ); + } + + return; + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessage mysql_list_fields(): Unable to save MySQL query result + */ + public function test_mysql_list_fields_fail() + { + $this->getConnection(); + $result = mysql_list_fields("shim_test", "nonexistent"); + } + + public function test_mysql_field() + { + $this->getConnection("shim_test"); + $result = mysql_query("SELECT * FROM testing LIMIT 1"); + $this->assertEquals("testing", mysql_field_table($result, 0)); $this->assertEquals("id", mysql_field_name($result, 0)); $this->assertEquals("int", mysql_field_type($result, 0)); @@ -350,13 +372,60 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase * @expectedException \PHPUnit_Framework_Error_Warning * @expectedExceptionMessageRegExp /^mysql_field_name\(\): Field 999 is invalid for MySQL result index .*$/ */ - public function test_mysql_list_fields_fail() + public function test_mysql_field_name_fail() { - $this->getConnection(); - $result = mysql_list_fields("shim_test", "testing"); - $this->assertResult($result); + $this->getConnection("shim_test"); + $result = mysql_query("SELECT * FROM testing LIMIT 1"); + + $this->assertEquals("testing", mysql_field_name($result, 999)); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessageRegExp /^mysql_field_table\(\): Field 999 is invalid for MySQL result index .*$/ + */ + public function test_mysql_field_table_fail() + { + $this->getConnection("shim_test"); + $result = mysql_query("SELECT * FROM testing LIMIT 1"); + + $this->assertEquals("testing", mysql_field_table($result, 999)); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessageRegExp /^mysql_field_type\(\): Field 999 is invalid for MySQL result index .*$/ + */ + public function test_mysql_field_type_fail() + { + $this->getConnection("shim_test"); + $result = mysql_query("SELECT * FROM testing LIMIT 1"); + + $this->assertEquals("testing", mysql_field_type($result, 999)); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessageRegExp /^mysql_field_len\(\): Field 999 is invalid for MySQL result index .*$/ + */ + public function test_mysql_field_len_fail() + { + $this->getConnection("shim_test"); + $result = mysql_query("SELECT * FROM testing LIMIT 1"); - mysql_field_name($result, 999); + $this->assertEquals("testing", mysql_field_len($result, 999)); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessageRegExp /^mysql_field_flags\(\): Field 999 is invalid for MySQL result index .*$/ + */ + public function test_mysql_field_flags_fail() + { + $this->getConnection("shim_test"); + $result = mysql_query("SELECT * FROM testing LIMIT 1"); + + $this->assertEquals("testing", mysql_field_flags($result, 999)); } public function test_mysql_num_fields() @@ -387,7 +456,7 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase { $this->getConnection("shim_test"); - $result = mysql_query("SELECT one, two FROM testing"); + $result = mysql_query("SELECT one, two FROM testing LIMIT 4"); $this->assertResult($result); $this->assertEquals(sizeof($results), mysql_num_rows($result)); @@ -405,7 +474,7 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase { $this->getConnection("shim_test"); - $result = mysql_query("SELECT * FROM testing"); + $result = mysql_query("SELECT * FROM testing LIMIT 4"); $this->assertResult($result); $this->assertEquals(4, mysql_num_rows($result)); } @@ -422,6 +491,74 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase $this->assertEquals(4, mysql_affected_rows()); } + public function test_mysql_result() + { + $this->getConnection(); + + $result = mysql_query("SELECT one, two AS aliased FROM testing"); + $this->assertResult($result); + + for($i = 0; $i < mysql_num_rows($result); $i++) { + $this->assertEquals($i+1, mysql_result($result, $i, 0)); + $this->assertEquals($i+1, mysql_result($result, $i, 'one')); + $this->assertEquals($i+1, mysql_result($result, $i, 1)); + $this->assertEquals($i+1, mysql_result($result, $i, 'aliased')); + } + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessageRegExp /^mysql_result\(\): three not found in MySQL result index (.*?)$/ + */ + public function test_mysql_result_fail() + { + $this->getConnection(); + + $result = mysql_query("SELECT one, two FROM testing LIMIT 1"); + $this->assertResult($result); + + mysql_result($result, 0, "three"); + } + + public function test_mysql_result_prefixed() + { + $this->getConnection(); + + $result = mysql_query("SELECT one, two FROM testing LIMIT 1"); + $this->assertResult($result); + + $this->assertEquals(1, mysql_result($result, 0, "testing.one")); + $this->assertEquals(1, mysql_result($result, 0, "testing.two")); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessageRegExp /^mysql_result\(\): testing.three not found in MySQL result index (.*?)$/ + */ + public function test_mysql_result_prefixed_fail() + { + $this->getConnection(); + + $result = mysql_query("SELECT one, two FROM testing LIMIT 1"); + $this->assertResult($result); + + mysql_result($result, 0, "testing.three"); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + * @expectedExceptionMessageRegExp /^mysql_result\(\): Unable to jump to row 1 on MySQL result index (.*?)$/ + */ + public function test_mysql_result_invalid_row() + { + $this->getConnection(); + + $result = mysql_query("SELECT one FROM testing LIMIT 1"); + $this->assertResult($result); + + mysql_result($result, 1, 0); + } + public function test_mysql_close() { mysql_connect(static::$host, 'root'); @@ -437,6 +574,34 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase mysql_close(); } + public function test_mysql_error() + { + $this->getConnection(); + + $this->assertEmpty(mysql_error()); + + $result = mysql_query("SELECT VERSION("); + $this->assertFalse($result); + + $this->assertEquals( + "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version " . + "for the right syntax to use near '' at line 1", + mysql_error() + ); + } + + public function test_mysql_errno() + { + $this->getConnection(); + + $this->assertEmpty(mysql_errno()); + + $result = mysql_query("SELECT VERSION("); + $this->assertFalse($result); + + $this->assertEquals(1064, mysql_errno()); + } + public function tearDown() { @mysql_close(); @@ -501,6 +666,7 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase return; } + static::$host = 'localhost'; } @@ -525,7 +691,7 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase } mysql_connect(static::$host, "root"); - mysql_query("DROP DATABASE shim_test"); + mysql_query("DROP DATABASE IF EXISTS shim_test"); } public function mysql_fetch_DataProvider() @@ -597,6 +763,34 @@ class MySqlShimTest extends \PHPUnit_Framework_TestCase mysql_query("SET NAMES latin1"); + $result = mysql_query("CREATE DATABASE IF NOT EXISTS shim_test CHARACTER SET latin1;"); + $this->assertTrue($result); + $result = mysql_select_db('shim_test'); + $this->assertTrue($result); + $result = mysql_query( + "CREATE TABLE IF NOT EXISTS testing ( + id int AUTO_INCREMENT, + one varchar(255), + two varchar(255), + three varchar(255), + four varchar(255), + five varchar(255), + six varchar(255), + seven varchar(255), + eight varchar(255), + nine ENUM('one', 'two', '\'three'), + ten SET('one', 'two', '\'\'three'), + eleven MEDIUMTEXT, + INDEX one_idx (one), + UNIQUE INDEX two_unq (two), + INDEX three_four_idx (three, four), + UNIQUE INDEX four_five_unq (four, five), + INDEX seven_eight_idx (seven, eight), + UNIQUE INDEX seven_eight_unq (seven, eight), + PRIMARY KEY (id) + ) CHARACTER SET latin1;" + ); + if ($db !== null) { $this->assertTrue(mysql_select_db($db)); } |