summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/mysql.php269
-rw-r--r--tests/MySqlShimTest.php274
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));
}