mirror of
https://github.com/vrana/adminer.git
synced 2025-09-01 18:32:39 +02:00
MySQL: Print comments of stored procedures and functions
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
$PROCEDURE = ($_GET["name"] ? $_GET["name"] : $_GET["call"]);
|
|
||||||
|
$PROCEDURE = ($_GET["name"] ?: $_GET["call"]);
|
||||||
page_header(lang('Call') . ": " . h($PROCEDURE), $error);
|
page_header(lang('Call') . ": " . h($PROCEDURE), $error);
|
||||||
|
|
||||||
$routine = routine($_GET["call"], (isset($_GET["callf"]) ? "FUNCTION" : "PROCEDURE"));
|
$routine = routine($_GET["call"], (isset($_GET["callf"]) ? "FUNCTION" : "PROCEDURE"));
|
||||||
@@ -28,13 +29,13 @@ if (!$error && $_POST) {
|
|||||||
}
|
}
|
||||||
$call[] = (isset($out[$key]) ? "@" . idf_escape($field["field"]) : $val);
|
$call[] = (isset($out[$key]) ? "@" . idf_escape($field["field"]) : $val);
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = (isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . table($PROCEDURE) . "(" . implode(", ", $call) . ")";
|
$query = (isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . table($PROCEDURE) . "(" . implode(", ", $call) . ")";
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$result = $connection->multi_query($query);
|
$result = $connection->multi_query($query);
|
||||||
$affected = $connection->affected_rows; // getting warnigns overwrites this
|
$affected = $connection->affected_rows; // getting warnigns overwrites this
|
||||||
echo $adminer->selectQuery($query, $start, !$result);
|
echo $adminer->selectQuery($query, $start, !$result);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
echo "<p class='error'>" . error() . "\n";
|
echo "<p class='error'>" . error() . "\n";
|
||||||
} else {
|
} else {
|
||||||
@@ -42,7 +43,7 @@ if (!$error && $_POST) {
|
|||||||
if (is_object($connection2)) {
|
if (is_object($connection2)) {
|
||||||
$connection2->select_db(DB);
|
$connection2->select_db(DB);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$result = $connection->store_result();
|
$result = $connection->store_result();
|
||||||
if (is_object($result)) {
|
if (is_object($result)) {
|
||||||
@@ -53,16 +54,15 @@ if (!$error && $_POST) {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
} while ($connection->next_result());
|
} while ($connection->next_result());
|
||||||
|
|
||||||
if ($out) {
|
if ($out) {
|
||||||
select($connection->query("SELECT " . implode(", ", $out)));
|
select($connection->query("SELECT " . implode(", ", $out)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
|
||||||
<form action="" method="post">
|
echo "<form action='' method='post'>\n";
|
||||||
<?php
|
|
||||||
if ($in) {
|
if ($in) {
|
||||||
echo "<table cellspacing='0' class='layout'>\n";
|
echo "<table cellspacing='0' class='layout'>\n";
|
||||||
foreach ($in as $key) {
|
foreach ($in as $key) {
|
||||||
@@ -83,8 +83,28 @@ if ($in) {
|
|||||||
}
|
}
|
||||||
echo "</table>\n";
|
echo "</table>\n";
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
<p>
|
echo "<p>",
|
||||||
<input type="submit" value="<?php echo lang('Call'); ?>">
|
"<input type='submit' value='", lang('Call'), "'>",
|
||||||
<input type="hidden" name="token" value="<?php echo $token; ?>">
|
"<input type='hidden' name='token' value='$token'>",
|
||||||
</form>
|
"</p>\n",
|
||||||
|
"</form>\n";
|
||||||
|
|
||||||
|
$comment = $routine["comment"];
|
||||||
|
if ($comment !== null && $comment !== "") {
|
||||||
|
$comment = h(trim($routine["comment"], "\n"));
|
||||||
|
|
||||||
|
// Remove indenting of all lines (used in MySQL routines in 'sys' database).
|
||||||
|
if (preg_match('~^ +~', $comment, $matches)) {
|
||||||
|
preg_match_all("~^($matches[0]|$)~m", $comment, $linesWithIndent);
|
||||||
|
|
||||||
|
if (count($linesWithIndent[0]) == substr_count($comment, "\n")) {
|
||||||
|
$comment = preg_replace("~^($matches[0])~m", "", $comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format common headlines (used in MySQL routines in 'sys' database).
|
||||||
|
$comment = preg_replace('~(^|[^\n]\n)(Description|Parameters|Example)\n~', "$1\n<strong>$2</strong>\n", $comment);
|
||||||
|
|
||||||
|
echo "<pre class='comment'>$comment</pre>\n";
|
||||||
|
}
|
||||||
|
@@ -182,25 +182,43 @@ if ($adminer->homepage()) {
|
|||||||
|
|
||||||
if (support("routine")) {
|
if (support("routine")) {
|
||||||
echo "<h3 id='routines'>" . lang('Routines') . "</h3>\n";
|
echo "<h3 id='routines'>" . lang('Routines') . "</h3>\n";
|
||||||
|
|
||||||
$routines = routines();
|
$routines = routines();
|
||||||
if ($routines) {
|
if ($routines) {
|
||||||
|
$commentsSupported = $routines[0]["ROUTINE_COMMENT"] !== null;
|
||||||
|
|
||||||
echo "<table>\n";
|
echo "<table>\n";
|
||||||
echo '<thead><tr><th>' . lang('Name') . '<td>' . lang('Type') . '<td>' . lang('Return type') . "<td></thead>\n";
|
echo '<thead><tr>',
|
||||||
|
'<th>', lang('Name'), '</th><td>', lang('Type'), '</td><td>', lang('Return type'), "</td>";
|
||||||
|
if ($commentsSupported) {
|
||||||
|
echo "<td>", lang('Comment'), "</td>";
|
||||||
|
}
|
||||||
|
echo "<td></td>",
|
||||||
|
"</tr></thead>\n";
|
||||||
|
|
||||||
odd('');
|
odd('');
|
||||||
foreach ($routines as $row) {
|
foreach ($routines as $row) {
|
||||||
$name = ($row["SPECIFIC_NAME"] == $row["ROUTINE_NAME"] ? "" : "&name=" . urlencode($row["ROUTINE_NAME"])); // not computed on the pages to be able to print the header first
|
// not computed on the pages to be able to print the header first
|
||||||
echo '<tr' . odd() . '>';
|
$name = ($row["SPECIFIC_NAME"] == $row["ROUTINE_NAME"] ? "" : "&name=" . urlencode($row["ROUTINE_NAME"]));
|
||||||
echo '<th><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'callf=' : 'call=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . h($row["ROUTINE_NAME"]) . '</a>';
|
|
||||||
echo '<td>' . h($row["ROUTINE_TYPE"]);
|
echo '<tr', odd(), '>',
|
||||||
echo '<td>' . h($row["DTD_IDENTIFIER"]);
|
'<th><a href="', h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'callf=' : 'call=') . urlencode($row["SPECIFIC_NAME"]) . $name), '">', h($row["ROUTINE_NAME"]), '</a></th>',
|
||||||
echo '<td><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'function=' : 'procedure=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . lang('Alter') . "</a>";
|
'<td>', h($row["ROUTINE_TYPE"]), '</td>',
|
||||||
|
'<td>', h($row["DTD_IDENTIFIER"]), '</td>';
|
||||||
|
|
||||||
|
if ($commentsSupported) {
|
||||||
|
echo '<td>', shorten_utf8(preg_replace('~\s{2,}~', " ", trim($row["ROUTINE_COMMENT"])), 50), '</td>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<td><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'function=' : 'procedure=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . lang('Alter') . "</a></td>";
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "</table>\n";
|
echo "</table>\n";
|
||||||
}
|
}
|
||||||
echo '<p class="links">'
|
|
||||||
. (support("procedure") ? '<a href="' . h(ME) . 'procedure=">' . lang('Create procedure') . '</a>' : '')
|
echo '<p class="links">',
|
||||||
. '<a href="' . h(ME) . 'function=">' . lang('Create function') . "</a>\n"
|
(support("procedure") ? '<a href="' . h(ME) . 'procedure=">' . lang('Create procedure') . '</a>' : ''),
|
||||||
;
|
'<a href="' . h(ME) . 'function=">' . lang('Create function') . "</a>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (support("sequence")) {
|
if (support("sequence")) {
|
||||||
|
@@ -901,23 +901,30 @@ if (!defined("DRIVER")) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get information about stored routine
|
/**
|
||||||
* @param string
|
* Gets information about stored routine.
|
||||||
* @param string "FUNCTION" or "PROCEDURE"
|
*
|
||||||
* @return array ("fields" => array("field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ), "returns" => , "definition" => , "language" => )
|
* @param string $name
|
||||||
*/
|
* @param string $type "FUNCTION" or "PROCEDURE"
|
||||||
|
*
|
||||||
|
* @return array ("fields" => array("field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ), "returns" => , "definition" => , "language" => )
|
||||||
|
*/
|
||||||
function routine($name, $type) {
|
function routine($name, $type) {
|
||||||
global $connection, $enum_length, $inout, $types;
|
global $connection, $enum_length, $inout, $types;
|
||||||
$aliases = array("bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar");
|
|
||||||
|
$info = get_rows("SELECT ROUTINE_BODY, ROUTINE_COMMENT FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB) . " AND ROUTINE_NAME = " . q($name))[0];
|
||||||
|
|
||||||
|
$aliases = ["bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar"];
|
||||||
$space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)";
|
$space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)";
|
||||||
$type_pattern = "((" . implode("|", array_merge(array_keys($types), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$enum_length)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
|
$type_pattern = "((" . implode("|", array_merge(array_keys($types), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$enum_length)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
|
||||||
$pattern = "$space*(" . ($type == "FUNCTION" ? "" : $inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
|
$pattern = "$space*(" . ($type == "FUNCTION" ? "" : $inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
|
||||||
$create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2);
|
$create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2);
|
||||||
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
|
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
|
||||||
$fields = array();
|
$fields = [];
|
||||||
preg_match_all("~$pattern\\s*,?~is", $match[1], $matches, PREG_SET_ORDER);
|
preg_match_all("~$pattern\\s*,?~is", $match[1], $matches, PREG_SET_ORDER);
|
||||||
|
|
||||||
foreach ($matches as $param) {
|
foreach ($matches as $param) {
|
||||||
$fields[] = array(
|
$fields[] = [
|
||||||
"field" => str_replace("``", "`", $param[2]) . $param[3],
|
"field" => str_replace("``", "`", $param[2]) . $param[3],
|
||||||
"type" => strtolower($param[5]),
|
"type" => strtolower($param[5]),
|
||||||
"length" => preg_replace_callback("~$enum_length~s", 'normalize_enum', $param[6]),
|
"length" => preg_replace_callback("~$enum_length~s", 'normalize_enum', $param[6]),
|
||||||
@@ -926,24 +933,29 @@ if (!defined("DRIVER")) {
|
|||||||
"full_type" => $param[4],
|
"full_type" => $param[4],
|
||||||
"inout" => strtoupper($param[1]),
|
"inout" => strtoupper($param[1]),
|
||||||
"collation" => strtolower($param[9]),
|
"collation" => strtolower($param[9]),
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
if ($type != "FUNCTION") {
|
|
||||||
return array("fields" => $fields, "definition" => $match[11]);
|
return $type == "FUNCTION" ? [
|
||||||
}
|
|
||||||
return array(
|
|
||||||
"fields" => $fields,
|
"fields" => $fields,
|
||||||
"returns" => array("type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]),
|
"returns" => ["type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]],
|
||||||
"definition" => $match[17],
|
"definition" => $match[17],
|
||||||
"language" => "SQL", // available in information_schema.ROUTINES.PARAMETER_STYLE
|
"language" => $info["ROUTINE_BODY"],
|
||||||
);
|
"comment" => $info["ROUTINE_COMMENT"],
|
||||||
|
] : [
|
||||||
|
"fields" => $fields,
|
||||||
|
"returns" => null,
|
||||||
|
"definition" => $match[11],
|
||||||
|
"language" => $info["ROUTINE_BODY"],
|
||||||
|
"comment" => $info["ROUTINE_COMMENT"],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get list of routines
|
/** Get list of routines
|
||||||
* @return array ("SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => )
|
* @return array ("SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => )
|
||||||
*/
|
*/
|
||||||
function routines() {
|
function routines() {
|
||||||
return get_rows("SELECT ROUTINE_NAME AS SPECIFIC_NAME, ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB));
|
return get_rows("SELECT ROUTINE_NAME AS SPECIFIC_NAME, ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, ROUTINE_COMMENT FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get list of available routine languages
|
/** Get list of available routine languages
|
||||||
|
@@ -668,23 +668,29 @@ ORDER BY connamespace, conname") as $row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function routine($name, $type) {
|
function routine($name, $type) {
|
||||||
$rows = get_rows('SELECT routine_definition AS definition, LOWER(external_language) AS language, *
|
$info = get_rows('SELECT routine_definition, external_language, type_udt_name
|
||||||
FROM information_schema.routines
|
FROM information_schema.routines
|
||||||
WHERE routine_schema = current_schema() AND specific_name = ' . q($name));
|
WHERE routine_schema = current_schema() AND specific_name = ' . q($name))[0];
|
||||||
$return = $rows[0];
|
|
||||||
$return["returns"] = array("type" => $return["type_udt_name"]);
|
$fields = get_rows('SELECT parameter_name AS field, data_type AS type, character_maximum_length AS length, parameter_mode AS inout
|
||||||
$return["fields"] = get_rows('SELECT parameter_name AS field, data_type AS type, character_maximum_length AS length, parameter_mode AS inout
|
FROM information_schema.parameters
|
||||||
FROM information_schema.parameters
|
WHERE specific_schema = current_schema() AND specific_name = ' . q($name) . '
|
||||||
WHERE specific_schema = current_schema() AND specific_name = ' . q($name) . '
|
ORDER BY ordinal_position');
|
||||||
ORDER BY ordinal_position');
|
|
||||||
return $return;
|
return [
|
||||||
|
"fields" => $fields,
|
||||||
|
"returns" => ["type" => $info["type_udt_name"]],
|
||||||
|
"definition" => $info["routine_definition"],
|
||||||
|
"language" => strtolower($info["external_language"]),
|
||||||
|
"comment" => null, // Comments are not supported.
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function routines() {
|
function routines() {
|
||||||
return get_rows('SELECT specific_name AS "SPECIFIC_NAME", routine_type AS "ROUTINE_TYPE", routine_name AS "ROUTINE_NAME", type_udt_name AS "DTD_IDENTIFIER"
|
return get_rows('SELECT specific_name AS "SPECIFIC_NAME", routine_name AS "ROUTINE_NAME", routine_type AS "ROUTINE_TYPE", type_udt_name AS "DTD_IDENTIFIER", null AS ROUTINE_COMMENT
|
||||||
FROM information_schema.routines
|
FROM information_schema.routines
|
||||||
WHERE routine_schema = current_schema()
|
WHERE routine_schema = current_schema()
|
||||||
ORDER BY SPECIFIC_NAME');
|
ORDER BY SPECIFIC_NAME');
|
||||||
}
|
}
|
||||||
|
|
||||||
function routine_languages() {
|
function routine_languages() {
|
||||||
|
@@ -830,6 +830,8 @@ function is_utf8($val) {
|
|||||||
* @return string escaped string with appended ...
|
* @return string escaped string with appended ...
|
||||||
*/
|
*/
|
||||||
function shorten_utf8($string, $length = 80, $suffix = "") {
|
function shorten_utf8($string, $length = 80, $suffix = "") {
|
||||||
|
if ($string == "") return $suffix;
|
||||||
|
|
||||||
if (!preg_match("(^(" . repeat_pattern("[\t\r\n -\x{10FFFF}]", $length) . ")($)?)u", $string, $match)) { // ~s causes trash in $match[2] under some PHP versions, (.|\n) is slow
|
if (!preg_match("(^(" . repeat_pattern("[\t\r\n -\x{10FFFF}]", $length) . ")($)?)u", $string, $match)) { // ~s causes trash in $match[2] under some PHP versions, (.|\n) is slow
|
||||||
preg_match("(^(" . repeat_pattern("[\t\r\n -~]", $length) . ")($)?)", $string, $match);
|
preg_match("(^(" . repeat_pattern("[\t\r\n -~]", $length) . ")($)?)", $string, $match);
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,8 @@ pre { margin: 1em 0 0; }
|
|||||||
pre code { display: block; font-size: 100%; }
|
pre code { display: block; font-size: 100%; }
|
||||||
pre, textarea { font: 110%/1.25 monospace; }
|
pre, textarea { font: 110%/1.25 monospace; }
|
||||||
pre.jush { background: #fff; }
|
pre.jush { background: #fff; }
|
||||||
|
pre.comment { white-space: pre-wrap; }
|
||||||
|
form + pre.comment { margin-top: 2em; }
|
||||||
input, textarea, select { box-sizing: border-box; }
|
input, textarea, select { box-sizing: border-box; }
|
||||||
input[type="image"] { vertical-align: middle; margin-top: -3px; }
|
input[type="image"] { vertical-align: middle; margin-top: -3px; }
|
||||||
input[type="number"] { -moz-appearance: textfield; }
|
input[type="number"] { -moz-appearance: textfield; }
|
||||||
|
Reference in New Issue
Block a user