2015-04-29 17:32:57 +12:00
|
|
|
<?php
|
|
|
|
|
2016-06-15 16:03:16 +12:00
|
|
|
namespace SilverStripe\ORM\Connect;
|
|
|
|
|
2016-08-19 10:51:35 +12:00
|
|
|
use mysqli_result;
|
|
|
|
use mysqli_stmt;
|
|
|
|
|
2015-04-29 17:32:57 +12:00
|
|
|
/**
|
2018-11-11 13:54:03 +13:00
|
|
|
* Provides a record-view for mysqli prepared statements
|
2015-04-29 17:32:57 +12:00
|
|
|
*
|
|
|
|
* By default streams unbuffered data, but seek(), rewind(), or numRecords() will force the statement to
|
|
|
|
* buffer itself and sacrifice any potential performance benefit.
|
|
|
|
*/
|
2016-11-29 12:31:16 +13:00
|
|
|
class MySQLStatement extends Query
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The related mysqli statement object if generated using a prepared query
|
|
|
|
*
|
|
|
|
* @var mysqli_stmt
|
|
|
|
*/
|
|
|
|
protected $statement;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Metadata result for this statement
|
|
|
|
*
|
|
|
|
* @var mysqli_result
|
|
|
|
*/
|
|
|
|
protected $metadata;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is the statement bound to the current resultset?
|
|
|
|
*
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
protected $bound = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List of column names
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $columns = array();
|
|
|
|
|
2018-11-11 13:54:03 +13:00
|
|
|
/**
|
|
|
|
* Map of column types, keyed by column name
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $types = array();
|
|
|
|
|
2016-11-29 12:31:16 +13:00
|
|
|
/**
|
|
|
|
* List of bound variables in the current row
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $boundValues = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Binds this statement to the variables
|
|
|
|
*/
|
|
|
|
protected function bind()
|
|
|
|
{
|
|
|
|
$variables = array();
|
|
|
|
|
|
|
|
// Bind each field
|
|
|
|
while ($field = $this->metadata->fetch_field()) {
|
|
|
|
$this->columns[] = $field->name;
|
2018-11-11 13:54:03 +13:00
|
|
|
$this->types[$field->name] = $field->type;
|
2016-11-29 12:31:16 +13:00
|
|
|
// Note that while boundValues isn't initialised at this point,
|
|
|
|
// later calls to $this->statement->fetch() Will populate
|
|
|
|
// $this->boundValues later with the next result.
|
|
|
|
$variables[] = &$this->boundValues[$field->name];
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->bound = true;
|
|
|
|
$this->metadata->free();
|
|
|
|
|
|
|
|
// Buffer all results
|
|
|
|
$this->statement->store_result();
|
|
|
|
|
|
|
|
call_user_func_array(array($this->statement, 'bind_result'), $variables);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hook the result-set given into a Query class, suitable for use by SilverStripe.
|
|
|
|
* @param mysqli_stmt $statement The related statement, if present
|
|
|
|
* @param mysqli_result $metadata The metadata for this statement
|
|
|
|
*/
|
|
|
|
public function __construct($statement, $metadata)
|
|
|
|
{
|
|
|
|
$this->statement = $statement;
|
|
|
|
$this->metadata = $metadata;
|
|
|
|
|
|
|
|
// Immediately bind and buffer
|
|
|
|
$this->bind();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function __destruct()
|
|
|
|
{
|
|
|
|
$this->statement->close();
|
|
|
|
$this->currentRecord = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function seek($row)
|
|
|
|
{
|
|
|
|
$this->rowNum = $row - 1;
|
2019-06-28 10:57:51 +12:00
|
|
|
|
|
|
|
// Fix for https://github.com/silverstripe/silverstripe-framework/issues/9097 without breaking the seek() API
|
|
|
|
$this->statement->data_seek($row);
|
|
|
|
$result = $this->next();
|
2016-11-29 12:31:16 +13:00
|
|
|
$this->statement->data_seek($row);
|
2019-06-28 10:57:51 +12:00
|
|
|
return $result;
|
2016-11-29 12:31:16 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
public function numRecords()
|
|
|
|
{
|
|
|
|
return $this->statement->num_rows();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function nextRecord()
|
|
|
|
{
|
|
|
|
// Skip data if out of data
|
|
|
|
if (!$this->statement->fetch()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dereferenced row
|
|
|
|
$row = array();
|
|
|
|
foreach ($this->boundValues as $key => $value) {
|
2018-11-11 13:54:03 +13:00
|
|
|
$floatTypes = [MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE, MYSQLI_TYPE_DECIMAL, MYSQLI_TYPE_NEWDECIMAL];
|
|
|
|
if (in_array($this->types[$key], $floatTypes)) {
|
|
|
|
$value = (float)$value;
|
|
|
|
}
|
2016-11-29 12:31:16 +13:00
|
|
|
$row[$key] = $value;
|
|
|
|
}
|
|
|
|
return $row;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function rewind()
|
|
|
|
{
|
2019-06-28 10:57:51 +12:00
|
|
|
$this->seek(0);
|
2016-11-29 12:31:16 +13:00
|
|
|
}
|
2015-04-29 17:32:57 +12:00
|
|
|
}
|