From 72beecc0ab082d32b117b346b76d562c9f4b478c Mon Sep 17 00:00:00 2001 From: Jakub Vrana Date: Wed, 3 Mar 2021 11:07:44 +0100 Subject: [PATCH] PostgreSQL: Support UPDATE OF triggers (bug #789) and triggers with more events (OR) --- adminer/drivers/pgsql.inc.php | 29 +++++++++++++++++++++-------- adminer/include/editing.inc.php | 2 +- adminer/static/editing.js | 2 +- adminer/trigger.inc.php | 2 +- changes.txt | 2 ++ 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/adminer/drivers/pgsql.inc.php b/adminer/drivers/pgsql.inc.php index af6f2bfd..296b8aa3 100644 --- a/adminer/drivers/pgsql.inc.php +++ b/adminer/drivers/pgsql.inc.php @@ -608,21 +608,34 @@ ORDER BY connamespace, conname") as $row) { return true; } - function trigger($name, $table = null) { + function trigger($name, $table) { if ($name == "") { return array("Statement" => "EXECUTE PROCEDURE ()"); } - if ($table === null) { - $table = $_GET['trigger']; + $columns = array(); + $where = "WHERE trigger_schema = current_schema() AND event_object_table = " . q($table) . " AND trigger_name = " . q($name); + foreach (get_rows("SELECT * FROM information_schema.triggered_update_columns $where") as $row) { + $columns[] = $row["event_object_column"]; } - $rows = get_rows('SELECT t.trigger_name AS "Trigger", t.action_timing AS "Timing", (SELECT STRING_AGG(event_manipulation, \' OR \') FROM information_schema.triggers WHERE event_object_table = t.event_object_table AND trigger_name = t.trigger_name ) AS "Events", t.event_manipulation AS "Event", \'FOR EACH \' || t.action_orientation AS "Type", t.action_statement AS "Statement" FROM information_schema.triggers t WHERE t.event_object_table = ' . q($table) . ' AND t.trigger_name = ' . q($name)); - return reset($rows); + $return = array(); + foreach (get_rows('SELECT trigger_name AS "Trigger", action_timing AS "Timing", event_manipulation AS "Event", \'FOR EACH \' || action_orientation AS "Type", action_statement AS "Statement" FROM information_schema.triggers ' . "$where ORDER BY event_manipulation DESC") as $row) { + if ($columns && $row["Event"] == "UPDATE") { + $row["Event"] .= " OF"; + } + $row["Of"] = implode(", ", $columns); + if ($return) { + $row["Event"] .= " OR $return[Event]"; + } + $return = $row; + } + return $return; } function triggers($table) { $return = array(); foreach (get_rows("SELECT * FROM information_schema.triggers WHERE trigger_schema = current_schema() AND event_object_table = " . q($table)) as $row) { - $return[$row["trigger_name"]] = array($row["action_timing"], $row["event_manipulation"]); + $trigger = trigger($row["trigger_name"], $table); + $return[$trigger["Trigger"]] = array($trigger["Timing"], $trigger["Event"]); } return $return; } @@ -630,7 +643,7 @@ ORDER BY connamespace, conname") as $row) { function trigger_options() { return array( "Timing" => array("BEFORE", "AFTER"), - "Event" => array("INSERT", "UPDATE", "DELETE"), + "Event" => array("INSERT", "UPDATE", "UPDATE OF", "DELETE", "INSERT OR UPDATE", "INSERT OR UPDATE OF", "DELETE OR INSERT", "DELETE OR UPDATE", "DELETE OR UPDATE OF", "DELETE OR INSERT OR UPDATE", "DELETE OR INSERT OR UPDATE OF"), "Type" => array("FOR EACH ROW", "FOR EACH STATEMENT"), ); } @@ -831,7 +844,7 @@ AND typelem = 0" $return = ""; foreach (triggers($table) as $trg_id => $trg) { $trigger = trigger($trg_id, $status['Name']); - $return .= "\nCREATE TRIGGER " . idf_escape($trigger['Trigger']) . " $trigger[Timing] $trigger[Events] ON " . idf_escape($status["nspname"]) . "." . idf_escape($status['Name']) . " $trigger[Type] $trigger[Statement];;\n"; + $return .= "\nCREATE TRIGGER " . idf_escape($trigger['Trigger']) . " $trigger[Timing] $trigger[Event] ON " . idf_escape($status["nspname"]) . "." . idf_escape($status['Name']) . " $trigger[Type] $trigger[Statement];;\n"; } return $return; } diff --git a/adminer/include/editing.inc.php b/adminer/include/editing.inc.php index 3cc2734e..88d66d44 100644 --- a/adminer/include/editing.inc.php +++ b/adminer/include/editing.inc.php @@ -430,7 +430,7 @@ function drop_create($drop, $create, $drop_created, $test, $drop_test, $location */ function create_trigger($on, $row) { global $jush; - $timing_event = " $row[Timing] $row[Event]" . ($row["Event"] == "UPDATE OF" ? " " . idf_escape($row["Of"]) : ""); + $timing_event = " $row[Timing] $row[Event]" . (preg_match('~ OF~', $row["Event"]) ? " $row[Of]" : ""); // SQL injection return "CREATE TRIGGER " . idf_escape($row["Trigger"]) . ($jush == "mssql" ? $on . $timing_event : $timing_event . $on) diff --git a/adminer/static/editing.js b/adminer/static/editing.js index 73643c6e..04210c72 100644 --- a/adminer/static/editing.js +++ b/adminer/static/editing.js @@ -658,7 +658,7 @@ function triggerChange(tableRe, table, form) { if (tableRe.test(form['Trigger'].value)) { form['Trigger'].value = table + '_' + (selectValue(form['Timing']).charAt(0) + formEvent.charAt(0)).toLowerCase(); } - alterClass(form['Of'], 'hidden', formEvent != 'UPDATE OF'); + alterClass(form['Of'], 'hidden', !/ OF/.test(formEvent)); } diff --git a/adminer/trigger.inc.php b/adminer/trigger.inc.php index 4864862c..4c780cb0 100644 --- a/adminer/trigger.inc.php +++ b/adminer/trigger.inc.php @@ -2,7 +2,7 @@ $TABLE = $_GET["trigger"]; $name = $_GET["name"]; $trigger_options = trigger_options(); -$row = (array) trigger($name) + array("Trigger" => $TABLE . "_bi"); +$row = (array) trigger($name, $TABLE) + array("Trigger" => $TABLE . "_bi"); if ($_POST) { if (!$error && in_array($_POST["Timing"], $trigger_options["Timing"]) && in_array($_POST["Event"], $trigger_options["Event"]) && in_array($_POST["Type"], $trigger_options["Type"])) { diff --git a/changes.txt b/changes.txt index ec4bbb6c..0500f5cc 100644 --- a/changes.txt +++ b/changes.txt @@ -2,6 +2,8 @@ Adminer 4.8.1-dev: Fix more PHP 8 warnings (bug #781) Avoid PHP warnings with PDO drivers (bug #786, regression from 4.7.8) MySQL: Allow moving views to other DB and renaming DB with views (bug #783) +PostgreSQL: Support UPDATE OF triggers (bug #789) +PostgreSQL: Support triggers with more events (OR) PostgreSQL < 10 PDO: Avoid displaying GENERATED ALWAYS BY IDENTITY everywhere (bug #785, regression from 4.7.9) SQLite: Fix displayed types (bug #784, regression from 4.8.0)