mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
showqueries debugging tool now inserts parameters in place (#5885)
This commit is contained in:
parent
a9df28c791
commit
f25b88b146
@ -39,8 +39,8 @@ Append the option and corresponding value to your URL in your browser's address
|
|||||||
## Database
|
## Database
|
||||||
|
|
||||||
| URL Variable | | Values | | Description |
|
| URL Variable | | Values | | Description |
|
||||||
| ------------ | | ------ | | ----------- |
|
| ------------ | | --------- | | ----------- |
|
||||||
| showqueries | | 1 | | List all SQL queries executed |
|
| showqueries | | 1\|inline | | List all SQL queries executed, the `inline` option will do a fudge replacement of parameterised queries |
|
||||||
| previewwrite | | 1 | | List all insert / update SQL queries, and **don't** execute them. Useful for previewing writes to the database. |
|
| previewwrite | | 1 | | List all insert / update SQL queries, and **don't** execute them. Useful for previewing writes to the database. |
|
||||||
|
|
||||||
## Security Redirects
|
## Security Redirects
|
||||||
|
56
model/DB.php
56
model/DB.php
@ -282,7 +282,7 @@ class DB {
|
|||||||
*
|
*
|
||||||
* @param array|integer $input An array of items needing placeholders, or a
|
* @param array|integer $input An array of items needing placeholders, or a
|
||||||
* number to specify the number of placeholders
|
* number to specify the number of placeholders
|
||||||
* @param string The string to join each placeholder together with
|
* @param string $join The string to join each placeholder together with
|
||||||
* @return string|null Either a list of placeholders, or null
|
* @return string|null Either a list of placeholders, or null
|
||||||
*/
|
*/
|
||||||
public static function placeholders($input, $join = ', ') {
|
public static function placeholders($input, $join = ', ') {
|
||||||
@ -297,6 +297,60 @@ class DB {
|
|||||||
return implode($join, array_fill(0, $number, '?'));
|
return implode($join, array_fill(0, $number, '?'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $sql The parameterised query
|
||||||
|
* @param array $parameters The parameters to inject into the query
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function inline_parameters($sql, $parameters) {
|
||||||
|
$segments = preg_split('/\?/', $sql);
|
||||||
|
$joined = '';
|
||||||
|
$inString = false;
|
||||||
|
$numSegments = count($segments);
|
||||||
|
for($i = 0; $i < $numSegments; $i++) {
|
||||||
|
$input = $segments[$i];
|
||||||
|
// Append next segment
|
||||||
|
$joined .= $segments[$i];
|
||||||
|
// Don't add placeholder after last segment
|
||||||
|
if($i === $numSegments - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check string escape on previous fragment
|
||||||
|
// Remove escaped backslashes, count them!
|
||||||
|
$input = preg_replace('/\\\\\\\\/', '', $input);
|
||||||
|
// Count quotes
|
||||||
|
$totalQuotes = substr_count($input, "'"); // Includes double quote escaped quotes
|
||||||
|
$escapedQuotes = substr_count($input, "\\'");
|
||||||
|
if((($totalQuotes - $escapedQuotes) % 2) !== 0) {
|
||||||
|
$inString = !$inString;
|
||||||
|
}
|
||||||
|
// Append placeholder replacement
|
||||||
|
if($inString) {
|
||||||
|
// Literal question mark
|
||||||
|
$joined .= '?';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode and insert next parameter
|
||||||
|
$next = array_shift($parameters);
|
||||||
|
if(is_array($next) && isset($next['value'])) {
|
||||||
|
$next = $next['value'];
|
||||||
|
}
|
||||||
|
if (is_bool($next)) {
|
||||||
|
$value = $next ? '1' : '0';
|
||||||
|
}
|
||||||
|
elseif (is_int($next)) {
|
||||||
|
$value = $next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$value = DB::is_active() ? Convert::raw2sql($next, true) : $next;
|
||||||
|
}
|
||||||
|
$joined .= $value;
|
||||||
|
}
|
||||||
|
return $joined;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the given SQL parameterised query with the specified arguments
|
* Execute the given SQL parameterised query with the specified arguments
|
||||||
*
|
*
|
||||||
|
@ -141,7 +141,8 @@ abstract class SS_Database {
|
|||||||
$sql,
|
$sql,
|
||||||
function($sql) use($connector, $parameters, $errorLevel) {
|
function($sql) use($connector, $parameters, $errorLevel) {
|
||||||
return $connector->preparedQuery($sql, $parameters, $errorLevel);
|
return $connector->preparedQuery($sql, $parameters, $errorLevel);
|
||||||
}
|
},
|
||||||
|
$parameters
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,13 +175,18 @@ abstract class SS_Database {
|
|||||||
*
|
*
|
||||||
* @param string $sql Query to run, and single parameter to callback
|
* @param string $sql Query to run, and single parameter to callback
|
||||||
* @param callable $callback Callback to execute code
|
* @param callable $callback Callback to execute code
|
||||||
|
* @param array $parameters Parameters for any parameterised query
|
||||||
* @return mixed Result of query
|
* @return mixed Result of query
|
||||||
*/
|
*/
|
||||||
protected function benchmarkQuery($sql, $callback) {
|
protected function benchmarkQuery($sql, $callback, $parameters = array()) {
|
||||||
if (isset($_REQUEST['showqueries']) && Director::isDev()) {
|
if (isset($_REQUEST['showqueries']) && Director::isDev()) {
|
||||||
$starttime = microtime(true);
|
$starttime = microtime(true);
|
||||||
$result = $callback($sql);
|
$result = $callback($sql);
|
||||||
$endtime = round(microtime(true) - $starttime, 4);
|
$endtime = round(microtime(true) - $starttime, 4);
|
||||||
|
// replace parameters as closely as possible to what we'd expect the DB to put in
|
||||||
|
if (strtolower($_REQUEST['showqueries']) == 'inline') {
|
||||||
|
$sql = DB::inline_parameters($sql, $parameters);
|
||||||
|
}
|
||||||
Debug::message("\n$sql\n{$endtime}s\n", false);
|
Debug::message("\n$sql\n{$endtime}s\n", false);
|
||||||
return $result;
|
return $result;
|
||||||
} else {
|
} else {
|
||||||
|
@ -160,35 +160,7 @@ class SQLQuery_ParameterInjector {
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function injectValues($sql, $parameters) {
|
protected function injectValues($sql, $parameters) {
|
||||||
$segments = preg_split('/\?/', $sql);
|
return DB::inline_parameters($sql, $parameters);
|
||||||
$joined = '';
|
|
||||||
$inString = false;
|
|
||||||
for($i = 0; $i < count($segments); $i++) {
|
|
||||||
// Append next segment
|
|
||||||
$joined .= $segments[$i];
|
|
||||||
// Don't add placeholder after last segment
|
|
||||||
if($i === count($segments) - 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// check string escape on previous fragment
|
|
||||||
if($this->checkStringTogglesLiteral($segments[$i])) {
|
|
||||||
$inString = !$inString;
|
|
||||||
}
|
|
||||||
// Append placeholder replacement
|
|
||||||
if($inString) {
|
|
||||||
// Literal questionmark
|
|
||||||
$joined .= '?';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode and insert next parameter
|
|
||||||
$next = array_shift($parameters);
|
|
||||||
if(is_array($next) && isset($next['value'])) {
|
|
||||||
$next = $next['value'];
|
|
||||||
}
|
|
||||||
$joined .= "'".Convert::raw2sql($next)."'";
|
|
||||||
}
|
|
||||||
return $joined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user