FIX: Correct type coercion of MySQL

This commit is contained in:
Sam Minnee 2018-11-11 13:54:03 +13:00
parent adb6e9eb8d
commit 45e1fcaf30
2 changed files with 36 additions and 3 deletions

View File

@ -4,6 +4,7 @@ namespace SilverStripe\ORM\Connect;
/** /**
* A result-set from a MySQL database (using MySQLiConnector) * A result-set from a MySQL database (using MySQLiConnector)
* Note that this class is only used for the results of non-prepared statements
*/ */
class MySQLQuery extends Query class MySQLQuery extends Query
{ {
@ -17,6 +18,11 @@ class MySQLQuery extends Query
*/ */
protected $handle; protected $handle;
/**
* Metadata about the columns of this query
*/
protected $columns;
/** /**
* Hook the result-set given into a Query class, suitable for use by SilverStripe. * Hook the result-set given into a Query class, suitable for use by SilverStripe.
* *
@ -27,6 +33,9 @@ class MySQLQuery extends Query
public function __construct($database, $handle) public function __construct($database, $handle)
{ {
$this->handle = $handle; $this->handle = $handle;
if (is_object($this->handle)) {
$this->columns = $this->handle->fetch_fields();
}
} }
public function __destruct() public function __destruct()
@ -40,7 +49,7 @@ class MySQLQuery extends Query
{ {
if (is_object($this->handle)) { if (is_object($this->handle)) {
$this->handle->data_seek($row); $this->handle->data_seek($row);
return $this->handle->fetch_assoc(); return $this->nextRecord();
} }
return null; return null;
} }
@ -55,7 +64,19 @@ class MySQLQuery extends Query
public function nextRecord() public function nextRecord()
{ {
if (is_object($this->handle) && ($data = $this->handle->fetch_assoc())) { $floatTypes = [MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE, MYSQLI_TYPE_DECIMAL, MYSQLI_TYPE_NEWDECIMAL];
if (is_object($this->handle) && ($row = $this->handle->fetch_array(MYSQLI_NUM))) {
$data = [];
foreach ($row as $i => $value) {
if (!isset($this->columns[$i])) {
throw new DatabaseException("Can't get metadata for column $i");
}
if (in_array($this->columns[$i]->type, $floatTypes)) {
$value = (float)$value;
}
$data[$this->columns[$i]->name] = $value;
}
return $data; return $data;
} else { } else {
return false; return false;

View File

@ -6,7 +6,7 @@ use mysqli_result;
use mysqli_stmt; use mysqli_stmt;
/** /**
* Provides a record-view for mysqli statements * Provides a record-view for mysqli prepared statements
* *
* By default streams unbuffered data, but seek(), rewind(), or numRecords() will force the statement to * By default streams unbuffered data, but seek(), rewind(), or numRecords() will force the statement to
* buffer itself and sacrifice any potential performance benefit. * buffer itself and sacrifice any potential performance benefit.
@ -42,6 +42,13 @@ class MySQLStatement extends Query
*/ */
protected $columns = array(); protected $columns = array();
/**
* Map of column types, keyed by column name
*
* @var array
*/
protected $types = array();
/** /**
* List of bound variables in the current row * List of bound variables in the current row
* *
@ -59,6 +66,7 @@ class MySQLStatement extends Query
// Bind each field // Bind each field
while ($field = $this->metadata->fetch_field()) { while ($field = $this->metadata->fetch_field()) {
$this->columns[] = $field->name; $this->columns[] = $field->name;
$this->types[$field->name] = $field->type;
// Note that while boundValues isn't initialised at this point, // Note that while boundValues isn't initialised at this point,
// later calls to $this->statement->fetch() Will populate // later calls to $this->statement->fetch() Will populate
// $this->boundValues later with the next result. // $this->boundValues later with the next result.
@ -116,6 +124,10 @@ class MySQLStatement extends Query
// Dereferenced row // Dereferenced row
$row = array(); $row = array();
foreach ($this->boundValues as $key => $value) { foreach ($this->boundValues as $key => $value) {
$floatTypes = [MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE, MYSQLI_TYPE_DECIMAL, MYSQLI_TYPE_NEWDECIMAL];
if (in_array($this->types[$key], $floatTypes)) {
$value = (float)$value;
}
$row[$key] = $value; $row[$key] = $value;
} }
return $row; return $row;