mirror of
https://github.com/processwire/processwire.git
synced 2025-08-08 07:47:00 +02:00
Refactor of WireDatabasePDO to add support for separate read-only database connection
This commit is contained in:
@@ -294,13 +294,13 @@ $config->sessionExpireSeconds = 86400;
|
|||||||
* automatically enabled.
|
* automatically enabled.
|
||||||
*
|
*
|
||||||
* ~~~~~
|
* ~~~~~
|
||||||
* $config->sessionAllow = function($session) {
|
* $config->sessionAllow = function($session) use($config) {
|
||||||
*
|
*
|
||||||
* // if there is a session cookie, a session is likely already in use so keep it going
|
* // if there is a session cookie, a session is likely already in use so keep it going
|
||||||
* if($session->hasCookie()) return true;
|
* if($session->hasCookie()) return true;
|
||||||
*
|
*
|
||||||
* // if URL is an admin URL, allow session (replace /processwire/ with your admin URL)
|
* // if URL is an admin URL, allow session (replace /processwire/ with your admin URL)
|
||||||
* if(strpos($_SERVER['REQUEST_URI'], '/processwire/) === 0) return true;
|
* if(strpos($config->requestPath(), '/processwire/) === 0) return true;
|
||||||
*
|
*
|
||||||
* // otherwise disallow session
|
* // otherwise disallow session
|
||||||
* return false;
|
* return false;
|
||||||
@@ -1189,7 +1189,59 @@ $config->dbQueryLogMax = 500;
|
|||||||
*/
|
*/
|
||||||
$config->dbStripMB4 = false;
|
$config->dbStripMB4 = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional settings for read-only “reader” database connection
|
||||||
|
*
|
||||||
|
* All `$config->db*` settings above are for a read/write database connection. You can
|
||||||
|
* optionally maintain a separate read-only database connection to reduce costs and
|
||||||
|
* allow for further database scalability. Use of this feature requires an environment
|
||||||
|
* that supports a separate read-only database connection to the same database used by the
|
||||||
|
* read/write connection. When enabled, ProcessWire will direct all non-writing queries to
|
||||||
|
* the read-only connection, while queries that write to the database are directed to the
|
||||||
|
* read/write connection.
|
||||||
|
*
|
||||||
|
* Specify one or more existing `$config->db*` settings in the array to use that value for
|
||||||
|
* the read-only connection. To enable a separate read-only database connection, this array
|
||||||
|
* must contain at minimum a `host` or `socket` entry. Beyond that, values not present in
|
||||||
|
* this array will be pulled from the existing `$config->db*` settings. Note, when specifying
|
||||||
|
* settings in this array, omit the `db` prefix and use lowercase for the first letter. For
|
||||||
|
* example, use `host` rather than `dbHost`, `name` rather than `dbName`, etc.
|
||||||
|
*
|
||||||
|
* When using this feature, you may want to exclude your admin from it, as the admin is an
|
||||||
|
* environment that's designed for both read and write, so there's less reason to maintain
|
||||||
|
* separate read-only and read/write connections in the admin. See the examples below.
|
||||||
|
*
|
||||||
|
* For more details see: https://processwire.com/blog/posts/pw-3.0.175/
|
||||||
|
*
|
||||||
|
* ~~~~~
|
||||||
|
* // allow read-only database connection always…
|
||||||
|
* $config->dbReader = [
|
||||||
|
* 'host' => 'readonly.mydb.domain.com'
|
||||||
|
* ];
|
||||||
|
*
|
||||||
|
* // …or, use read-only connection only if not in the admin…
|
||||||
|
* if(!$config->requestPath('/processwire/')) {
|
||||||
|
* $config->dbReader = [ 'host' => 'readonly.mydb.domain.com' ];
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // …or limit read-only to GET requests, exclude admin and contact page…
|
||||||
|
* $skipPaths = [ '/processwire/', '/contact/' ];
|
||||||
|
* if($config->requestMethod('GET') && !$config->requestPath($skipPaths)) {
|
||||||
|
* $config->dbReader = [ 'host' => 'readonly.mydb.domain.com' ];
|
||||||
|
* }
|
||||||
|
* ~~~~~
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
* @since 3.0.175
|
||||||
|
* @see https://processwire.com/blog/posts/pw-3.0.175/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
$config->dbReader = array(
|
||||||
|
// 'host' => 'readonly.mydb.domain.com',
|
||||||
|
// 'port' => 3306,
|
||||||
|
// 'name' => 'mydb',
|
||||||
|
// …etc., though most likely you will only need 'host' entry to setup a reader
|
||||||
|
);
|
||||||
|
|
||||||
/*** 8. MODULES *********************************************************************************/
|
/*** 8. MODULES *********************************************************************************/
|
||||||
|
|
||||||
|
@@ -3,10 +3,9 @@
|
|||||||
/**
|
/**
|
||||||
* ProcessWire PDO Database
|
* ProcessWire PDO Database
|
||||||
*
|
*
|
||||||
* Serves as a wrapper to PHP's PDO class
|
* Serves as a wrapper to PHP’s PDO class
|
||||||
*
|
*
|
||||||
*
|
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer
|
||||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
|
||||||
* https://processwire.com
|
* https://processwire.com
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -29,92 +28,140 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
/**
|
/**
|
||||||
* Log of all queries performed in this instance
|
* Log of all queries performed in this instance
|
||||||
*
|
*
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
protected $queryLog = array();
|
protected $queryLog = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Max queries allowedin the query log (set from $config->dbQueryLogMax)
|
* Max queries allowedin the query log (set from $config->dbQueryLogMax)
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $queryLogMax = 500;
|
protected $queryLogMax = 500;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether queries will be logged
|
* Whether queries will be logged
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $debugMode = false;
|
protected $debugMode = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached result from getTables() method
|
* Cached result from getTables() method
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $tablesCache = array();
|
protected $tablesCache = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of PDO
|
* Data for read-write PDO connection
|
||||||
*
|
*
|
||||||
* @var \PDO
|
* @var array
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $pdo = null;
|
protected $writer = array(
|
||||||
|
'pdo' => null,
|
||||||
|
'init' => false,
|
||||||
|
'commands' => array(
|
||||||
|
// commands that rewrite a writable connection
|
||||||
|
'alter',
|
||||||
|
'call',
|
||||||
|
'comment',
|
||||||
|
'commit',
|
||||||
|
'create',
|
||||||
|
'delete',
|
||||||
|
'drop',
|
||||||
|
'insert',
|
||||||
|
'lock',
|
||||||
|
'merge',
|
||||||
|
'rename',
|
||||||
|
'replace',
|
||||||
|
'rollback',
|
||||||
|
'savepoint',
|
||||||
|
'set',
|
||||||
|
'start',
|
||||||
|
'truncate',
|
||||||
|
'unlock',
|
||||||
|
'update',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for read-only PDO connection
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $reader = array(
|
||||||
|
'pdo' => null,
|
||||||
|
'has' => false, // is reader available?
|
||||||
|
'init' => false, // is reader initalized?
|
||||||
|
'allow' => true, // is reader allowed? (false when in transaction, etc.)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last used PDO connection
|
||||||
|
*
|
||||||
|
* @var null|\PDO
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $pdoLast = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not our _init() has been called for the current $pdo connection
|
* Whether or not our _init() has been called for the current $pdo connection
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $init = false;
|
protected $init = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip 4-byte characters in “quote” and “escapeStr” methods? (only when dbEngine is not utf8mb4)
|
* Strip 4-byte characters in “quote” and “escapeStr” methods? (only when dbEngine is not utf8mb4)
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $stripMB4 = false;
|
protected $stripMB4 = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lowercase value of $config->dbEngine
|
* Lowercase value of $config->dbEngine
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $engine = '';
|
protected $engine = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lowercase value of $config->dbCharset
|
* Lowercase value of $config->dbCharset
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $charset = '';
|
protected $charset = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regular comparison operators
|
* Regular comparison operators
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $comparisonOperators = array('=', '<', '>', '>=', '<=', '<>', '!=');
|
protected $comparisonOperators = array('=', '<', '>', '>=', '<=', '<>', '!=');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bitwise comparison operators
|
* Bitwise comparison operators
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $bitwiseOperators = array('&', '~', '&~', '|', '^', '<<', '>>');
|
protected $bitwiseOperators = array('&', '~', '&~', '|', '^', '<<', '>>');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Substitute variable names according to engine as used by getVariable() method
|
* Substitute variable names according to engine as used by getVariable() method
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $subVars = array(
|
protected $subVars = array(
|
||||||
'myisam' => array(),
|
'myisam' => array(),
|
||||||
@@ -126,130 +173,225 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* PDO connection settings
|
* PDO connection settings
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private $pdoConfig = array(
|
private $pdoConfig = array(
|
||||||
'dsn' => '',
|
'dsn' => '',
|
||||||
'user' => '',
|
'user' => '',
|
||||||
'pass' => '',
|
'pass' => '',
|
||||||
'options' => '',
|
'options' => '',
|
||||||
|
'reader' => array(
|
||||||
|
'dsn' => '',
|
||||||
|
'user' => '',
|
||||||
|
'pass' => '',
|
||||||
|
'options' => '',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached values from getVariable method
|
* Cached values from getVariable method
|
||||||
*
|
*
|
||||||
* @var array associative of name => value
|
* @var array associative of name => value
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $variableCache = array();
|
protected $variableCache = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached InnoDB stopwords (keys are the stopwords and values are irrelevant)
|
* Cached InnoDB stopwords (keys are the stopwords and values are irrelevant)
|
||||||
*
|
*
|
||||||
* @var array|null Becomes array once loaded
|
* @var array|null Becomes array once loaded
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $stopwordCache = null;
|
protected $stopwordCache = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new PDO instance from ProcessWire $config API variable
|
* Create a new PDO instance from ProcessWire $config API variable
|
||||||
*
|
*
|
||||||
* If you need to make other PDO connections, just instantiate a new WireDatabasePDO (or native PDO)
|
* If you need to make other PDO connections, just instantiate a new WireDatabasePDO (or native PDO)
|
||||||
* rather than calling this getInstance method.
|
* rather than calling this getInstance method.
|
||||||
*
|
*
|
||||||
* #pw-internal
|
* #pw-internal
|
||||||
*
|
*
|
||||||
* @param Config $config
|
* @param Config $config
|
||||||
* @return WireDatabasePDO
|
*
|
||||||
|
* @return WireDatabasePDO
|
||||||
* @throws WireException
|
* @throws WireException
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static function getInstance(Config $config) {
|
public static function getInstance(Config $config) {
|
||||||
|
|
||||||
if(!class_exists('\PDO')) {
|
if(!class_exists('\PDO')) {
|
||||||
throw new WireException('Required PDO class (database) not found - please add PDO support to your PHP.');
|
throw new WireException('Required PDO class (database) not found - please add PDO support to your PHP.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$host = $config->dbHost;
|
|
||||||
$username = $config->dbUser;
|
$username = $config->dbUser;
|
||||||
$password = $config->dbPass;
|
$password = $config->dbPass;
|
||||||
$name = $config->dbName;
|
|
||||||
$socket = $config->dbSocket;
|
|
||||||
$charset = $config->dbCharset;
|
$charset = $config->dbCharset;
|
||||||
$options = $config->dbOptions;
|
$options = $config->dbOptions;
|
||||||
|
$reader = $config->dbReader;
|
||||||
$initCommand = str_replace('{charset}', $charset, $config->dbInitCommand);
|
$initCommand = str_replace('{charset}', $charset, $config->dbInitCommand);
|
||||||
|
|
||||||
if($socket) {
|
|
||||||
// if socket is provided ignore $host and $port and use $socket instead:
|
|
||||||
$dsn = "mysql:unix_socket=$socket;dbname=$name;";
|
|
||||||
} else {
|
|
||||||
$dsn = "mysql:dbname=$name;host=$host";
|
|
||||||
$port = $config->dbPort;
|
|
||||||
if($port) $dsn .= ";port=$port";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!is_array($options)) $options = array();
|
if(!is_array($options)) $options = array();
|
||||||
|
|
||||||
if(!isset($options[\PDO::ATTR_ERRMODE])) {
|
if(!isset($options[\PDO::ATTR_ERRMODE])) {
|
||||||
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION;
|
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($initCommand && !isset($options[\PDO::MYSQL_ATTR_INIT_COMMAND])) {
|
if($initCommand && !isset($options[\PDO::MYSQL_ATTR_INIT_COMMAND])) {
|
||||||
$options[\PDO::MYSQL_ATTR_INIT_COMMAND] = $initCommand;
|
$options[\PDO::MYSQL_ATTR_INIT_COMMAND] = $initCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
$database = new WireDatabasePDO($dsn, $username, $password, $options);
|
$dsnArray = array(
|
||||||
|
'socket' => $config->dbSocket,
|
||||||
|
'name' => $config->dbName,
|
||||||
|
'host' => $config->dbHost,
|
||||||
|
'port' => $config->dbPort,
|
||||||
|
);
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
'dsn' => self::dsn($dsnArray),
|
||||||
|
'user' => $username,
|
||||||
|
'pass' => $password,
|
||||||
|
'options' => $options,
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!empty($reader) && (!empty($reader['host']) || !empty($reader['socket']))) {
|
||||||
|
$reader['dsn'] = self::dsn(array_merge($dsnArray, $reader));
|
||||||
|
$reader = array_merge($data, $reader);
|
||||||
|
$data['reader'] = $reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
$database = new WireDatabasePDO($data);
|
||||||
$database->setDebugMode($config->debug);
|
$database->setDebugMode($config->debug);
|
||||||
$config->wire($database);
|
$config->wire($database);
|
||||||
$database->_init();
|
// $database->_init();
|
||||||
|
|
||||||
return $database;
|
return $database;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct WireDatabasePDO
|
* Create a PDO DSN string from array
|
||||||
*
|
*
|
||||||
* #pw-internal
|
* #pw-internal
|
||||||
*
|
*
|
||||||
* @param $dsn
|
* @param array $options May contain keys: 'name', 'host', 'port', 'socket' (if applies), 'type' (default=mysql)
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @since 3.0.175
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static public function dsn(array $options) {
|
||||||
|
$defaults = array(
|
||||||
|
'type' => 'mysql',
|
||||||
|
'socket' => '',
|
||||||
|
'name' => '',
|
||||||
|
'host' => '',
|
||||||
|
'port' => '',
|
||||||
|
);
|
||||||
|
$options = array_merge($defaults, $options);
|
||||||
|
if($options['socket']) {
|
||||||
|
// if socket is provided ignore $host and $port and use socket instead
|
||||||
|
$dsn = "mysql:unix_socket=$options[socket];dbname=$options[name];";
|
||||||
|
} else {
|
||||||
|
$dsn = "mysql:dbname=$options[name];host=$options[host]";
|
||||||
|
if($options['port']) $dsn .= ";port=$options[port]";
|
||||||
|
}
|
||||||
|
return $dsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct WireDatabasePDO
|
||||||
|
*
|
||||||
|
* ~~~~~
|
||||||
|
* // The following are required to construct a WireDatabasePDO
|
||||||
|
* $dsn = 'mysql:dbname=mydb;host=myhost;port=3306';
|
||||||
|
* $username = 'username';
|
||||||
|
* $password = 'password';
|
||||||
|
* $driver_options = []; // optional
|
||||||
|
*
|
||||||
|
* // Construct option A
|
||||||
|
* $db = new WireDatabasePDO($dsn, $username, $password, $driver_options);
|
||||||
|
*
|
||||||
|
* // Construct option B
|
||||||
|
* $db = new WireDatabasePDO([
|
||||||
|
* 'dsn' => $dsn,
|
||||||
|
* 'user' => $username,
|
||||||
|
* 'pass' => $password,
|
||||||
|
* 'options' => $driver_options, // optional
|
||||||
|
* 'reader' => [ // optional
|
||||||
|
* 'dsn' => '…',
|
||||||
|
* …
|
||||||
|
* ],
|
||||||
|
* …
|
||||||
|
* ]);
|
||||||
|
* ~~~~~
|
||||||
|
*
|
||||||
|
* #pw-internal
|
||||||
|
*
|
||||||
|
* @param string|array $dsn DSN string or (3.0.175+) optionally use array of connection options and omit all remaining arguments.
|
||||||
* @param null $username
|
* @param null $username
|
||||||
* @param null $password
|
* @param null $password
|
||||||
* @param array $driver_options
|
* @param array $driver_options
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct($dsn, $username = null, $password = null, array $driver_options = array()) {
|
public function __construct($dsn, $username = null, $password = null, array $driver_options = array()) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->pdoConfig['dsn'] = $dsn;
|
if(is_array($dsn) && isset($dsn['dsn'])) {
|
||||||
$this->pdoConfig['user'] = $username;
|
if($username !== null && empty($dsn['user'])) $dsn['user'] = $username;
|
||||||
$this->pdoConfig['pass'] = $password;
|
if($password !== null && empty($dsn['pass'])) $dsn['pass'] = $password;
|
||||||
$this->pdoConfig['options'] = $driver_options;
|
if(!isset($dsn['options'])) $dsn['options'] = $driver_options;
|
||||||
$this->pdo();
|
$this->pdoConfig = array_merge($this->pdoConfig, $dsn);
|
||||||
|
if(!empty($this->pdoConfig['reader']['dsn'])) $this->reader['has'] = true;
|
||||||
|
} else {
|
||||||
|
$this->pdoConfig['dsn'] = $dsn;
|
||||||
|
$this->pdoConfig['user'] = $username;
|
||||||
|
$this->pdoConfig['pass'] = $password;
|
||||||
|
$this->pdoConfig['options'] = $driver_options;
|
||||||
|
}
|
||||||
|
// $this->pdo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional initialization after DB connection established and Wire instance populated
|
* Additional initialization after DB connection established and Wire instance populated
|
||||||
*
|
*
|
||||||
* #pw-internal
|
* #pw-internal
|
||||||
*
|
*
|
||||||
|
* @param \PDO|null
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public function _init() {
|
public function _init($pdo = null) {
|
||||||
if($this->init || !$this->isWired()) return;
|
|
||||||
$this->init = true;
|
if(!$this->isWired()) return;
|
||||||
|
|
||||||
|
if($pdo === $this->reader['pdo']) {
|
||||||
|
if($this->reader['init']) return;
|
||||||
|
$this->reader['init'] = true;
|
||||||
|
} else {
|
||||||
|
if($this->writer['init']) return;
|
||||||
|
$this->writer['init'] = true;
|
||||||
|
if($pdo === null) $pdo = $this->writer['pdo'];
|
||||||
|
}
|
||||||
|
|
||||||
$config = $this->wire()->config;
|
$config = $this->wire()->config;
|
||||||
$this->stripMB4 = $config->dbStripMB4 && strtolower($config->dbEngine) != 'utf8mb4';
|
|
||||||
$this->engine = strtolower($config->dbEngine);
|
if(empty($this->engine)) {
|
||||||
$this->charset = strtolower($config->dbCharset);
|
$this->engine = strtolower($config->dbEngine);
|
||||||
$this->queryLogMax = (int) $config->dbQueryLogMax;
|
$this->charset = strtolower($config->dbCharset);
|
||||||
if($config->debug && $this->pdo) {
|
$this->stripMB4 = $config->dbStripMB4 && $this->charset != 'utf8mb4';
|
||||||
|
$this->queryLogMax = (int) $config->dbQueryLogMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($config->debug && $pdo) {
|
||||||
// custom PDO statement for debug mode
|
// custom PDO statement for debug mode
|
||||||
$this->debugMode = true;
|
$this->debugMode = true;
|
||||||
$this->pdo->setAttribute(
|
$pdo->setAttribute(
|
||||||
\PDO::ATTR_STATEMENT_CLASS,
|
\PDO::ATTR_STATEMENT_CLASS,
|
||||||
array(__NAMESPACE__ . "\\WireDatabasePDOStatement", array($this))
|
array(__NAMESPACE__ . "\\WireDatabasePDOStatement", array($this))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sqlModes = $config->dbSqlModes;
|
$sqlModes = $config->dbSqlModes;
|
||||||
|
|
||||||
if(is_array($sqlModes)) {
|
if(is_array($sqlModes)) {
|
||||||
// ["5.7.0" => "remove:mode1,mode2/add:mode3"]
|
// ["5.7.0" => "remove:mode1,mode2/add:mode3"]
|
||||||
foreach($sqlModes as $minVersion => $commands) {
|
foreach($sqlModes as $minVersion => $commands) {
|
||||||
@@ -263,7 +405,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
if(empty($modes)) continue;
|
if(empty($modes)) continue;
|
||||||
$action = 'set';
|
$action = 'set';
|
||||||
if(strpos($modes, ':')) list($action, $modes) = explode(':', $modes);
|
if(strpos($modes, ':')) list($action, $modes) = explode(':', $modes);
|
||||||
$this->sqlMode(trim($action), trim($modes), $minVersion);
|
$this->sqlMode(trim($action), trim($modes), $minVersion, $pdo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,25 +414,143 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
/**
|
/**
|
||||||
* Return the actual current PDO connection instance
|
* Return the actual current PDO connection instance
|
||||||
*
|
*
|
||||||
* If connection is lost, this will restore it automatically.
|
* If connection is lost, this will restore it automatically.
|
||||||
*
|
*
|
||||||
* #pw-group-PDO
|
* #pw-group-PDO
|
||||||
*
|
*
|
||||||
|
* @param string|\PDOStatement|null SQL, statement, or statement type (reader or primary) (3.0.175+)
|
||||||
|
*
|
||||||
* @return \PDO
|
* @return \PDO
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function pdo() {
|
public function pdo($type = null) {
|
||||||
if(!$this->pdo) {
|
if($type === null) return $this->pdoWriter();
|
||||||
$this->init = false;
|
return $this->pdoType($type);
|
||||||
$this->pdo = new \PDO(
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return read-write (primary) PDO connection
|
||||||
|
*
|
||||||
|
* @return \PDO
|
||||||
|
* @since 3.0.175
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function pdoWriter() {
|
||||||
|
if(!$this->writer['pdo']) {
|
||||||
|
$this->writer['init'] = false;
|
||||||
|
$pdo = new \PDO(
|
||||||
$this->pdoConfig['dsn'],
|
$this->pdoConfig['dsn'],
|
||||||
$this->pdoConfig['user'],
|
$this->pdoConfig['user'],
|
||||||
$this->pdoConfig['pass'],
|
$this->pdoConfig['pass'],
|
||||||
$this->pdoConfig['options']
|
$this->pdoConfig['options']
|
||||||
);
|
);
|
||||||
|
$this->writer['pdo'] = $pdo;
|
||||||
|
$this->_init($pdo);
|
||||||
|
} else {
|
||||||
|
$pdo = $this->writer['pdo'];
|
||||||
}
|
}
|
||||||
if(!$this->init) $this->_init();
|
$this->pdoLast = $pdo;
|
||||||
return $this->pdo;
|
return $pdo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return read-only PDO connection if available or read/write PDO connection if not
|
||||||
|
*
|
||||||
|
* @return \PDO
|
||||||
|
* @since 3.0.175
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function pdoReader() {
|
||||||
|
if(!$this->allowReader()) return $this->pdoWriter();
|
||||||
|
if(!$this->reader['pdo']) {
|
||||||
|
$this->reader['init'] = false;
|
||||||
|
$pdo = new \PDO(
|
||||||
|
$this->pdoConfig['reader']['dsn'],
|
||||||
|
$this->pdoConfig['reader']['user'],
|
||||||
|
$this->pdoConfig['reader']['pass'],
|
||||||
|
$this->pdoConfig['reader']['options']
|
||||||
|
);
|
||||||
|
$this->reader['pdo'] = $pdo;
|
||||||
|
$this->_init($pdo);
|
||||||
|
} else {
|
||||||
|
$pdo = $this->reader['pdo'];
|
||||||
|
}
|
||||||
|
$this->pdoLast = $pdo;
|
||||||
|
return $pdo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return correct PDO instance type (reader or writer) based on given statement
|
||||||
|
*
|
||||||
|
* @param string|\PDOStatement $statement
|
||||||
|
* @param bool $getName Get name of PDO type rather than instance? (default=false)
|
||||||
|
* @return \PDO|string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function pdoType(&$statement, $getName = false) {
|
||||||
|
|
||||||
|
$reader = 'reader';
|
||||||
|
$writer = 'writer';
|
||||||
|
|
||||||
|
if(!$this->reader['has']) return $getName ? $writer : $this->pdoWriter();
|
||||||
|
|
||||||
|
if($statement === $writer || $statement === $reader) {
|
||||||
|
$type = $statement;
|
||||||
|
} else if(!$this->reader['has']) {
|
||||||
|
$type = $writer;
|
||||||
|
} else if(!is_string($statement)) {
|
||||||
|
// PDOStatement or other, always return write
|
||||||
|
// @todo add support for inspection of PDOStatement
|
||||||
|
$type = $writer;
|
||||||
|
} else if(stripos($statement, 'select') === 0) {
|
||||||
|
$type = $reader;
|
||||||
|
} else if(stripos($statement, 'insert') === 0) {
|
||||||
|
$type = $writer;
|
||||||
|
} else {
|
||||||
|
$pos = strpos($statement, ' ');
|
||||||
|
$word = strtolower(($pos ? substr($statement, 0, $pos) : $statement));
|
||||||
|
if($word === 'set') {
|
||||||
|
// all 'set' commands are read-only allowed except autocommit and transaction
|
||||||
|
$word = trim(substr($statement, $pos + 1, 12));
|
||||||
|
if(stripos($word, 'autocommit') === 0 || stripos($word, 'transaction') === 0) {
|
||||||
|
$type = $writer;
|
||||||
|
} else {
|
||||||
|
$type = $reader;
|
||||||
|
}
|
||||||
|
} else if($word === 'lock') {
|
||||||
|
if(!$getName) $this->allowReader(false);
|
||||||
|
$type = $writer;
|
||||||
|
} else if($word === 'unlock') {
|
||||||
|
if(!$getName) $this->allowReader(true);
|
||||||
|
$type = $writer;
|
||||||
|
} else {
|
||||||
|
$type = in_array($word, $this->writer['commands']) ? $writer : $reader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($type === $reader && !$this->reader['allow']) $type = $writer;
|
||||||
|
|
||||||
|
if($getName) return $type;
|
||||||
|
|
||||||
|
return $type === 'reader' ? $this->pdoReader() : $this->pdoWriter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return last used PDO connection
|
||||||
|
*
|
||||||
|
* @return \PDO
|
||||||
|
* @since 3.0.175
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function pdoLast() {
|
||||||
|
if($this->pdoLast) {
|
||||||
|
$pdo = $this->pdoLast;
|
||||||
|
if($pdo === $this->reader['pdo'] && !$this->reader['allow']) $pdo = null;
|
||||||
|
} else {
|
||||||
|
$pdo = null;
|
||||||
|
}
|
||||||
|
if($pdo === null) $pdo = $this->pdoWriter();
|
||||||
|
return $pdo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,7 +563,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function errorCode() {
|
public function errorCode() {
|
||||||
return $this->pdo()->errorCode();
|
return $this->pdoLast()->errorCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -316,7 +576,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function errorInfo() {
|
public function errorInfo() {
|
||||||
return $this->pdo()->errorInfo();
|
return $this->pdoLast()->errorInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -330,7 +590,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function getAttribute($attribute) {
|
public function getAttribute($attribute) {
|
||||||
return $this->pdo()->getAttribute($attribute);
|
return $this->pdoLast()->getAttribute($attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -345,7 +605,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setAttribute($attribute, $value) {
|
public function setAttribute($attribute, $value) {
|
||||||
return $this->pdo()->setAttribute($attribute, $value);
|
return $this->pdoLast()->setAttribute($attribute, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -359,7 +619,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function lastInsertId($name = null) {
|
public function lastInsertId($name = null) {
|
||||||
return $this->pdo()->lastInsertId($name);
|
return $this->pdoWriter()->lastInsertId($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -375,7 +635,8 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*/
|
*/
|
||||||
public function query($statement, $note = '') {
|
public function query($statement, $note = '') {
|
||||||
if($this->debugMode) $this->queryLog($statement, $note);
|
if($this->debugMode) $this->queryLog($statement, $note);
|
||||||
return $this->pdo()->query($statement);
|
$pdo = $this->pdoType($statement);
|
||||||
|
return $pdo->query($statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -388,7 +649,8 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function beginTransaction() {
|
public function beginTransaction() {
|
||||||
return $this->pdo()->beginTransaction();
|
$this->allowReader(false);
|
||||||
|
return $this->pdoWriter()->beginTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -401,7 +663,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function inTransaction() {
|
public function inTransaction() {
|
||||||
return (bool) $this->pdo()->inTransaction();
|
return (bool) $this->pdoWriter()->inTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -416,7 +678,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
public function supportsTransaction($table = '') {
|
public function supportsTransaction($table = '') {
|
||||||
$engine = '';
|
$engine = '';
|
||||||
if($table) {
|
if($table) {
|
||||||
$query = $this->prepare('SHOW TABLE STATUS WHERE name=:name');
|
$query = $this->pdoReader()->prepare('SHOW TABLE STATUS WHERE name=:name');
|
||||||
$query->bindValue(':name', $table);
|
$query->bindValue(':name', $table);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
if($query->rowCount()) {
|
if($query->rowCount()) {
|
||||||
@@ -425,7 +687,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
}
|
}
|
||||||
$query->closeCursor();
|
$query->closeCursor();
|
||||||
} else {
|
} else {
|
||||||
$engine = $this->wire('config')->dbEngine;
|
$engine = $this->engine;
|
||||||
}
|
}
|
||||||
return strtoupper($engine) === 'INNODB';
|
return strtoupper($engine) === 'INNODB';
|
||||||
}
|
}
|
||||||
@@ -456,7 +718,8 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function commit() {
|
public function commit() {
|
||||||
return $this->pdo()->commit();
|
$this->allowReader(true);
|
||||||
|
return $this->pdoWriter()->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -469,7 +732,8 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function rollBack() {
|
public function rollBack() {
|
||||||
return $this->pdo()->rollBack();
|
$this->allowReader(true);
|
||||||
|
return $this->pdoWriter()->rollBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -513,7 +777,8 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
\PDO::ATTR_STATEMENT_CLASS => array(__NAMESPACE__ . "\\WireDatabasePDOStatement", array($this))
|
\PDO::ATTR_STATEMENT_CLASS => array(__NAMESPACE__ . "\\WireDatabasePDOStatement", array($this))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$pdoStatement = $this->pdo()->prepare($statement, $driver_options);
|
$pdo = $this->reader['has'] ? $this->pdoType($statement) : $this->pdoWriter();
|
||||||
|
$pdoStatement = $pdo->prepare($statement, $driver_options);
|
||||||
if($this->debugMode) {
|
if($this->debugMode) {
|
||||||
if($pdoStatement instanceof WireDatabasePDOStatement) {
|
if($pdoStatement instanceof WireDatabasePDOStatement) {
|
||||||
/** @var WireDatabasePDOStatement $pdoStatement */
|
/** @var WireDatabasePDOStatement $pdoStatement */
|
||||||
@@ -544,7 +809,8 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
return $this->execute($statement);
|
return $this->execute($statement);
|
||||||
}
|
}
|
||||||
if($this->debugMode) $this->queryLog($statement, $note);
|
if($this->debugMode) $this->queryLog($statement, $note);
|
||||||
return $this->pdo()->exec($statement);
|
$pdo = $this->reader['has'] ? $this->pdoType($statement) : $this->pdoWriter();
|
||||||
|
return $pdo->exec($statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -568,64 +834,31 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
* @param \PDOStatement $query
|
* @param \PDOStatement $query
|
||||||
* @param bool $throw Whether or not to throw exception on query error (default=true)
|
* @param bool $throw Whether or not to throw exception on query error (default=true)
|
||||||
* @param int $maxTries Max number of times it will attempt to retry query on error
|
* @param int $maxTries Deprecated/argument does nothing (was: “Max number of times it will attempt to retry query on error”)
|
||||||
* @return bool True on success, false on failure. Note if you want this, specify $throw=false in your arguments.
|
* @return bool True on success, false on failure. Note if you want this, specify $throw=false in your arguments.
|
||||||
* @throws \PDOException
|
* @throws \PDOException
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function execute(\PDOStatement $query, $throw = true, $maxTries = 3) {
|
public function execute(\PDOStatement $query, $throw = true, $maxTries = 3) {
|
||||||
|
|
||||||
$tryAgain = 0;
|
try {
|
||||||
$_throw = $throw;
|
$result = $query->execute();
|
||||||
|
} catch(\PDOException $e) {
|
||||||
do {
|
$result = false;
|
||||||
try {
|
if($query->errorCode() == '42S22') {
|
||||||
$result = $query->execute();
|
// unknown column error
|
||||||
|
$errorInfo = $query->errorInfo();
|
||||||
} catch(\PDOException $e) {
|
if(preg_match('/[\'"]([_a-z0-9]+\.[_a-z0-9]+)[\'"]/i', $errorInfo[2], $matches)) {
|
||||||
|
$this->unknownColumnError($matches[1]);
|
||||||
$result = false;
|
|
||||||
$error = $e->getMessage();
|
|
||||||
$throw = false; // temporarily disable while we try more
|
|
||||||
|
|
||||||
if($tryAgain === 0) {
|
|
||||||
// setup retry loop
|
|
||||||
$tryAgain = $maxTries;
|
|
||||||
} else {
|
|
||||||
// decrement retry loop
|
|
||||||
$tryAgain--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stripos($error, 'MySQL server has gone away') !== false) {
|
|
||||||
// forces reconection on next query
|
|
||||||
$this->wire('database')->closeConnection();
|
|
||||||
|
|
||||||
} else if($query->errorCode() == '42S22') {
|
|
||||||
// unknown column error
|
|
||||||
$errorInfo = $query->errorInfo();
|
|
||||||
if(preg_match('/[\'"]([_a-z0-9]+\.[_a-z0-9]+)[\'"]/i', $errorInfo[2], $matches)) {
|
|
||||||
$this->unknownColumnError($matches[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// some other error that we don't have retry plans for
|
|
||||||
// tryAgain=0 will force the loop to stop
|
|
||||||
$tryAgain = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($tryAgain < 1) {
|
|
||||||
// if at end of retry loop, restore original throw state
|
|
||||||
$throw = $_throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($throw) {
|
|
||||||
throw $e;
|
|
||||||
} else {
|
|
||||||
$this->error($error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if($throw) {
|
||||||
} while($tryAgain && !$result);
|
throw $e;
|
||||||
|
} else {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
if($maxTries) {} // ignore, argument no longer used
|
||||||
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@@ -677,6 +910,10 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
$this->queryLog['error'] = "$qty additional queries omitted because \$config->dbQueryLogMax = $this->queryLogMax";
|
$this->queryLog['error'] = "$qty additional queries omitted because \$config->dbQueryLogMax = $this->queryLogMax";
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
if($this->reader['has']) {
|
||||||
|
$type = $this->pdoType($sql, true);
|
||||||
|
$note = trim("$note [$type]");
|
||||||
|
}
|
||||||
$this->queryLog[] = $sql . ($note ? " -- $note" : "");
|
$this->queryLog[] = $sql . ($note ? " -- $note" : "");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -966,9 +1203,9 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*/
|
*/
|
||||||
public function quote($str) {
|
public function quote($str) {
|
||||||
if($this->stripMB4 && is_string($str) && !empty($str)) {
|
if($this->stripMB4 && is_string($str) && !empty($str)) {
|
||||||
$str = $this->wire('sanitizer')->removeMB4($str);
|
$str = $this->wire()->sanitizer->removeMB4($str);
|
||||||
}
|
}
|
||||||
return $this->pdo()->quote($str);
|
return $this->pdoLast()->quote($str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1004,6 +1241,8 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*/
|
*/
|
||||||
public function __get($key) {
|
public function __get($key) {
|
||||||
if($key === 'pdo') return $this->pdo();
|
if($key === 'pdo') return $this->pdo();
|
||||||
|
if($key === 'pdoReader') return $this->pdoReader();
|
||||||
|
if($key === 'pdoWriter') return $this->pdoWriter();
|
||||||
if($key === 'debugMode') return $this->debugMode;
|
if($key === 'debugMode') return $this->debugMode;
|
||||||
return parent::__get($key);
|
return parent::__get($key);
|
||||||
}
|
}
|
||||||
@@ -1015,7 +1254,10 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function closeConnection() {
|
public function closeConnection() {
|
||||||
$this->pdo = null;
|
$this->reader['pdo'] = null;
|
||||||
|
$this->writer['pdo'] = null;
|
||||||
|
$this->reader['init'] = false;
|
||||||
|
$this->writer['init'] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1044,6 +1286,7 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
/** @noinspection PhpUnusedLocalVariableInspection */
|
/** @noinspection PhpUnusedLocalVariableInspection */
|
||||||
list($varName, $value) = $query->fetch(\PDO::FETCH_NUM);
|
list($varName, $value) = $query->fetch(\PDO::FETCH_NUM);
|
||||||
$this->variableCache[$name] = $value;
|
$this->variableCache[$name] = $value;
|
||||||
|
$query->closeCursor();
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1119,17 +1362,17 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
*/
|
*/
|
||||||
public function backups() {
|
public function backups() {
|
||||||
|
|
||||||
$path = $this->wire('config')->paths->assets . 'backups/database/';
|
$path = $this->wire()->config->paths->assets . 'backups/database/';
|
||||||
if(!is_dir($path)) {
|
if(!is_dir($path)) {
|
||||||
$this->wire('files')->mkdir($path, true);
|
$this->wire()->files->mkdir($path, true);
|
||||||
if(!is_dir($path)) throw new WireException("Unable to create path for backups: $path");
|
if(!is_dir($path)) throw new WireException("Unable to create path for backups: $path");
|
||||||
}
|
}
|
||||||
|
|
||||||
$backups = new WireDatabaseBackup($path);
|
$backups = new WireDatabaseBackup($path);
|
||||||
$backups->setWire($this->wire());
|
$backups->setWire($this->wire());
|
||||||
$backups->setDatabase($this);
|
$backups->setDatabase($this);
|
||||||
$backups->setDatabaseConfig($this->wire('config'));
|
$backups->setDatabaseConfig($this->wire()->config);
|
||||||
$backups->setBackupOptions(array('user' => $this->wire('user')->name));
|
$backups->setBackupOptions(array('user' => $this->wire()->user->name));
|
||||||
|
|
||||||
return $backups;
|
return $backups;
|
||||||
}
|
}
|
||||||
@@ -1152,6 +1395,22 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
return $max;
|
return $max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable PDO reader instance, or omit argument to get current state
|
||||||
|
*
|
||||||
|
* Returns true if reader is configured and allowed
|
||||||
|
* Returns false if reader is not configured or not allowed
|
||||||
|
*
|
||||||
|
* @param bool $allow
|
||||||
|
* @return bool
|
||||||
|
* @since 3.0.175
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function allowReader($allow = null) {
|
||||||
|
if($allow !== null) $this->reader['allow'] = (bool) $allow;
|
||||||
|
return $this->reader['has'] && $this->reader['allow'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get SQL mode, set SQL mode, add to existing SQL mode, or remove from existing SQL mode
|
* Get SQL mode, set SQL mode, add to existing SQL mode, or remove from existing SQL mode
|
||||||
*
|
*
|
||||||
@@ -1172,15 +1431,22 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
* @param string $mode Mode string or CSV string with SQL mode(s), i.e. "STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY".
|
* @param string $mode Mode string or CSV string with SQL mode(s), i.e. "STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY".
|
||||||
* This argument should be omitted when using the "get" action.
|
* This argument should be omitted when using the "get" action.
|
||||||
* @param string $minVersion Make the given action only apply if MySQL version is at least $minVersion, i.e. "5.7.0".
|
* @param string $minVersion Make the given action only apply if MySQL version is at least $minVersion, i.e. "5.7.0".
|
||||||
|
* @param \PDO PDO connection to use or omit for current (default=null) 3.0.175+
|
||||||
* @return string|bool Returns string in "get" action, boolean false if required version not present, or true otherwise.
|
* @return string|bool Returns string in "get" action, boolean false if required version not present, or true otherwise.
|
||||||
* @throws WireException If given an invalid $action
|
* @throws WireException If given an invalid $action
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function sqlMode($action = 'get', $mode = '', $minVersion = '') {
|
public function sqlMode($action = 'get', $mode = '', $minVersion = '', $pdo = null) {
|
||||||
|
|
||||||
$result = true;
|
$result = true;
|
||||||
$modes = array();
|
$modes = array();
|
||||||
|
|
||||||
|
if($pdo === null) {
|
||||||
|
$pdo = $this->pdoLast();
|
||||||
|
} else {
|
||||||
|
$this->pdoLast = $pdo;
|
||||||
|
}
|
||||||
|
|
||||||
if(empty($action)) $action = 'get';
|
if(empty($action)) $action = 'get';
|
||||||
|
|
||||||
if($action !== 'get' && $minVersion) {
|
if($action !== 'get' && $minVersion) {
|
||||||
@@ -1190,29 +1456,29 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
|
|
||||||
if($mode) {
|
if($mode) {
|
||||||
foreach(explode(',', $mode) as $m) {
|
foreach(explode(',', $mode) as $m) {
|
||||||
$modes[] = $this->escapeStr(strtoupper($this->wire('sanitizer')->fieldName($m)));
|
$modes[] = $this->escapeStr(strtoupper($this->wire()->sanitizer->fieldName($m)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch($action) {
|
switch($action) {
|
||||||
case 'get':
|
case 'get':
|
||||||
$query = $this->pdo()->query("SELECT @@sql_mode");
|
$query = $pdo->query("SELECT @@sql_mode");
|
||||||
$result = $query->fetchColumn();
|
$result = $query->fetchColumn();
|
||||||
$query->closeCursor();
|
$query->closeCursor();
|
||||||
break;
|
break;
|
||||||
case 'set':
|
case 'set':
|
||||||
$modes = implode(',', $modes);
|
$modes = implode(',', $modes);
|
||||||
$result = $modes;
|
$result = $modes;
|
||||||
$this->pdo()->exec("SET sql_mode='$modes'");
|
$pdo->exec("SET sql_mode='$modes'");
|
||||||
break;
|
break;
|
||||||
case 'add':
|
case 'add':
|
||||||
foreach($modes as $m) {
|
foreach($modes as $m) {
|
||||||
$this->pdo()->exec("SET sql_mode=(SELECT CONCAT(@@sql_mode,',$m'))");
|
$pdo->exec("SET sql_mode=(SELECT CONCAT(@@sql_mode,',$m'))");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'remove':
|
case 'remove':
|
||||||
foreach($modes as $m) {
|
foreach($modes as $m) {
|
||||||
$this->pdo()->exec("SET sql_mode=(SELECT REPLACE(@@sql_mode,'$m',''))");
|
$pdo->exec("SET sql_mode=(SELECT REPLACE(@@sql_mode,'$m',''))");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1221,5 +1487,6 @@ class WireDatabasePDO extends Wire implements WireDatabase {
|
|||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user