1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 10:59:02 +01:00

Optimize mysql usage. Remove prepare.

This commit is contained in:
Alexander Pankratov 2021-02-27 22:58:01 +03:00
parent 9094c19687
commit 7fe10430be
3 changed files with 107 additions and 98 deletions

View File

@ -15,7 +15,6 @@ use danog\MadelineProto\Settings\Database\Mysql as DatabaseMysql;
class MysqlArray extends SqlArray class MysqlArray extends SqlArray
{ {
protected DatabaseMysql $dbSettings; protected DatabaseMysql $dbSettings;
private Pool $db;
// Legacy // Legacy
protected array $settings; protected array $settings;
@ -35,38 +34,36 @@ class MysqlArray extends SqlArray
* *
* @param SqlArray::STATEMENT_* $type * @param SqlArray::STATEMENT_* $type
* *
* @return Promise * @return string
*/ */
protected function prepareStatements(int $type): Promise protected function getSqlQuery(int $type): string
{ {
switch ($type) { switch ($type) {
case SqlArray::STATEMENT_GET: case SqlArray::SQL_GET:
return $this->db->prepare( return "SELECT `value` FROM `{$this->table}` WHERE `key` = :index LIMIT 1";
"SELECT `value` FROM `{$this->table}` WHERE `key` = :index LIMIT 1" case SqlArray::SQL_SET:
); return "
case SqlArray::STATEMENT_SET: INSERT INTO `{$this->table}`
return $this->db->prepare(" SET `key` = :index, `value` = :value
INSERT INTO `{$this->table}` ON DUPLICATE KEY UPDATE `value` = :value
SET `key` = :index, `value` = :value ";
ON DUPLICATE KEY UPDATE `value` = :value case SqlArray::SQL_UNSET:
"); return "
case SqlArray::STATEMENT_UNSET: DELETE FROM `{$this->table}`
return $this->db->prepare(" WHERE `key` = :index
DELETE FROM `{$this->table}` ";
WHERE `key` = :index case SqlArray::SQL_COUNT:
"); return "
case SqlArray::STATEMENT_COUNT: SELECT count(`key`) as `count` FROM `{$this->table}`
return $this->db->prepare(" ";
SELECT count(`key`) as `count` FROM `{$this->table}` case SqlArray::SQL_ITERATE:
"); return "
case SqlArray::STATEMENT_ITERATE: SELECT `key`, `value` FROM `{$this->table}`
return $this->db->prepare(" ";
SELECT `key`, `value` FROM `{$this->table}` case SqlArray::SQL_CLEAR:
"); return "
case SqlArray::STATEMENT_CLEAR: DELETE FROM `{$this->table}`
return $this->db->prepare(" ";
DELETE FROM `{$this->table}`
");
} }
throw new Exception("An invalid statement type $type was provided!"); throw new Exception("An invalid statement type $type was provided!");
} }
@ -97,6 +94,7 @@ class MysqlArray extends SqlArray
*/ */
public function initConnection($settings): \Generator public function initConnection($settings): \Generator
{ {
$this->pdo = new \PDO('mysql:');
if (!isset($this->db)) { if (!isset($this->db)) {
$this->db = yield from Mysql::getConnection($settings); $this->db = yield from Mysql::getConnection($settings);
} }

View File

@ -17,7 +17,6 @@ use danog\MadelineProto\Settings\Database\Postgres as DatabasePostgres;
class PostgresArray extends SqlArray class PostgresArray extends SqlArray
{ {
public DatabasePostgres $dbSettings; public DatabasePostgres $dbSettings;
private Pool $db;
// Legacy // Legacy
protected array $settings; protected array $settings;
@ -27,39 +26,37 @@ class PostgresArray extends SqlArray
* *
* @param SqlArray::STATEMENT_* $type * @param SqlArray::STATEMENT_* $type
* *
* @return Promise * @return string
*/ */
protected function prepareStatements(int $type): Promise protected function getSqlQuery(int $type): string
{ {
switch ($type) { switch ($type) {
case SqlArray::STATEMENT_GET: case SqlArray::SQL_GET:
return $this->db->prepare( return "SELECT value FROM \"{$this->table}\" WHERE key = :index LIMIT 1";
"SELECT value FROM \"{$this->table}\" WHERE key = :index LIMIT 1", case SqlArray::SQL_SET:
); return "
case SqlArray::STATEMENT_SET:
return $this->db->prepare("
INSERT INTO \"{$this->table}\" INSERT INTO \"{$this->table}\"
(key,value) (key,value)
VALUES (:index, :value) VALUES (:index, :value)
ON CONFLICT (key) DO UPDATE SET value = :value ON CONFLICT (key) DO UPDATE SET value = :value
"); ";
case SqlArray::STATEMENT_UNSET: case SqlArray::SQL_UNSET:
return $this->db->prepare(" return "
DELETE FROM \"{$this->table}\" DELETE FROM \"{$this->table}\"
WHERE key = :index WHERE key = :index
"); ";
case SqlArray::STATEMENT_COUNT: case SqlArray::SQL_COUNT:
return $this->db->prepare(" return "
SELECT count(key) as count FROM \"{$this->table}\" SELECT count(key) as count FROM \"{$this->table}\"
"); ";
case SqlArray::STATEMENT_ITERATE: case SqlArray::SQL_ITERATE:
return $this->db->prepare(" return "
SELECT key, value FROM \"{$this->table}\" SELECT key, value FROM \"{$this->table}\"
"); ";
case SqlArray::STATEMENT_CLEAR: case SqlArray::SQL_CLEAR:
return $this->db->prepare(" return "
DELETE FROM \"{$this->table}\" DELETE FROM \"{$this->table}\"
"); ";
} }
throw new Exception("An invalid statement type $type was provided!"); throw new Exception("An invalid statement type $type was provided!");
} }
@ -81,6 +78,7 @@ class PostgresArray extends SqlArray
*/ */
public function initConnection($settings): \Generator public function initConnection($settings): \Generator
{ {
$this->pdo = new \PDO('postgre:');
if (!isset($this->db)) { if (!isset($this->db)) {
$this->db = yield from Postgres::getConnection($settings); $this->db = yield from Postgres::getConnection($settings);
} }
@ -130,7 +128,7 @@ class PostgresArray extends SqlArray
$this->setCache($index, $value); $this->setCache($index, $value);
$request = $this->execute( $request = $this->execute(
self::STATEMENT_SET, $this->getSqlQuery(self::SQL_SET),
[ [
'index' => $index, 'index' => $index,
'value' => new ByteA(\serialize($value)), 'value' => new ByteA(\serialize($value)),

View File

@ -4,8 +4,9 @@ namespace danog\MadelineProto\Db;
use Amp\Producer; use Amp\Producer;
use Amp\Promise; use Amp\Promise;
use Amp\Sql\CommandResult;
use Amp\Sql\Pool;
use Amp\Sql\ResultSet; use Amp\Sql\ResultSet;
use Amp\Sql\Statement;
use Amp\Success; use Amp\Success;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
@ -16,19 +17,16 @@ use function Amp\call;
*/ */
abstract class SqlArray extends DriverArray abstract class SqlArray extends DriverArray
{ {
/** protected Pool $db;
* Statement array. //Pdo driver used for value quoting, to prevent sql injections.
* protected \PDO $pdo;
* @var Statement[]
*/
private array $statements = [];
protected const STATEMENT_GET = 0; protected const SQL_GET = 0;
protected const STATEMENT_SET = 1; protected const SQL_SET = 1;
protected const STATEMENT_UNSET = 2; protected const SQL_UNSET = 2;
protected const STATEMENT_COUNT = 3; protected const SQL_COUNT = 3;
protected const STATEMENT_ITERATE = 4; protected const SQL_ITERATE = 4;
protected const STATEMENT_CLEAR = 5; protected const SQL_CLEAR = 5;
/** /**
@ -36,9 +34,9 @@ abstract class SqlArray extends DriverArray
* *
* @param SqlArray::STATEMENT_* $type * @param SqlArray::STATEMENT_* $type
* *
* @return Promise * @return string
*/ */
abstract protected function prepareStatements(int $type): Promise; abstract protected function getSqlQuery(int $type): string;
/** /**
* Get value from row. * Get value from row.
@ -51,11 +49,9 @@ abstract class SqlArray extends DriverArray
public function getIterator(): Producer public function getIterator(): Producer
{ {
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
return new Producer(function (callable $emit) { return new Producer(function (callable $emit) {
if (!isset($this->statements[self::STATEMENT_ITERATE])) { $request = yield from $this->executeRaw($this->getSqlQuery(self::SQL_ITERATE));
$this->statements[self::STATEMENT_ITERATE] = yield $this->prepareStatements(self::STATEMENT_ITERATE);
}
$request = yield $this->statements[self::STATEMENT_ITERATE]->execute();
while (yield $request->advance()) { while (yield $request->advance()) {
$row = $request->getCurrent(); $row = $request->getCurrent();
@ -106,7 +102,7 @@ abstract class SqlArray extends DriverArray
$this->unsetCache($index); $this->unsetCache($index);
return $this->execute( return $this->execute(
self::STATEMENT_UNSET, $this->getSqlQuery(self::SQL_UNSET),
['index' => $index] ['index' => $index]
); );
} }
@ -122,7 +118,7 @@ abstract class SqlArray extends DriverArray
public function count(): Promise public function count(): Promise
{ {
return call(function () { return call(function () {
$row = yield $this->execute(self::STATEMENT_COUNT); $row = yield $this->execute($this->getSqlQuery(self::SQL_COUNT));
return $row[0]['count'] ?? 0; return $row[0]['count'] ?? 0;
}); });
} }
@ -134,7 +130,7 @@ abstract class SqlArray extends DriverArray
*/ */
public function clear(): Promise public function clear(): Promise
{ {
return $this->execute(self::STATEMENT_CLEAR); return $this->execute($this->getSqlQuery(self::SQL_CLEAR));
} }
public function offsetGet($offset): Promise public function offsetGet($offset): Promise
@ -144,7 +140,7 @@ abstract class SqlArray extends DriverArray
return $cached; return $cached;
} }
$row = yield $this->execute(self::STATEMENT_GET, ['index' => $offset]); $row = yield $this->execute($this->getSqlQuery(self::SQL_GET), ['index' => $offset]);
if ($value = $this->getValue($row)) { if ($value = $this->getValue($row)) {
$this->setCache($offset, $value); $this->setCache($offset, $value);
@ -176,7 +172,7 @@ abstract class SqlArray extends DriverArray
$this->setCache($index, $value); $this->setCache($index, $value);
$request = $this->execute( $request = $this->execute(
self::STATEMENT_SET, $this->getSqlQuery(self::SQL_SET),
[ [
'index' => $index, 'index' => $index,
'value' => \serialize($value), 'value' => \serialize($value),
@ -192,34 +188,18 @@ abstract class SqlArray extends DriverArray
/** /**
* Perform async request to db. * Perform async request to db.
* *
* @param int $stmt * @param string $sql
* @param array $params * @param array $params
* *
* @psalm-param self::STATEMENT_* $stmt * @psalm-param self::STATEMENT_* $stmt
* *
* @return Promise * @return Promise<array>
* @throws \Throwable * @throws \Throwable
*/ */
protected function execute(int $stmt, array $params = []): Promise protected function execute(string $sql, array $params = []): Promise
{ {
return call(function () use ($stmt, $params) { return call(function () use ($sql, $params) {
if ( $request = yield from $this->executeRaw($sql, $params);
!empty($params['index'])
&& !\mb_check_encoding($params['index'], 'UTF-8')
) {
$params['index'] = \mb_convert_encoding($params['index'], 'UTF-8');
}
if (!isset($this->statements[$stmt])) {
$this->statements[$stmt] = yield $this->prepareStatements($stmt);
}
try {
$request = yield $this->statements[$stmt]->execute($params);
} catch (\Throwable $e) {
Logger::log($e->getMessage(), Logger::ERROR);
return [];
}
$result = []; $result = [];
if ($request instanceof ResultSet) { if ($request instanceof ResultSet) {
while (yield $request->advance()) { while (yield $request->advance()) {
@ -229,4 +209,37 @@ abstract class SqlArray extends DriverArray
return $result; return $result;
}); });
} }
/**
* Return raw query result.
*
* @param string $sql
* @param array $params
*
* @return \Generator<CommandResult|ResultSet>
*/
protected function executeRaw(string $sql, array $params = []): \Generator
{
if (
!empty($params['index'])
&& !\mb_check_encoding($params['index'], 'UTF-8')
) {
$params['index'] = \mb_convert_encoding($params['index'], 'UTF-8');
}
try {
foreach ($params as $key => $value) {
$value = $this->pdo->quote($value);
$sql = str_replace(":$key", $value, $sql);
}
$request = yield $this->db->query($sql);
} catch (\Throwable $e) {
Logger::log($e->getMessage(), Logger::ERROR);
return [];
}
return $request;
}
} }