2021-10-25 19:49:12 -07:00
|
|
|
<?php
|
2025-03-29 10:50:03 +00:00
|
|
|
|
2022-02-14 20:48:15 -08:00
|
|
|
/**
|
|
|
|
|
* Records PDO queries to display on exception page.
|
2021-10-25 19:49:12 -07:00
|
|
|
*
|
2022-02-14 20:48:15 -08:00
|
|
|
* @package NamelessMC\Database
|
|
|
|
|
* @see ErrorHandler
|
|
|
|
|
* @author Aberdeener
|
|
|
|
|
* @version 2.0.0-pr13
|
|
|
|
|
* @license MIT
|
2021-10-25 19:49:12 -07:00
|
|
|
*/
|
2024-03-09 03:19:55 -08:00
|
|
|
class QueryRecorder extends Instanceable
|
|
|
|
|
{
|
2022-06-13 02:21:21 +00:00
|
|
|
private array $_query_stack = [];
|
2021-10-25 19:49:12 -07:00
|
|
|
private int $_query_stack_num = 1;
|
|
|
|
|
|
2021-11-03 22:15:44 -07:00
|
|
|
/**
|
|
|
|
|
* Get an array of all the SQL queries that have been executed in this request.
|
|
|
|
|
*
|
|
|
|
|
* @return array SQL queries
|
|
|
|
|
*/
|
2024-03-09 03:19:55 -08:00
|
|
|
public function getSqlStack(): array
|
|
|
|
|
{
|
2023-06-12 10:31:01 -06:00
|
|
|
$stack = array_reverse($this->_query_stack);
|
|
|
|
|
|
|
|
|
|
// Compile queries - replace bound parameters with their values and syntax highlight
|
|
|
|
|
foreach ($stack as &$query) {
|
|
|
|
|
$query['sql_query'] = $this->compileQuery(
|
|
|
|
|
$query['sql_string'],
|
|
|
|
|
$query['sql_params']
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $stack;
|
2021-10-25 19:49:12 -07:00
|
|
|
}
|
|
|
|
|
|
2021-11-03 22:15:44 -07:00
|
|
|
/**
|
|
|
|
|
* Add a query to the stack.
|
|
|
|
|
*
|
2024-03-09 03:19:55 -08:00
|
|
|
* @param string $sql Raw SQL query executed
|
|
|
|
|
* @param array $params Bound parameters used in the query
|
2021-11-03 22:15:44 -07:00
|
|
|
*/
|
2024-03-09 03:19:55 -08:00
|
|
|
public function pushQuery(string $sql, array $params): void
|
|
|
|
|
{
|
2022-06-17 22:46:42 -06:00
|
|
|
if (!Debugging::canViewDetailedError()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-03 22:15:44 -07:00
|
|
|
$backtrace = $this->lastReleventBacktrace();
|
2021-10-25 19:49:12 -07:00
|
|
|
|
|
|
|
|
$this->_query_stack[] = [
|
|
|
|
|
'number' => $this->_query_stack_num,
|
|
|
|
|
'frame' => ErrorHandler::parseFrame(null, $backtrace['file'], $backtrace['line'], $this->_query_stack_num),
|
2023-06-12 10:31:01 -06:00
|
|
|
'sql_string' => $sql,
|
|
|
|
|
'sql_params' => $params,
|
2021-10-25 19:49:12 -07:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$this->_query_stack_num++;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-03 22:15:44 -07:00
|
|
|
/**
|
2022-03-29 14:57:56 -07:00
|
|
|
* Get the last debug_backtrace entry which is not the file that executed this query or a database class.
|
2021-11-03 22:15:44 -07:00
|
|
|
*
|
|
|
|
|
* @return array debug_backtrace entry
|
|
|
|
|
*/
|
2024-03-09 03:19:55 -08:00
|
|
|
private function lastReleventBacktrace(): array
|
|
|
|
|
{
|
2022-06-27 21:16:06 -06:00
|
|
|
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
2021-10-25 19:49:12 -07:00
|
|
|
|
|
|
|
|
$current_file = $last_file = $backtrace[0]['file'];
|
|
|
|
|
$i = 1;
|
|
|
|
|
|
2022-03-29 14:57:56 -07:00
|
|
|
while (
|
|
|
|
|
$current_file === $last_file
|
2023-02-21 15:43:09 +01:00
|
|
|
|| str_ends_with($backtrace[$i]['file'], 'DB.php')
|
2022-03-29 14:57:56 -07:00
|
|
|
) {
|
2021-10-25 19:49:12 -07:00
|
|
|
$last_file = $backtrace[$i]['file'];
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $backtrace[$i];
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-03 22:15:44 -07:00
|
|
|
/**
|
|
|
|
|
* Get a compiled SQL query with bound parameters replaced with their values
|
|
|
|
|
* and syntax highlighted.
|
|
|
|
|
*
|
2024-03-09 03:19:55 -08:00
|
|
|
* @param string $sql Raw SQL query
|
|
|
|
|
* @param array $params Bound parameters
|
2021-11-03 22:15:44 -07:00
|
|
|
* @return string Compiled + syntax highlighted SQL query
|
|
|
|
|
*/
|
2024-03-09 03:19:55 -08:00
|
|
|
private function compileQuery(string $sql, array $params): string
|
|
|
|
|
{
|
2021-10-25 19:49:12 -07:00
|
|
|
$comp = '';
|
|
|
|
|
|
|
|
|
|
$split = explode(' ?', $sql);
|
|
|
|
|
|
|
|
|
|
$i = 0;
|
|
|
|
|
foreach ($split as $section) {
|
|
|
|
|
if ($section == '') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 15:53:28 -08:00
|
|
|
if (!isset($params[$i])) {
|
|
|
|
|
$comp .= $section;
|
|
|
|
|
$i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 19:49:12 -07:00
|
|
|
$param = $params[$i];
|
|
|
|
|
|
|
|
|
|
$comp .= "$section '$param'";
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 23:31:17 -07:00
|
|
|
if (!str_ends_with($comp, ';')) {
|
|
|
|
|
$comp .= ';';
|
|
|
|
|
}
|
2021-10-25 19:49:12 -07:00
|
|
|
|
2021-12-05 08:17:24 -08:00
|
|
|
return SqlFormatter::highlight(trim($comp));
|
2021-10-25 19:49:12 -07:00
|
|
|
}
|
2021-11-02 23:37:19 -07:00
|
|
|
}
|