namespace Friendica\Database;
-use Friendica\Core\Config\IConfigCache;
-use Friendica\Core\Logger;
+use Friendica\Core\Config\Cache\IConfigCache;
use Friendica\Core\System;
use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Profiler;
use mysqli;
use mysqli_result;
use mysqli_stmt;
use PDO;
use PDOException;
use PDOStatement;
+use Psr\Log\LoggerInterface;
/**
* @class MySQL database class
/**
* @var IConfigCache
*/
- private static $config;
+ private static $configCache;
+ /**
+ * @var Profiler
+ */
+ private static $profiler;
+ /**
+ * @var LoggerInterface
+ */
+ private static $logger;
+ /**
+ * @var string
+ */
+ private static $basePath;
private static $server_info = '';
private static $connection;
private static $driver;
private static $db_name = '';
private static $db_charset = '';
- public static function connect($config, $serveraddr, $user, $pass, $db, $charset = null)
+ public static function connect($basePath, IConfigCache $configCache, Profiler $profiler, LoggerInterface $logger, $serveraddr, $user, $pass, $db, $charset = null)
{
if (!is_null(self::$connection) && self::connected()) {
return true;
}
// We are storing these values for being able to perform a reconnect
- self::$config = $config;
+ self::$basePath = $basePath;
+ self::$configCache = $configCache;
+ self::$profiler = $profiler;
+ self::$logger = $logger;
self::$db_serveraddr = $serveraddr;
self::$db_user = $user;
self::$db_pass = $pass;
return self::$connected;
}
+ /**
+ * Sets the logger for DBA
+ *
+ * @note this is necessary because if we want to load the logger configuration
+ * from the DB, but there's an error, we would print out an exception.
+ * So the logger gets updated after the logger configuration can be retrieved
+ * from the database
+ *
+ * @param LoggerInterface $logger
+ */
+ public static function setLogger(LoggerInterface $logger)
+ {
+ self::$logger = $logger;
+ }
+
/**
* Disconnects the current database connection
*/
public static function reconnect() {
self::disconnect();
- $ret = self::connect(self::$config, self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
+ $ret = self::connect(self::$basePath, self::$configCache, self::$profiler, self::$logger, self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
return $ret;
}
*/
private static function logIndex($query) {
- if (!self::$config->get('system', 'db_log_index')) {
+ if (!self::$configCache->get('system', 'db_log_index')) {
return;
}
return;
}
- $watchlist = explode(',', self::$config->get('system', 'db_log_index_watch'));
- $blacklist = explode(',', self::$config->get('system', 'db_log_index_blacklist'));
+ $watchlist = explode(',', self::$configCache->get('system', 'db_log_index_watch'));
+ $blacklist = explode(',', self::$configCache->get('system', 'db_log_index_blacklist'));
while ($row = self::fetch($r)) {
- if ((intval(self::$config->get('system', 'db_loglimit_index')) > 0)) {
+ if ((intval(self::$configCache->get('system', 'db_loglimit_index')) > 0)) {
$log = (in_array($row['key'], $watchlist) &&
- ($row['rows'] >= intval(self::$config->get('system', 'db_loglimit_index'))));
+ ($row['rows'] >= intval(self::$configCache->get('system', 'db_loglimit_index'))));
} else {
$log = false;
}
- if ((intval(self::$config->get('system', 'db_loglimit_index_high')) > 0) && ($row['rows'] >= intval($Config::getConfigValue('system', 'db_loglimit_index_high')))) {
+ if ((intval(self::$configCache->get('system', 'db_loglimit_index_high')) > 0) && ($row['rows'] >= intval(self::$configCache->get('system', 'db_loglimit_index_high')))) {
$log = true;
}
if ($log) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
- @file_put_contents(self::$config->get('system', 'db_log_index'), DateTimeFormat::utcNow()."\t".
+ @file_put_contents(self::$configCache->get('system', 'db_log_index'), DateTimeFormat::utcNow()."\t".
$row['key']."\t".$row['rows']."\t".$row['Extra']."\t".
basename($backtrace[1]["file"])."\t".
$backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
* @throws \Exception
*/
public static function p($sql) {
- $a = \get_app();
$stamp1 = microtime(true);
if ((substr_count($sql, '?') != count($args)) && (count($args) > 0)) {
// Question: Should we continue or stop the query here?
- Logger::log('Parameter mismatch. Query "'.$sql.'" - Parameters '.print_r($args, true), Logger::DEBUG);
+ self::$logger->warning('Query parameters mismatch.', ['query' => $sql, 'args' => $args, 'callstack' => System::callstack()]);
}
$sql = self::cleanQuery($sql);
$orig_sql = $sql;
- if (self::$config->get('system', 'db_callstack')) {
+ if (self::$configCache->get('system', 'db_callstack') !== null) {
$sql = "/*".System::callstack()." */ ".$sql;
}
$error = self::$error;
$errorno = self::$errorno;
- Logger::log('DB Error '.self::$errorno.': '.self::$error."\n".
- System::callstack(8)."\n".self::replaceParameters($sql, $args));
+ self::$logger->error('DB Error', [
+ 'code' => self::$errorno,
+ 'error' => self::$error,
+ 'callstack' => System::callstack(8),
+ 'params' => self::replaceParameters($sql, $args),
+ ]);
// On a lost connection we try to reconnect - but only once.
if ($errorno == 2006) {
if (self::$in_retrial || !self::reconnect()) {
// It doesn't make sense to continue when the database connection was lost
if (self::$in_retrial) {
- Logger::log('Giving up retrial because of database error '.$errorno.': '.$error);
+ self::$logger->notice('Giving up retrial because of database error', [
+ 'code' => self::$errorno,
+ 'error' => self::$error,
+ ]);
} else {
- Logger::log("Couldn't reconnect after database error ".$errorno.': '.$error);
+ self::$logger->notice('Couldn\'t reconnect after database error', [
+ 'code' => self::$errorno,
+ 'error' => self::$error,
+ ]);
}
exit(1);
} else {
// We try it again
- Logger::log('Reconnected after database error '.$errorno.': '.$error);
+ self::$logger->notice('Reconnected after database error', [
+ 'code' => self::$errorno,
+ 'error' => self::$error,
+ ]);
self::$in_retrial = true;
$ret = self::p($sql, $args);
self::$in_retrial = false;
self::$errorno = $errorno;
}
- $a->saveTimestamp($stamp1, 'database');
+ self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
- if (self::$config->get('system', 'db_log')) {
+ if (self::$configCache->get('system', 'db_log')) {
$stamp2 = microtime(true);
$duration = (float)($stamp2 - $stamp1);
- if (($duration > self::$config->get('system', 'db_loglimit'))) {
+ if (($duration > self::$configCache->get('system', 'db_loglimit'))) {
$duration = round($duration, 3);
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
- @file_put_contents(self::$config->get('system', 'db_log'), DateTimeFormat::utcNow()."\t".$duration."\t".
+ @file_put_contents(self::$configCache->get('system', 'db_log'), DateTimeFormat::utcNow()."\t".$duration."\t".
basename($backtrace[1]["file"])."\t".
$backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
substr(self::replaceParameters($sql, $args), 0, 2000)."\n", FILE_APPEND);
* @throws \Exception
*/
public static function e($sql) {
- $a = \get_app();
$stamp = microtime(true);
$error = self::$error;
$errorno = self::$errorno;
- Logger::log('DB Error '.self::$errorno.': '.self::$error."\n".
- System::callstack(8)."\n".self::replaceParameters($sql, $params));
+ self::$logger->error('DB Error', [
+ 'code' => self::$errorno,
+ 'error' => self::$error,
+ 'callstack' => System::callstack(8),
+ 'params' => self::replaceParameters($sql, $params),
+ ]);
// On a lost connection we simply quit.
// A reconnect like in self::p could be dangerous with modifications
if ($errorno == 2006) {
- Logger::log('Giving up because of database error '.$errorno.': '.$error);
+ self::$logger->error('Giving up because of database error', [
+ 'code' => self::$errorno,
+ 'error' => self::$error,
+ ]);
exit(1);
}
self::$errorno = $errorno;
}
- $a->saveTimestamp($stamp, "database_write");
+ self::$profiler->saveTimestamp($stamp, "database_write", System::callstack());
return $retval;
}
* @return array current row
*/
public static function fetch($stmt) {
- $a = \get_app();
$stamp1 = microtime(true);
}
}
- $a->saveTimestamp($stamp1, 'database');
+ self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
return $columns;
}
public static function insert($table, $param, $on_duplicate_update = false) {
if (empty($table) || empty($param)) {
- Logger::log('Table and fields have to be set');
+ self::$logger->info('Table and fields have to be set');
return false;
}
* This process must only be started once, since the value is cached.
*/
private static function buildRelationData() {
- $definition = DBStructure::definition(self::$config->get('system', 'basepath'));
+ $definition = DBStructure::definition(self::$basePath);
foreach ($definition AS $table => $structure) {
foreach ($structure['fields'] AS $field => $field_struct) {
public static function delete($table, array $conditions, array $options = [], array &$callstack = [])
{
if (empty($table) || empty($conditions)) {
- Logger::log('Table and conditions have to be set');
+ self::$logger->info('Table and conditions have to be set');
return false;
}
if ((count($command['conditions']) > 1) || is_int($first_key)) {
$sql = "DELETE FROM `" . $command['table'] . "`" . $condition_string;
- Logger::log(self::replaceParameters($sql, $conditions), Logger::DATA);
+ self::$logger->debug(self::replaceParameters($sql, $conditions));
if (!self::e($sql, $conditions)) {
if ($do_transaction) {
$sql = "DELETE FROM `" . $table . "` WHERE `" . $field . "` IN (" .
substr(str_repeat("?, ", count($field_values)), 0, -2) . ");";
- Logger::log(self::replaceParameters($sql, $field_values), Logger::DATA);
+ self::$logger->debug(self::replaceParameters($sql, $field_values));
if (!self::e($sql, $field_values)) {
if ($do_transaction) {
public static function update($table, $fields, $condition, $old_fields = []) {
if (empty($table) || empty($fields) || empty($condition)) {
- Logger::log('Table, fields and condition have to be set');
+ self::$logger->info('Table, fields and condition have to be set');
return false;
}
}
$limit_string = '';
- if (isset($params['limit']) && is_int($params['limit'])) {
+ if (isset($params['limit']) && is_numeric($params['limit'])) {
$limit_string = " LIMIT " . intval($params['limit']);
}
* @return boolean was the close successful?
*/
public static function close($stmt) {
- $a = \get_app();
$stamp1 = microtime(true);
break;
}
- $a->saveTimestamp($stamp1, 'database');
+ self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
return $ret;
}