Skip to content

Commit

Permalink
Implement cache for prepared statements.
Browse files Browse the repository at this point in the history
  • Loading branch information
Olivier Poitrey committed Nov 14, 2008
1 parent 49d97d9 commit 4493b02
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 5 deletions.
36 changes: 33 additions & 3 deletions MyDBD.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class MyDBD
$link = null,
$connected = false,
$connectionInfo = null,
$statementCache = array(),
$lastQueryHandle = null,
$extendedConnectionInfo = array(),
$extendedQueryInfo = array(),
Expand Down Expand Up @@ -83,6 +84,8 @@ class MyDBD
* - query_log: If query_log is on, all queries will be logged using MyDBD_Logger. (bool)
* - pear_compat: Activate the PEAR Db compatibility layer. (bool)
* - pear_compat_class: Change the default PEAR Db compatibility class. (string)
* - query_prepare_cache: Make the query() method to use prepareCached() instead of prepare()
* when needed.
* - client_interactive: Allow interactive_timeout seconds (instead of wait_timeout seconds)
* of inactivity before closing the connection. (bool)
* - connect_timeout: Connection timeout in seconds (int)
Expand Down Expand Up @@ -130,6 +133,7 @@ public function __construct(array $connectionInfo = array(), array $options = ar
'query_log' => false,
'pear_compat' => false,
'pear_compat_class' => 'MyDBD_PearCompat',
'query_prepare_cache' => false,
'connect_timeout' => 0,
'wait_timeout' => 0,
'client_interactive' => false,
Expand Down Expand Up @@ -268,14 +272,14 @@ public function query()

if (count($params) > 0)
{
$sth = $this->prepare($query);
$sth = $this->options['query_prepare_cache'] ? $this->prepareCached($query) : $this->prepare($query);
$result = call_user_func_array(array($sth, 'execute'), $params);
}
else
{
$result = new MyDBD_ResultSet($this->link()->query($query), $this->options);
$this->handleErrors();
$this->lastQueryHandle = $this->link(); // used by affectedRows()
$this->lastQueryHandle = $this->link(); // used by getAffectedRows()

if ($this->options['query_log']) MyDBD_Logger::log('query', $query, null, microtime(true) - $start);
}
Expand All @@ -290,7 +294,7 @@ public function query()
* @see MyDBD_PreparedStatement::prepare()
* @see MyDBD_PreparedStatement::execute()
*
* @param string $query The SQL query to prepare
* @param string $query The SQL query to prepare
* @param string $type... List of query parameters types. If provided, the number of items MUST
* match the number of markers in the prepared query. If omited, types will
* be automatically guessed from the first execute() parameters PHP ctypes.
Expand Down Expand Up @@ -325,6 +329,32 @@ public function prepare()
return $sth;
}

/**
* Same as prepare() with statement cache management.
*
* @see prepare()
*
* @param string $query The SQL query to prepare
* @param string $type... List of query parameters types. If provided, the number of items MUST
* match the number of markers in the prepared query. If omited, types will
* be automatically guessed from the first execute() parameters PHP ctypes.
* Items of the string can by one of the following: 'double', 'integer', 'string'.
*
* @return MyDBD_PreparedStatement
*/
public function prepareCached()
{
$args = func_get_args();
$cacheKey = md5($args[0]);

if (!isset($this->statementCache[$cacheKey]))
{
$this->statementCache[$cacheKey] = call_user_func_array(array($this, 'prepare'), $args);
}

return $this->statementCache[$cacheKey];
}

/**
* Start a new transaction.
*
Expand Down
29 changes: 27 additions & 2 deletions MyDBD/PreparedStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class MyDBD_PreparedStatement
private
$stmt = null,
$options = null,
$frozen = false,
$preparedQuery = null,
$resultSet = null,
$boundParams = null;

/**
Expand All @@ -27,6 +29,18 @@ public function __construct(mysqli_stmt $preparedStatement, array $options)
$this->options = $options;
}

/**
* Freeze the statement so it's not possible to prepare another query with it. This permits to
* store this statement in a cache safely.
*
* @return $this
*/
public function freeze()
{
$this->frozen = true;
return $this;
}

/**
* Prepare a SQL statement for execution. Once prepared, a statement can be executed one or several
* time with different parameters if placeholder where used.
Expand Down Expand Up @@ -57,6 +71,7 @@ public function __construct(mysqli_stmt $preparedStatement, array $options)
* with NULL by ? IS NULL too. In general, parameters are legal only in Data Manipulation
* Languange (DML) statements, and not in Data Defination Language (DDL) statements.
*
* @throws RuntimeException If calling this method on a frozen statement (stored in cache).
* @throws InvalidArgumentException If a given type doesn't match autorized list.
* @throws SQLMismatchException If number of types given doesn't match the number of markers
* in the query.
Expand All @@ -65,6 +80,11 @@ public function __construct(mysqli_stmt $preparedStatement, array $options)
*/
public function prepare()
{
if ($this->frozen)
{
throw new RuntimeException('Cannot call prepare() on a frozen statement.');
}

$args = func_get_args();
$query = array_shift($args);

Expand Down Expand Up @@ -151,7 +171,12 @@ public function execute()
// integrity problem due to mysqli design limitation
// you can't store several result set on several executed query
// from the same prepared statment
return new MyDBD_StatementResultSet($this->stmt, $metadata, $this->options);
if (!isset($this->resultSet))
{
$this->resultSet = new MyDBD_StatementResultSet($this->stmt, $metadata, $this->options);
}

return $this->resultSet->reset();
}
else
{
Expand All @@ -171,7 +196,7 @@ public function execute()
* matched the WHERE clause in the query or that no query has yet been executed.
* -1 indicates that the query returned an error.
*/
public function affectedRows()
public function getAffectedRows()
{
return $this->stmt->affected_rows;
}
Expand Down
19 changes: 19 additions & 0 deletions MyDBD/StatementResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ public function __construct(mysqli_stmt $result, mysqli_result $metadata, array
call_user_func_array(array($this->result, 'bind_result'), $args);
}

/**
* Reset the object so it can be reused for anoter row.
*
* @return $this
*/
public function reset()
{
if ($this->cursor !== 0)
{
$this->seek(0);
}

$this->fetchMode = self::FETCH_ORDERED;
$this->fetchClass = 'stdClass';
$this->fetchCol = 0;

return $this;
}

/**
* @see ResultSet::fetchArray()
*/
Expand Down

0 comments on commit 4493b02

Please sign in to comment.