From e81334ef8743730fd22349b1443ad1d0d33a9b3f Mon Sep 17 00:00:00 2001 From: Jakub Vrana Date: Tue, 30 Jan 2018 15:18:26 +0100 Subject: [PATCH] PostgreSQL: Support functions --- adminer/call.inc.php | 4 ++-- adminer/db.inc.php | 5 ++-- adminer/drivers/mysql.inc.php | 13 ++++++++-- adminer/drivers/pgsql.inc.php | 42 +++++++++++++++++++-------------- adminer/include/editing.inc.php | 6 ++--- adminer/procedure.inc.php | 13 +++++----- changes.txt | 1 + 7 files changed, 51 insertions(+), 33 deletions(-) diff --git a/adminer/call.inc.php b/adminer/call.inc.php index cc64027a..9ceb398f 100644 --- a/adminer/call.inc.php +++ b/adminer/call.inc.php @@ -1,8 +1,8 @@ $field) { diff --git a/adminer/db.inc.php b/adminer/db.inc.php index 671c232f..9439a30b 100644 --- a/adminer/db.inc.php +++ b/adminer/db.inc.php @@ -159,11 +159,12 @@ if ($adminer->homepage()) { echo '' . lang('Name') . '' . lang('Type') . '' . lang('Return type') . " \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 ''; - echo '' . h($row["ROUTINE_NAME"]) . ''; + echo '' . h($row["ROUTINE_NAME"]) . ''; echo '' . h($row["ROUTINE_TYPE"]); echo '' . h($row["DTD_IDENTIFIER"]); - echo '' . lang('Alter') . ""; + echo '' . lang('Alter') . ""; } echo "\n"; } diff --git a/adminer/drivers/mysql.inc.php b/adminer/drivers/mysql.inc.php index 6504536c..5adbac83 100644 --- a/adminer/drivers/mysql.inc.php +++ b/adminer/drivers/mysql.inc.php @@ -840,10 +840,10 @@ if (!defined("DRIVER")) { } /** Get list of routines - * @return array ("ROUTINE_TYPE" => , "ROUTINE_NAME" => , "DTD_IDENTIFIER" => ) + * @return array ("SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => ) */ function routines() { - return get_rows("SELECT 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 FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB)); } /** Get list of available routine languages @@ -853,6 +853,15 @@ if (!defined("DRIVER")) { return array(); // "SQL" not required } + /** Get routine signature + * @param string + * @param array result of routine() + * @return string + */ + function routine_id($name, $row) { + return idf_escape($name); + } + /** Get last auto increment ID * @return string */ diff --git a/adminer/drivers/pgsql.inc.php b/adminer/drivers/pgsql.inc.php index 793a02ff..cd24826f 100644 --- a/adminer/drivers/pgsql.inc.php +++ b/adminer/drivers/pgsql.inc.php @@ -541,30 +541,36 @@ ORDER BY conkey, conname") as $row) { ); } - /* function routine($name, $type) { - //! there can be more functions with the same name differing only in parameters, it must be also passed to DROP FUNCTION - //! no procedures, only functions - //! different syntax of CREATE FUNCTION - $rows = get_rows('SELECT pg_catalog.format_type(p.prorettype, NULL) AS "returns", p.prosrc AS "definition" -FROM pg_catalog.pg_namespace n -JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid -WHERE n.nspname = current_schema() AND p.proname = ' . q($name)); - $rows[0]["fields"] = array(); //! - return $rows[0]; + $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; } - */ function routines() { - return get_rows('SELECT p.proname AS "ROUTINE_NAME", p.proargtypes AS "ROUTINE_TYPE", pg_catalog.format_type(p.prorettype, NULL) AS "DTD_IDENTIFIER" -FROM pg_catalog.pg_namespace n -JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid -WHERE n.nspname = current_schema() -ORDER BY p.proname'); + 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'); } function routine_languages() { - return get_vals("SELECT langname FROM pg_catalog.pg_language"); + return get_vals("SELECT LOWER(lanname) FROM pg_catalog.pg_language"); + } + + function routine_id($name, $row) { + $return = array(); + foreach ($row["fields"] as $field) { + $return[] = $field["type"]; + } + return idf_escape($name) . "(" . implode(", ", $return) . ")"; } function last_id() { @@ -727,7 +733,7 @@ AND typelem = 0" } function support($feature) { - return preg_match('~^(database|table|columns|sql|indexes|comment|view|' . (min_version(9.3) ? 'materializedview|' : '') . 'scheme|processlist|sequence|trigger|type|variables|drop_col|kill|dump)$~', $feature); //! routine| + return preg_match('~^(database|table|columns|sql|indexes|comment|view|' . (min_version(9.3) ? 'materializedview|' : '') . 'scheme|routine|processlist|sequence|trigger|type|variables|drop_col|kill|dump)$~', $feature); } function kill_process($val) { diff --git a/adminer/include/editing.inc.php b/adminer/include/editing.inc.php index 23a174d0..983e6c0d 100644 --- a/adminer/include/editing.inc.php +++ b/adminer/include/editing.inc.php @@ -413,7 +413,7 @@ function create_trigger($on, $row) { * @return string */ function create_routine($routine, $row) { - global $inout; + global $inout, $jush; $set = array(); $fields = (array) $row["fields"]; ksort($fields); // enforce fields order @@ -422,13 +422,13 @@ function create_routine($routine, $row) { $set[] = (preg_match("~^($inout)\$~", $field["inout"]) ? "$field[inout] " : "") . idf_escape($field["field"]) . process_type($field, "CHARACTER SET"); } } + $definition = rtrim("\n$row[definition]", ";"); return "CREATE $routine " . idf_escape(trim($row["name"])) . " (" . implode(", ", $set) . ")" . (isset($_GET["function"]) ? " RETURNS" . process_type($row["returns"], "CHARACTER SET") : "") . ($row["language"] ? " LANGUAGE $row[language]" : "") - . rtrim("\n$row[definition]", ";") - . ";" + . ($jush == "pgsql" ? " AS " . q($definition) : "$definition;") ; } diff --git a/adminer/procedure.inc.php b/adminer/procedure.inc.php index fede3e33..942dd189 100644 --- a/adminer/procedure.inc.php +++ b/adminer/procedure.inc.php @@ -1,17 +1,18 @@ $temp_name) + $row), - "DROP $routine " . idf_escape($temp_name), + "DROP $routine " . routine_id($temp_name, $row), substr(ME, 0, -1), lang('Routine has been dropped.'), lang('Routine has been altered.'), @@ -24,7 +25,7 @@ if ($_POST && !process_fields($row["fields"]) && !$error) { page_header(($PROCEDURE != "" ? (isset($_GET["function"]) ? lang('Alter function') : lang('Alter procedure')) . ": " . h($PROCEDURE) : (isset($_GET["function"]) ? lang('Create function') : lang('Create procedure'))), $error); if (!$_POST && $PROCEDURE != "") { - $row = routine($PROCEDURE, $routine); + $row = routine($_GET["procedure"], $routine); $row["name"] = $PROCEDURE; } @@ -35,7 +36,7 @@ $routine_languages = routine_languages();

: " maxlength="64" autocapitalize="off"> - +