// This Database Adapter depends on MySqliDatabase
if (!class_exists('QMySqli5Database'))
require(__QCODO_CORE__ . '/database/QMySqli5Database.class.php');
// New MySQL 5 constanst not yet in PHP (as of PHP 5.1.2)
if (!defined('MYSQLI_TYPE_NEWDECIMAL'))
define('MYSQLI_TYPE_NEWDECIMAL', 246);
if (!defined('MYSQLI_TYPE_BIT'))
define('MYSQLI_TYPE_BIT', 16);
class QMySqli5MasterSlaveDatabase extends QMySqli5Database {
const Adapter = 'MySql Improved Database Adapter for MySQL 5 (Master/Slave)';
protected $objMysqliMaster;
public function IsInMasterSlaveMode ()
{
if ($this->objMysqliMaster) return true;
if (($this->master_server)) return true;
else return false;
}
public function GetTables() {
// Connect if Applicable
if (!$this->blnConnectedFlag) $this->Connect();
// Use the MySQL5 Information Schema to get a list of all the tables in this database
// (excluding views, etc.)
$strDatabaseName = $this->Database;
$objResult = $this->Query("
SELECT
table_name
FROM
information_schema.tables
WHERE
table_type <> 'VIEW' AND
table_schema = '$strDatabaseName';
");
$strToReturn = array();
while ($strRowArray = $objResult->FetchRow())
array_push($strToReturn, $strRowArray[0]);
return $strToReturn;
}
/**
* to query master...
*
* @param string $strQuery
*/
public function QueryMaster($strQuery) {
if (!$this->IsInMasterSlaveMode())
throw new QMySqliDatabaseException("queryMaster: no master/slave setup", -1, $strQuery);
// Connect if Applicable
if (!$this->blnConnectedFlag) $this->Connect();
// Log Query (for Profiling, if applicable)
$this->LogQuery($strQuery);
// Perform the Query
$objResult = $this->objMysqliMaster->query($strQuery);
if ($this->objMysqliMaster->error)
throw new QMySqliDatabaseException($this->objMysqliMaster->error, $this->objMysqliMaster->errno, $strQuery);
// Return the Result
$objMySqliDatabaseResult = new QMySqli5DatabaseResult($objResult, $this);
return $objMySqliDatabaseResult;
}
public function Query($strQuery) {
// Connect if Applicable
if (!$this->blnConnectedFlag) $this->Connect();
// Log Query (for Profiling, if applicable)
$this->LogQuery($strQuery);
// Perform the Query
// sometimes we want to query master (i.e. for highly interactive cases, like job postings)
// this switch is normally OFF, turned ON by say jobs.uloop.com
if (QApplication::$MysqlForceMaster)
// if (false)
{
// ULogger::log("force query master :\n $strQuery");
$objResult = $this->objMysqliMaster->query($strQuery);
if ($this->objMysqliMaster->error)
throw new QMySqliDatabaseException($this->objMysqliMaster->error, $this->objMysqliMaster->errno, $strQuery);
}
else
{
// ULogger::log("regular query :\n $strQuery");
$objResult = $this->objMySqli->query($strQuery);
if ($this->objMySqli->error)
throw new QMySqliDatabaseException($this->objMySqli->error, $this->objMySqli->errno, $strQuery);
}
// Return the Result
$objMySqliDatabaseResult = new QMySqli5DatabaseResult($objResult, $this);
return $objMySqliDatabaseResult;
}
/**
* Performs a Multi Result-Set Query, which is available with Stored Procs in MySQL 5
* Written by Mike Hostetler
*
* @param string $strQuery
* @return QMySqli5DatabaseResult[] array of results
*/
public function MultiQuery($strQuery) {
// Connect if Applicable
if (!$this->blnConnectedFlag) $this->Connect();
// Log Query (for Profiling, if applicable)
$this->LogQuery($strQuery);
// Perform the Query
$this->objMySqli->multi_query($strQuery);
if ($this->objMySqli->error)
throw new QMySqliDatabaseException($this->objMySqli->error, $this->objMySqli->errno, $strNonQuery);
$objResultSets = array();
do {
if ($objResult = $this->objMySqli->store_result()) {
array_push($objResultSets,new QMySqli5DatabaseResult($objResult, $this));
}
} while ($this->objMySqli->next_result());
return $objResultSets;
}
public function NonQuery($strNonQuery) {
if ($this->IsInMasterSlaveMode())
$this->NonQueryMaster($strNonQuery);
else
$this->NonQuerySlave($strNonQuery);
}
protected function NonQuerySlave($strNonQuery)
{
// Connect if Applicable
if (!$this->blnConnectedFlag) $this->Connect();
// Log Query (for Profiling, if applicable)
$this->LogQuery($strNonQuery);
// Perform the Query
$this->objMySqli->query($strNonQuery);
if ($this->objMySqli->error)
throw new QMySqliDatabaseException($this->objMySqli->error, $this->objMySqli->errno, $strNonQuery);
}
protected function NonQueryMaster($strNonQuery)
{
if (!$this->blnConnectedFlag) $this->Connect();
$this->LogQuery($strNonQuery);
$this->objMysqliMaster->query($strNonQuery);
if ($this->objMysqliMaster->error)
throw new QMySqliDatabaseException($this->objMysqliMaster->error, $this->objMysqliMaster->errno, $strNonQuery);
}
public function Connect() {
$this->ConnectToSlave();
// check if master is defined
if ($this->IsInMasterSlaveMode())
{
$this->ConnectToMaster();
}
// Update "Connected" Flag
$this->blnConnectedFlag = true;
}
protected function ConnectToSlave()
{
// Connect to the Database Server
$this->objMySqli = new MySqli($this->Server, $this->Username, $this->Password, $this->Database, $this->Port);
if (!$this->objMySqli)
throw new QMySqliDatabaseException("Unable to connect to Database", -1, null);
if ($this->objMySqli->error)
throw new QMySqliDatabaseException($this->objMySqli->error, $this->objMySqli->errno, null);
// Set to AutoCommit
// $this->NonQuery('SET AUTOCOMMIT=1;');
$this->RunQueryOnDb($this->objMySqli, 'SET AUTOCOMMIT=1;');
// Set NAMES (if applicable)
if (array_key_exists('encoding', $this->objConfigArray))
{
// $this->NonQuery('SET NAMES ' . $this->objConfigArray['encoding'] . ';');
$this->RunQueryOnDb( $this->objMySqli, 'SET NAMES ' . $this->objConfigArray['encoding'] . ';');
}
}
protected function RunQueryOnDb($objSqli , $str)
{
$objSqli->query($str);
if ($objSqli->error)
throw new QMySqliDatabaseException($objSqli->error, $objSqli->errno, $str);
}
protected function ConnectToMaster()
{
$this->objMysqliMaster = new mysqli($this->master_server, $this->master_username, $this->master_password, $this->master_database, $this->master_port);
if (!$this->objMysqliMaster)
throw new QMySqliDatabaseException("Unable to connect to master Database", -1, null);
if ($this->objMysqliMaster->error)
throw new QMySqliDatabaseException($this->objMysqliMaster->error, $this->objMysqliMaster->errno, null);
// Set to AutoCommit
$this->RunQueryOnDb($this->objMysqliMaster, 'SET AUTOCOMMIT=1;');
// Set NAMES (if applicable)
// FIXME : use the encoding for slave server?
if (array_key_exists('encoding', $this->objConfigArray))
{
// $this->NonQuery('SET NAMES ' . $this->objConfigArray['encoding'] . ';');
$this->RunQueryOnDb( $this->objMysqliMaster, 'SET NAMES ' . $this->objConfigArray['encoding'] . ';');
}
}
public function Close() {
if ($this->objMysqliMaster)
$this->objMysqliMaster->Close();
parent::Close();
}
public function InsertId($strTableName = null, $strColumnName = null) {
if ($this->IsInMasterSlaveMode())
return $this->objMysqliMaster->insert_id;
else
return $this->objMySqli->insert_id;
}
public function __get($strName) {
switch ($strName)
{
case 'master_server':
case 'master_port':
case 'master_database':
case 'master_username':
case 'master_password':
return $this->objConfigArray[$strName];
case 'AffectedRows':
if ($this->IsInMasterSlaveMode())
return $this->objMysqliMaster->affected_rows;
else
return $this->objMySqli->affected_rows;
default:
try {
return parent::__get($strName);
} catch (QCallerException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
}
}
}