mirror of
https://github.com/vrana/adminer.git
synced 2025-08-30 09:39:51 +02:00
MySQL: Print comments of stored procedures and functions
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
$PROCEDURE = ($_GET["name"] ? $_GET["name"] : $_GET["call"]);
|
||||
|
||||
$PROCEDURE = ($_GET["name"] ?: $_GET["call"]);
|
||||
page_header(lang('Call') . ": " . h($PROCEDURE), $error);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
$query = (isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . table($PROCEDURE) . "(" . implode(", ", $call) . ")";
|
||||
$start = microtime(true);
|
||||
$result = $connection->multi_query($query);
|
||||
$affected = $connection->affected_rows; // getting warnigns overwrites this
|
||||
echo $adminer->selectQuery($query, $start, !$result);
|
||||
|
||||
|
||||
if (!$result) {
|
||||
echo "<p class='error'>" . error() . "\n";
|
||||
} else {
|
||||
@@ -42,7 +43,7 @@ if (!$error && $_POST) {
|
||||
if (is_object($connection2)) {
|
||||
$connection2->select_db(DB);
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
$result = $connection->store_result();
|
||||
if (is_object($result)) {
|
||||
@@ -53,16 +54,15 @@ if (!$error && $_POST) {
|
||||
;
|
||||
}
|
||||
} while ($connection->next_result());
|
||||
|
||||
|
||||
if ($out) {
|
||||
select($connection->query("SELECT " . implode(", ", $out)));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<form action="" method="post">
|
||||
<?php
|
||||
echo "<form action='' method='post'>\n";
|
||||
|
||||
if ($in) {
|
||||
echo "<table cellspacing='0' class='layout'>\n";
|
||||
foreach ($in as $key) {
|
||||
@@ -83,8 +83,28 @@ if ($in) {
|
||||
}
|
||||
echo "</table>\n";
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<input type="submit" value="<?php echo lang('Call'); ?>">
|
||||
<input type="hidden" name="token" value="<?php echo $token; ?>">
|
||||
</form>
|
||||
|
||||
echo "<p>",
|
||||
"<input type='submit' value='", lang('Call'), "'>",
|
||||
"<input type='hidden' name='token' value='$token'>",
|
||||
"</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")) {
|
||||
echo "<h3 id='routines'>" . lang('Routines') . "</h3>\n";
|
||||
|
||||
$routines = routines();
|
||||
if ($routines) {
|
||||
$commentsSupported = $routines[0]["ROUTINE_COMMENT"] !== null;
|
||||
|
||||
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('');
|
||||
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
|
||||
echo '<tr' . odd() . '>';
|
||||
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 '<td>' . h($row["DTD_IDENTIFIER"]);
|
||||
echo '<td><a href="' . h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'function=' : 'procedure=') . urlencode($row["SPECIFIC_NAME"]) . $name) . '">' . lang('Alter') . "</a>";
|
||||
// not computed on the pages to be able to print the header first
|
||||
$name = ($row["SPECIFIC_NAME"] == $row["ROUTINE_NAME"] ? "" : "&name=" . urlencode($row["ROUTINE_NAME"]));
|
||||
|
||||
echo '<tr', odd(), '>',
|
||||
'<th><a href="', h(ME . ($row["ROUTINE_TYPE"] != "PROCEDURE" ? 'callf=' : 'call=') . urlencode($row["SPECIFIC_NAME"]) . $name), '">', h($row["ROUTINE_NAME"]), '</a></th>',
|
||||
'<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 '<p class="links">'
|
||||
. (support("procedure") ? '<a href="' . h(ME) . 'procedure=">' . lang('Create procedure') . '</a>' : '')
|
||||
. '<a href="' . h(ME) . 'function=">' . lang('Create function') . "</a>\n"
|
||||
;
|
||||
|
||||
echo '<p class="links">',
|
||||
(support("procedure") ? '<a href="' . h(ME) . 'procedure=">' . lang('Create procedure') . '</a>' : ''),
|
||||
'<a href="' . h(ME) . 'function=">' . lang('Create function') . "</a>\n";
|
||||
}
|
||||
|
||||
if (support("sequence")) {
|
||||
|
@@ -901,23 +901,30 @@ if (!defined("DRIVER")) {
|
||||
);
|
||||
}
|
||||
|
||||
/** Get information about stored routine
|
||||
* @param string
|
||||
* @param string "FUNCTION" or "PROCEDURE"
|
||||
* @return array ("fields" => array("field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ), "returns" => , "definition" => , "language" => )
|
||||
*/
|
||||
/**
|
||||
* Gets information about stored routine.
|
||||
*
|
||||
* @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) {
|
||||
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)";
|
||||
$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";
|
||||
$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);
|
||||
$fields = array();
|
||||
$fields = [];
|
||||
preg_match_all("~$pattern\\s*,?~is", $match[1], $matches, PREG_SET_ORDER);
|
||||
|
||||
foreach ($matches as $param) {
|
||||
$fields[] = array(
|
||||
$fields[] = [
|
||||
"field" => str_replace("``", "`", $param[2]) . $param[3],
|
||||
"type" => strtolower($param[5]),
|
||||
"length" => preg_replace_callback("~$enum_length~s", 'normalize_enum', $param[6]),
|
||||
@@ -926,24 +933,29 @@ if (!defined("DRIVER")) {
|
||||
"full_type" => $param[4],
|
||||
"inout" => strtoupper($param[1]),
|
||||
"collation" => strtolower($param[9]),
|
||||
);
|
||||
];
|
||||
}
|
||||
if ($type != "FUNCTION") {
|
||||
return array("fields" => $fields, "definition" => $match[11]);
|
||||
}
|
||||
return array(
|
||||
|
||||
return $type == "FUNCTION" ? [
|
||||
"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],
|
||||
"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
|
||||
* @return array ("SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => )
|
||||
*/
|
||||
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
|
||||
|
@@ -668,23 +668,29 @@ ORDER BY connamespace, conname") as $row) {
|
||||
}
|
||||
|
||||
function routine($name, $type) {
|
||||
$rows = get_rows('SELECT routine_definition AS definition, LOWER(external_language) AS language, *
|
||||
FROM information_schema.routines
|
||||
WHERE routine_schema = current_schema() AND specific_name = ' . q($name));
|
||||
$return = $rows[0];
|
||||
$return["returns"] = array("type" => $return["type_udt_name"]);
|
||||
$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
|
||||
WHERE specific_schema = current_schema() AND specific_name = ' . q($name) . '
|
||||
ORDER BY ordinal_position');
|
||||
return $return;
|
||||
$info = get_rows('SELECT routine_definition, external_language, type_udt_name
|
||||
FROM information_schema.routines
|
||||
WHERE routine_schema = current_schema() AND specific_name = ' . q($name))[0];
|
||||
|
||||
$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
|
||||
WHERE specific_schema = current_schema() AND specific_name = ' . q($name) . '
|
||||
ORDER BY ordinal_position');
|
||||
|
||||
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() {
|
||||
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"
|
||||
FROM information_schema.routines
|
||||
WHERE routine_schema = current_schema()
|
||||
ORDER BY SPECIFIC_NAME');
|
||||
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
|
||||
WHERE routine_schema = current_schema()
|
||||
ORDER BY SPECIFIC_NAME');
|
||||
}
|
||||
|
||||
function routine_languages() {
|
||||
|
@@ -830,6 +830,8 @@ function is_utf8($val) {
|
||||
* @return string escaped string with appended ...
|
||||
*/
|
||||
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
|
||||
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, textarea { font: 110%/1.25 monospace; }
|
||||
pre.jush { background: #fff; }
|
||||
pre.comment { white-space: pre-wrap; }
|
||||
form + pre.comment { margin-top: 2em; }
|
||||
input, textarea, select { box-sizing: border-box; }
|
||||
input[type="image"] { vertical-align: middle; margin-top: -3px; }
|
||||
input[type="number"] { -moz-appearance: textfield; }
|
||||
|
Reference in New Issue
Block a user