Commit 9cbf09d4 by Scott

Add more methods to DbConnection, add DbResult class

parent 3d604bff
......@@ -20,6 +20,7 @@ namespace Q2A\Database;
use PDO;
use PDOException;
use Q2A\Database\DbResult;
class DbConnection
{
......@@ -27,6 +28,7 @@ class DbConnection
protected $config;
protected $allowConnect = false;
protected $failHandler;
protected $updateCountsSuspended = 0;
public function __construct()
{
......@@ -51,6 +53,15 @@ class DbConnection
}
/**
* Obtain the raw PDO object.
* @return PDO
*/
public function getPDO()
{
return $this->pdo;
}
/**
* Indicates to the Q2A database layer that database connections are permitted from this point forwards (before
* this point, some plugins may not have had a chance to override some database access functions).
*/
......@@ -99,6 +110,15 @@ class DbConnection
}
/**
* Disconnect from the Q2A database.
* @return void
*/
public function disconnect()
{
$this->pdo = null;
}
/**
* If a DB error occurs, call the installed fail handler (if any) otherwise report error and exit immediately.
* @param $type
* @param int $errno
......@@ -123,12 +143,17 @@ class DbConnection
/**
* Prepare and execute a SQL query, handling any failures. In debugging mode, track the queries and resources used.
* @param string $query
* @param array $params
* @return PDOStatement
* @param string $query
* @param array $params
* @return DbResult
*/
public function query($query, $params = array())
{
// Substitute ^ with the configured table prefix
$query = preg_replace_callback('/\^([A-Za-z_0-9]+)/', function($matches) {
return $this->addTablePrefix($matches[1]);
}, $query);
try {
if (QA_DEBUG_PERFORMANCE) {
global $qa_usage;
......@@ -138,19 +163,12 @@ class DbConnection
$stmt = $this->execute($query, $params);
$usedtime = array_sum(explode(' ', microtime())) - $oldtime;
// fetch counts
$gotrows = $gotcolumns = null;
if ($result instanceof mysqli_result) {
$gotrows = $result->num_rows;
$gotcolumns = $result->field_count;
}
$qa_usage->logDatabaseQuery($query, $usedtime, $gotrows, $gotcolumns);
$qa_usage->logDatabaseQuery($query, $usedtime, $stmt->rowCount(), $stmt->columnCount());
} else {
$stmt = $this->execute($query, $params);
}
return $stmt;
return new DbResult($stmt);
} catch (PDOException $ex) {
$this->failError('query', $ex->getCode(), $ex->getMessage(), $query);
}
......@@ -159,8 +177,8 @@ class DbConnection
/**
* Lower-level function to prepare and execute a SQL query. Automatically retries if there is a MySQL deadlock
* error.
* @param string $query
* @param array $params
* @param string $query
* @param array $params
* @return PDOStatement
*/
protected function execute($query, $params = array())
......@@ -180,4 +198,62 @@ class DbConnection
return $stmt;
}
/**
* Return the full name (with prefix) of database table $rawname, usually if it used after a ^ symbol.
* @param string $rawName
* @return string
*/
public function addTablePrefix($rawName)
{
$prefix = QA_MYSQL_TABLE_PREFIX;
if (defined('QA_MYSQL_USERS_PREFIX')) {
switch (strtolower($rawName)) {
case 'users':
case 'userlogins':
case 'userprofile':
case 'userfields':
case 'messages':
case 'cookies':
case 'blobs':
case 'cache':
case 'userlogins_ibfk_1': // also special cases for constraint names
case 'userprofile_ibfk_1':
$prefix = QA_MYSQL_USERS_PREFIX;
break;
}
}
return $prefix . $rawName;
}
/**
* Return the value of the auto-increment column for the last inserted row.
* @return string
*/
public function lastInsertId()
{
return $this->pdo->lastInsertId();
}
/**
* Suspend or reinstate the updating of counts (of many different types) in the database, to save time when making
* a lot of changes. A counter is kept to allow multiple calls.
* @param bool $suspend
*/
public function suspendUpdateCounts($suspend = true)
{
$this->updateCountsSuspended += ($suspend ? 1 : -1);
}
/**
* Returns whether counts should currently be updated (i.e. if count updating has not been suspended).
* @return bool
*/
public function shouldUpdateCounts()
{
return $this->updateCountsSuspended <= 0;
}
}
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
namespace Q2A\Database;
use PDO;
use PDOStatement;
class DbResult
{
private $stmt;
public function __construct(PDOStatement $stmt)
{
$this->stmt = $stmt;
}
public function fetchNextAssoc()
{
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
public function fetchAllAssoc()
{
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Return a specific cell from the results. Typically used with (single-row, single-column) aggregate queries.
* @param $col 0-indexed column to select from (defaults to first column).
* @param bool $allowempty If false, throw a fatal error if there is no result.
* @return mixed|null
*/
public function fetchOneValue($col = 0, $allowempty = false)
{
$data = $this->stmt->fetchColumn($col);
if ($data !== false) {
return $data;
}
if (!$allowempty) {
qa_fatal_error('Reading one value from empty results');
}
return null;
}
/**
* Return a numbered array containing the specified column.
* @param $col 0-indexed column to select from (defaults to first column).
* @return array
*/
public function fetchAllValues($col = 0)
{
return $this->stmt->fetchAll(PDO::FETCH_COLUMN, $col);
}
/**
* Number of rows found (SELECT queries) or rows affected (UPDATE/INSERT/DELETE queries).
* @return int
*/
public function rowCount()
{
return $this->stmt->rowCount();
}
/**
* Obtain the raw PDOStatement object.
* @return PDO
*/
public function getPDOStatement()
{
return $this->stmt;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment