[Phpmyadmin-git] [SCM] phpMyAdmin branch, master, updated. RELEASE_3_4_3_1-8195-g0ebd961

Rouslan Placella roccivic at users.sourceforge.net
Wed Jul 13 12:18:10 CEST 2011


The branch, master has been updated
       via  0ebd961db7a39ccb02bc1a5772e95df803b9c38c (commit)
       via  8aad65b4948d5f526bbe33c5b0023b4da9ae3a4b (commit)
       via  ff7468b2cf69133b81c7534e492f7d6679ea514b (commit)
       via  fed169554a18e71d95010c2716d0ea379f1c8301 (commit)
       via  6f0f522fcdfde819d25764e582f24a5e5f4d883a (commit)
       via  265a5cebc005003b4fd8f0ce00cd24234da14106 (commit)
       via  9898cf860915712504dd23c24ecaf8ce58c546e3 (commit)
       via  c8ec2dd8cb65b5f7cb44fdbb2e73b37df5b02619 (commit)
       via  4df98e9e6227b521a358895e8b282f2af70ae96c (commit)
       via  262a27232edb9aa6b45cd1a695f5f0741311b2b1 (commit)
       via  eb33912d8d4a8a937271f9ee8783f26b74df78e2 (commit)
       via  a4dd7561b05ab1dd939f2f0b4142b0e02c6f181f (commit)
       via  125467978e7f8fc55e1c0fd6ac39d932ea28c5b8 (commit)
       via  283bb10c3597c6cf5ada14503b77c03cd4d24bc3 (commit)
       via  612d6a1ff1b213e6c6fc3d9918e55fde85f6be82 (commit)
       via  cae5bba400133478f9cc2f482dc1c5c16c4d7cb6 (commit)
       via  ec83a934d138b79ceea4aad0704f304f6e062356 (commit)
       via  5a35754d0b4c9b8f13f49f91a5dd1b03775b31ee (commit)
       via  dad5d3594a2190a6bed7818ad7cda7ed450ce046 (commit)
       via  b3b7d45e782db5add6a2c508bc62e282b2052281 (commit)
       via  b03249f64ac36b0c65112115d459e5ebe607727c (commit)
       via  6490a75c4e8e7f671612394b4fb039057b4a5bf0 (commit)
       via  ccd1cc3f9e508c9bb056787f99ec9a00f0afb38e (commit)
       via  d1f0b34ab50dfc9c91d7b1eb3990382b6f252e5b (commit)
       via  492884984beecb6f44110aa8191ecd1a43d6dae4 (commit)
       via  5d48637abc34fa0c54d4a88e0e979616aa359f3c (commit)
       via  d47e01e7ef103d3869af0f163a9a65c364cdcd62 (commit)
       via  7857a05de33377652ac41ce5fcc66e8cbebff57d (commit)
       via  9c11b373fbdf4d5f4ae0fb9d1a966b75f8839ce8 (commit)
       via  8e8a5e54f00908c689a2ed917e75085345ffc88d (commit)
       via  a2751ee65b5aa0caf653c03a0e6c08cd68561098 (commit)
       via  bc2cd16c4c3cf3255412035919d504b2050cd7cf (commit)
       via  357d84e52fed9279777432a3d98d25d9c5f7a55f (commit)
       via  e947712358b812ce00b26b79939b9b36de37374e (commit)
       via  3b19b5393405fd13474789b93be3603c1e9b388a (commit)
       via  5769a2143c76020e698c1e3545a601cdd1c9e488 (commit)
       via  15ad6605b1c87339282bb3310387c2aa0bca961a (commit)
       via  55d2358359fe65a09d737921bdf055128901a730 (commit)
       via  1bbb2ea37e44969c26f4cc0bc98f4636ec4dcd09 (commit)
       via  79e7544c3d586a6c2364139c3cb3ea150195933b (commit)
       via  8c13805344c3bd2afe18168ce6b416636c5da4e4 (commit)
       via  58d97f87eec2291f6762894a858cf60ceeb77c8a (commit)
       via  d7c0da5f859a136d2529905d74c84903b7b1b963 (commit)
       via  31e03fc6401ef5244f8dad02aa1cfc3bdecd82c7 (commit)
       via  7ee2c0977021507341914b6e18d486b3f8840678 (commit)
       via  c150eb0c7c22a65573ddaa648bc0ab3ef2d23530 (commit)
       via  cf61fb1270d0efc4759723dd3467e117fa657eb2 (commit)
       via  b4b56ed461d639efc352f621af0dcf34035ad293 (commit)
       via  cbafdb9a1fcbb7e54eed56b8b5c727e4b075a234 (commit)
       via  ef3a45b5961659d843c978a9875c6a71bd9bb7c3 (commit)
       via  dc6be930befd001b2e12b9c18c923aec78b9a3a3 (commit)
       via  3b1edd95e624c17c0bd6fe939c41f968c667e938 (commit)
       via  75fd7df711d360559e58425fa811cd42610bbe62 (commit)
       via  4da8d2e98f50cb420838140a14bfed66deb168f6 (commit)
       via  8c15a1d25c4d9c5ff46e063ae17172daa3da1ecd (commit)
       via  81adfeab7a222ad9e714c493e01d50db4fb13ebd (commit)
       via  14e88e6f682a91a382443253db12a54d0b2f5cec (commit)
       via  eef43b22b2185887c3ad63474e45046db94ca708 (commit)
       via  5bafd840b711e07dbebe620523992adaaf15bfd4 (commit)
       via  67c5b63a4addc5b7fab425febaca341243595f97 (commit)
       via  4f4efd231d92168699f2bcbca574ce2385c41327 (commit)
       via  4cbef2bdf65636a471798a825e8ddbc5493fbc8a (commit)
       via  238f52a7e9051f1d986537da9b32ced3c9ee0dd5 (commit)
       via  0a90116985fdc4336731dacdc053ce4cbe0a2537 (commit)
      from  32c7781fb46b4774cbd568403dcd4f22da60ecc1 (commit)


- Log -----------------------------------------------------------------
commit 0ebd961db7a39ccb02bc1a5772e95df803b9c38c
Merge: 32c7781fb46b4774cbd568403dcd4f22da60ecc1 8aad65b4948d5f526bbe33c5b0023b4da9ae3a4b
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jul 13 11:15:25 2011 +0100

    Merge branch 'rte'

commit 8aad65b4948d5f526bbe33c5b0023b4da9ae3a4b
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 17:14:32 2011 +0100

    Moved some Routine functions around to match the order of Event and Trigger functions.

commit ff7468b2cf69133b81c7534e492f7d6679ea514b
Merge: fed169554a18e71d95010c2716d0ea379f1c8301 7802be3c48de27f14f4bc8e6acf331c3aff1951e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 14:54:42 2011 +0100

    Merge branch 'master' into rte

commit fed169554a18e71d95010c2716d0ea379f1c8301
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 14:52:36 2011 +0100

    Swapped some inline styles for classes.

commit 6f0f522fcdfde819d25764e582f24a5e5f4d883a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 14:33:26 2011 +0100

    Do not send 'name' and 'row' data in the AJAX request, if it will not be used because the trigger will not be inserted into the list.

commit 265a5cebc005003b4fd8f0ce00cd24234da14106
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 14:25:38 2011 +0100

    Fixed bug introduced in previous commit: new rows always inserted at the bottom of the list.

commit 9898cf860915712504dd23c24ecaf8ce58c546e3
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 14:00:42 2011 +0100

    Coding guidelines for routines.

commit c8ec2dd8cb65b5f7cb44fdbb2e73b37df5b02619
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 12:58:23 2011 +0100

    Coding guidelines for triggers.

commit 4df98e9e6227b521a358895e8b282f2af70ae96c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 12 12:02:12 2011 +0100

    Coding guidelines for code common to Routines, Triggers and Events.

commit 262a27232edb9aa6b45cd1a695f5f0741311b2b1
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jul 11 14:36:40 2011 +0100

    Coding guidelines for events.

commit eb33912d8d4a8a937271f9ee8783f26b74df78e2
Merge: a4dd7561b05ab1dd939f2f0b4142b0e02c6f181f dacfab623734ca5927693dc9cdabd84c4961420a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jul 11 12:30:47 2011 +0100

    Merge branch 'master' into rte

commit a4dd7561b05ab1dd939f2f0b4142b0e02c6f181f
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jul 11 12:28:09 2011 +0100

    SERIAL and BOOLEAN types have no length.

commit 125467978e7f8fc55e1c0fd6ac39d932ea28c5b8
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 8 16:40:59 2011 +0100

    Removed some pointless parameters from functions that handle the editing and execution of routines

commit 283bb10c3597c6cf5ada14503b77c03cd4d24bc3
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 8 16:36:20 2011 +0100

    More comments for functions that handle Routines, Triggers and Events

commit 612d6a1ff1b213e6c6fc3d9918e55fde85f6be82
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 8 16:05:46 2011 +0100

    Standardized all "name" attributes for input fields of the Routines, Triggers and Events editors

commit cae5bba400133478f9cc2f482dc1c5c16c4d7cb6
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 8 12:58:33 2011 +0100

    Better filtering on generation of 'CREATE [ROUTINE|TRIGGER|EVENT]' queries.

commit ec83a934d138b79ceea4aad0704f304f6e062356
Merge: 5a35754d0b4c9b8f13f49f91a5dd1b03775b31ee c8ba421d379c15cd6bac620a77be50513e7da710
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 8 11:36:48 2011 +0100

    Merge branch 'master' into rte

commit 5a35754d0b4c9b8f13f49f91a5dd1b03775b31ee
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jul 7 15:27:48 2011 +0100

    Reverted to fetching lists by row instead of by cell, also implemented better control over some localized strings

commit dad5d3594a2190a6bed7818ad7cda7ed450ce046
Merge: b3b7d45e782db5add6a2c508bc62e282b2052281 e15d5de30991885663c3538b46e4de02d41dd74b
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jul 7 12:31:53 2011 +0100

    Merge branch 'master' into rte

commit b3b7d45e782db5add6a2c508bc62e282b2052281
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jul 6 18:08:22 2011 +0100

    Dropping useless rte_common.lib.php

commit b03249f64ac36b0c65112115d459e5ebe607727c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jul 6 18:01:51 2011 +0100

    Do not export the delimiter for triggers

commit 6490a75c4e8e7f671612394b4fb039057b4a5bf0
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jul 6 17:54:31 2011 +0100

    Fixed bug, where after deleting a table the Routines, Triggers and Events tabs stopped working.

commit ccd1cc3f9e508c9bb056787f99ec9a00f0afb38e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jul 6 14:29:46 2011 +0100

    Simplified code for 'export' functionality of Routines, Triggers and Events

commit d1f0b34ab50dfc9c91d7b1eb3990382b6f252e5b
Merge: 492884984beecb6f44110aa8191ecd1a43d6dae4 e9126d231887cfdeeed096648201f9e0d2f0b6f5
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jul 6 14:18:36 2011 +0100

    Merge branch 'master' into rte

commit 492884984beecb6f44110aa8191ecd1a43d6dae4
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jul 6 14:06:30 2011 +0100

    Comments and whitespace for JS files for Routines, Triggers and Events

commit 5d48637abc34fa0c54d4a88e0e979616aa359f3c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 16:25:08 2011 +0100

    Added validation for the Events editor

commit d47e01e7ef103d3869af0f163a9a65c364cdcd62
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 16:06:37 2011 +0100

    Tabs -> Spaces

commit 7857a05de33377652ac41ce5fcc66e8cbebff57d
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 16:04:08 2011 +0100

    Removed pointless constant 'ITEM'

commit 9c11b373fbdf4d5f4ae0fb9d1a966b75f8839ce8
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 15:45:43 2011 +0100

    Added '---' to otherwise empty table cells in the routines editor.

commit 8e8a5e54f00908c689a2ed917e75085345ffc88d
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 14:33:44 2011 +0100

    Bolded the labels in the editor for Routines, Triggers and Events

commit a2751ee65b5aa0caf653c03a0e6c08cd68561098
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 14:18:31 2011 +0100

    LINTed the JavaScript for Routines, Triggers and Events.

commit bc2cd16c4c3cf3255412035919d504b2050cd7cf
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 13:19:58 2011 +0100

    Moved code common to Routines, Triggers and Events from "functions.js" to "rte/common.js"

commit 357d84e52fed9279777432a3d98d25d9c5f7a55f
Merge: e947712358b812ce00b26b79939b9b36de37374e 70c70db1392e703346434e65d59110a6ba321367
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 13:13:31 2011 +0100

    Merge branch 'master' into rte
    
    Conflicts:
    	js/db_routines.js

commit e947712358b812ce00b26b79939b9b36de37374e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 12:53:49 2011 +0100

    Do not insert not preserved events from the past into the list of events. Also use same logic for other items.

commit 3b19b5393405fd13474789b93be3603c1e9b388a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 12:30:06 2011 +0100

    Move JS code for Routines, Triggers and Events into a separate folder

commit 5769a2143c76020e698c1e3545a601cdd1c9e488
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 12:28:25 2011 +0100

    Moved more item-specific code out of rte_common.js

commit 15ad6605b1c87339282bb3310387c2aa0bca961a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 11:38:46 2011 +0100

    Set 'maxlength' of input fields in HTML, instead of validating against a maximum length in JS.

commit 55d2358359fe65a09d737921bdf055128901a730
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jul 5 11:27:24 2011 +0100

    Factored out the JS for the editor of Routines, Triggers and Events and moved it into a namespace.

commit 1bbb2ea37e44969c26f4cc0bc98f4636ec4dcd09
Merge: 79e7544c3d586a6c2364139c3cb3ea150195933b 064d399d878f36a0a26f6db890b947bccb3ef8ab
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jul 4 15:36:27 2011 +0100

    Merge branch 'master' into rte

commit 79e7544c3d586a6c2364139c3cb3ea150195933b
Merge: 8c13805344c3bd2afe18168ce6b416636c5da4e4 2279fd9c98ee43acba942d08c0dd3ca987748a1c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 1 16:51:42 2011 +0100

    Merge branch 'master' into rte
    
    Conflicts:
    	db_routines.php
    	libraries/database_interface.lib.php
    	libraries/db_events.inc.php
    	libraries/rte/rte_routines.lib.php

commit 8c13805344c3bd2afe18168ce6b416636c5da4e4
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 1 16:46:17 2011 +0100

    Prototype imlementation of the events editor

commit 58d97f87eec2291f6762894a858cf60ceeb77c8a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jul 1 16:45:03 2011 +0100

    Fix broken trigger links after edit operation

commit d7c0da5f859a136d2529905d74c84903b7b1b963
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 30 18:27:40 2011 +0100

    Missing semicolon breaks formatting of the pretty printer

commit 31e03fc6401ef5244f8dad02aa1cfc3bdecd82c7
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 30 18:22:23 2011 +0100

    Order the list of events by name

commit 7ee2c0977021507341914b6e18d486b3f8840678
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 30 16:37:18 2011 +0100

    Properly attach datepickers to AJAX dialogs.

commit c150eb0c7c22a65573ddaa648bc0ab3ef2d23530
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 30 13:19:31 2011 +0100

    Integrate PMA_toggleButton() with $cfg['AjaxEnable']

commit cf61fb1270d0efc4759723dd3467e117fa657eb2
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 30 13:12:26 2011 +0100

    Prototype integration of Triggers editor.

commit b4b56ed461d639efc352f621af0dcf34035ad293
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 28 17:24:07 2011 +0100

    Merge branch 'master' into rte
    
    Conflicts:
    	db_routines.php
    	libraries/db_events.inc.php
    	libraries/rte/rte_routines.lib.php

commit cbafdb9a1fcbb7e54eed56b8b5c727e4b075a234
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 28 15:34:57 2011 +0100

    Refactored some routine, trigger and event manipulation code

commit ef3a45b5961659d843c978a9875c6a71bd9bb7c3
Merge: dc6be930befd001b2e12b9c18c923aec78b9a3a3 a01662dd4ac363c6bb1663ac6b81d7e797114503
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 27 11:27:21 2011 +0100

    Merge branch 'master' into rte
    
    Conflicts:
    	libraries/db_events.inc.php
    	libraries/display_triggers.inc.php

commit dc6be930befd001b2e12b9c18c923aec78b9a3a3
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:54:54 2011 +0100

    Revert "CSS fix for the toggle button"
    
    This reverts commit 81adfeab7a222ad9e714c493e01d50db4fb13ebd.

commit 3b1edd95e624c17c0bd6fe939c41f968c667e938
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:52:33 2011 +0100

    Renamed db_events.inc.php to db_events.lib.php

commit 75fd7df711d360559e58425fa811cd42610bbe62
Merge: 4da8d2e98f50cb420838140a14bfed66deb168f6 67224c407e95f5f1ba937d670f8e148da66afd39
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:49:55 2011 +0100

    Merge branch 'master' into rte

commit 4da8d2e98f50cb420838140a14bfed66deb168f6
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:45:18 2011 +0100

    Added legend to bottom fieldset in the routines page

commit 8c15a1d25c4d9c5ff46e063ae17172daa3da1ecd
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:44:24 2011 +0100

    Imporved event functionality code and moved it into functions

commit 81adfeab7a222ad9e714c493e01d50db4fb13ebd
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:40:47 2011 +0100

    CSS fix for the toggle button

commit 14e88e6f682a91a382443253db12a54d0b2f5cec
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:40:08 2011 +0100

    Small footer fixes

commit eef43b22b2185887c3ad63474e45046db94ca708
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 24 13:39:19 2011 +0100

    More MySQL documentation links for routines and triggers

commit 5bafd840b711e07dbebe620523992adaaf15bfd4
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 23 14:58:48 2011 +0100

    Hide Events and Triggers navigation links from unprivileged users

commit 67c5b63a4addc5b7fab425febaca341243595f97
Merge: 4f4efd231d92168699f2bcbca574ce2385c41327 fd493c6b4cff296646a9c9ea0d0eda6fbcf9a881
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 23 14:10:19 2011 +0100

    Merge branch 'master' into rte

commit 4f4efd231d92168699f2bcbca574ce2385c41327
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 22 18:16:18 2011 +0100

    Better "event scheduler" functionality

commit 4cbef2bdf65636a471798a825e8ddbc5493fbc8a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 22 14:31:09 2011 +0100

    Uncommented hidden navigation links

commit 238f52a7e9051f1d986537da9b32ced3c9ee0dd5
Merge: 0a90116985fdc4336731dacdc053ce4cbe0a2537 4b75560c3b08ccdaff7cf427e747d83a6ff3ca54
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 22 13:01:46 2011 +0100

    Merge branch 'master' into rte

commit 0a90116985fdc4336731dacdc053ce4cbe0a2537
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 21 21:51:49 2011 +0100

    PMA_slidingMessage() must accept invalid input objects.

-----------------------------------------------------------------------

Summary of changes:
 db_events.php                           |   33 +-
 db_routines.php                         |  428 +---------
 db_triggers.php                         |   34 +-
 js/db_events.js                         |    2 -
 js/db_routines.js                       |  568 ------------
 js/display_triggers.js                  |    2 -
 js/functions.js                         |  231 +++---
 js/messages.php                         |    1 -
 js/rte/common.js                        |  380 ++++++++
 js/rte/events.js                        |   43 +
 js/rte/routines.js                      |  395 ++++++++
 js/rte/triggers.js                      |    8 +
 libraries/common.inc.php                |    1 +
 libraries/common.lib.php                |   81 ++
 libraries/database_interface.lib.php    |   13 +-
 libraries/db_events.inc.php             |  150 ---
 libraries/db_links.inc.php              |   10 +-
 libraries/db_routines.lib.php           | 1204 -------------------------
 libraries/display_triggers.inc.php      |  123 ---
 libraries/rte/rte_events.lib.php        |  567 ++++++++++++
 libraries/rte/rte_export.lib.php        |  107 +++
 libraries/rte/rte_footer.lib.php        |  127 +++
 libraries/rte/rte_list.lib.php          |  338 +++++++
 libraries/rte/rte_main.inc.php          |  135 +++
 libraries/rte/rte_routines.lib.php      | 1494 +++++++++++++++++++++++++++++++
 libraries/rte/rte_triggers.lib.php      |  435 +++++++++
 libraries/tbl_links.inc.php             |    9 +-
 tbl_triggers.php                        |   36 +-
 themes/original/css/theme_right.css.php |   59 ++
 themes/original/img/toggle-ltr.png      |  Bin 0 -> 232 bytes
 themes/original/img/toggle-rtl.png      |  Bin 0 -> 230 bytes
 themes/pmahomme/css/theme_right.css.php |   62 ++
 themes/pmahomme/img/toggle-ltr.png      |  Bin 0 -> 425 bytes
 themes/pmahomme/img/toggle-rtl.png      |  Bin 0 -> 427 bytes
 34 files changed, 4419 insertions(+), 2657 deletions(-)
 delete mode 100644 js/db_events.js
 delete mode 100644 js/db_routines.js
 delete mode 100644 js/display_triggers.js
 create mode 100644 js/rte/common.js
 create mode 100644 js/rte/events.js
 create mode 100644 js/rte/routines.js
 create mode 100644 js/rte/triggers.js
 delete mode 100644 libraries/db_events.inc.php
 delete mode 100644 libraries/db_routines.lib.php
 delete mode 100644 libraries/display_triggers.inc.php
 create mode 100644 libraries/rte/rte_events.lib.php
 create mode 100644 libraries/rte/rte_export.lib.php
 create mode 100644 libraries/rte/rte_footer.lib.php
 create mode 100644 libraries/rte/rte_list.lib.php
 create mode 100644 libraries/rte/rte_main.inc.php
 create mode 100644 libraries/rte/rte_routines.lib.php
 create mode 100644 libraries/rte/rte_triggers.lib.php
 create mode 100644 themes/original/img/toggle-ltr.png
 create mode 100644 themes/original/img/toggle-rtl.png
 create mode 100644 themes/pmahomme/img/toggle-ltr.png
 create mode 100644 themes/pmahomme/img/toggle-rtl.png

diff --git a/db_events.php b/db_events.php
index 7d22f5d..f659607 100644
--- a/db_events.php
+++ b/db_events.php
@@ -1,40 +1,33 @@
 <?php
-
+/* vim: set expandtab sw=4 ts=4 sts=4: */
 /**
  * Events management.
  *
  * @package phpMyAdmin
  */
-require_once './libraries/common.inc.php';
-require_once './libraries/common.lib.php';
-
-$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
-$GLOBALS['js_include'][] = 'db_events.js';
-
-/**
- * Create labels for the list
- */
-$titles = PMA_buildActionTitles();
 
 /**
- * Displays the header
+ * Include required files
  */
-require_once './libraries/db_common.inc.php';
+require_once './libraries/common.inc.php';
+require_once './libraries/common.lib.php';
 
 /**
- * Displays the tabs
+ * Include JavaScript libraries
  */
-require_once './libraries/db_info.inc.php';
+$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
+$GLOBALS['js_include'][] = 'jquery/timepicker.js';
+$GLOBALS['js_include'][] = 'rte/common.js';
+$GLOBALS['js_include'][] = 'rte/events.js';
 
 /**
- * Displays the list of events
+ * Include all other files
  */
-require_once './libraries/db_events.inc.php';
+require_once './libraries/rte/rte_events.lib.php';
 
 /**
- * Displays the footer
+ * Do the magic
  */
-require './libraries/footer.inc.php';
-
+require_once './libraries/rte/rte_main.inc.php';
 
 ?>
diff --git a/db_routines.php b/db_routines.php
index 422ec76..efac9ea 100644
--- a/db_routines.php
+++ b/db_routines.php
@@ -11,7 +11,6 @@
  */
 require_once './libraries/common.inc.php';
 require_once './libraries/common.lib.php';
-require_once './libraries/db_routines.lib.php';
 require_once './libraries/mysql_charsets.lib.php';
 require_once './libraries/data_mysql.inc.php';
 
@@ -20,432 +19,17 @@ require_once './libraries/data_mysql.inc.php';
  */
 $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
 $GLOBALS['js_include'][] = 'jquery/timepicker.js';
-$GLOBALS['js_include'][] = 'db_routines.js';
+$GLOBALS['js_include'][] = 'rte/common.js';
+$GLOBALS['js_include'][] = 'rte/routines.js';
 
 /**
- * Create labels for the list
+ * Include all other files
  */
-$titles = PMA_buildActionTitles();
-
-if ($GLOBALS['is_ajax_request'] != true) {
-    /**
-     * Displays the header
-     */
-    require_once './libraries/db_common.inc.php';
-    /**
-     * Displays the tabs
-     */
-    require_once './libraries/db_info.inc.php';
-} else {
-    if (strlen($db)) {
-        PMA_DBI_select_db($db);
-        if (! isset($url_query)) {
-            $url_query = PMA_generate_common_url($db);
-        }
-    }
-}
-
-/**
- * Process all requests
- */
-
-// Some definitions
-$param_directions    = array('IN',
-                             'OUT',
-                             'INOUT');
-$param_opts_num      = array('UNSIGNED',
-                             'ZEROFILL',
-                             'UNSIGNED ZEROFILL');
-$param_sqldataaccess = array('NO SQL',
-                             'CONTAINS SQL',
-                             'READS SQL DATA',
-                             'MODIFIES SQL DATA');
-
-/**
- * Generate the conditional classes that will be used to attach jQuery events to links.
- */
-$ajax_class = array(
-                  'add'    => '',
-                  'edit'   => '',
-                  'exec'   => '',
-                  'drop'   => '',
-                  'export' => ''
-              );
-if ($GLOBALS['cfg']['AjaxEnable']) {
-    $ajax_class['add']    = 'class="add_routine_anchor"';
-    $ajax_class['edit']   = 'class="edit_routine_anchor"';
-    $ajax_class['exec']   = 'class="exec_routine_anchor"';
-    $ajax_class['drop']   = 'class="drop_routine_anchor"';
-    $ajax_class['export'] = 'class="export_routine_anchor"';
-}
-
-/**
- * Keep a list of errors that occured while processing an 'Add' or 'Edit' operation.
- */
-$routine_errors = array();
-
-/**
- * Handle all user requests other than the default of listing routines
- */
-if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['routine_name'])) {
-    // Build the queries
-    $routine   = PMA_RTN_getRoutineDataFromName($db, $_REQUEST['routine_name'], false);
-    if ($routine !== false) {
-        $queries   = array();
-        $end_query = array();
-        $args      = array();
-        for ($i=0; $i<$routine['num_params']; $i++) {
-            if (isset($_REQUEST['params'][$routine['param_name'][$i]])) {
-                $value = $_REQUEST['params'][$routine['param_name'][$i]];
-                if (is_array($value)) { // is SET type
-                    $value = implode(',', $value);
-                }
-                $value = PMA_sqlAddSlashes($value);
-                if (! empty($_REQUEST['funcs'][$routine['param_name'][$i]])
-                      && in_array($_REQUEST['funcs'][$routine['param_name'][$i]], $cfg['Functions'])) {
-                    $queries[] = "SET @p$i={$_REQUEST['funcs'][$routine['param_name'][$i]]}('$value');\n";
-                } else {
-                    $queries[] = "SET @p$i='$value';\n";
-                }
-                $args[] = "@p$i";
-            } else {
-                $args[] = "@p$i";
-            }
-            if ($routine['type'] == 'PROCEDURE') {
-                if ($routine['param_dir'][$i] == 'OUT' || $routine['param_dir'][$i] == 'INOUT') {
-                    $end_query[] = "@p$i AS " . PMA_backquote($routine['param_name'][$i]);
-                }
-            }
-        }
-        if ($routine['type'] == 'PROCEDURE') {
-            $queries[] = "CALL " . PMA_backquote($routine['name'])
-                       . "(" . implode(', ', $args) . ");\n";
-            if (count($end_query)) {
-                $queries[] = "SELECT " . implode(', ', $end_query) . ";\n";
-            }
-        } else {
-            $queries[] = "SELECT " . PMA_backquote($routine['name'])
-                       . "(" . implode(', ', $args) . ") "
-                       . "AS " . PMA_backquote($routine['name']) . ";\n";
-        }
-        // Execute the queries
-        $affected = 0;
-        $result = null;
-        $outcome = true;
-        foreach ($queries as $num => $query) {
-            $resource = PMA_DBI_try_query($query);
-            if ($resource === false) {
-                $outcome = false;
-                break;
-            }
-            while (true) {
-                if(! PMA_DBI_more_results()) {
-                    break;
-                }
-                PMA_DBI_next_result();
-            }
-            if (substr($query, 0, 6) == 'SELECT') {
-                $result = $resource;
-            } else if (substr($query, 0, 4) == 'CALL') {
-                $affected = PMA_DBI_affected_rows() - PMA_DBI_num_rows($resource);
-            }
-        }
-        // Generate output
-        if ($outcome) {
-            $message = __('Your SQL query has been executed successfully');
-            if ($routine['type'] == 'PROCEDURE') {
-                $message .= '<br />';
-                $message .= sprintf(_ngettext('%d row affected by the last statement inside the procedure', '%d rows affected by the last statement inside the procedure', $affected), $affected);
-            }
-            $message = PMA_message::success($message);
-            // Pass the SQL queries through the "pretty printer"
-            $output  = '<code class="sql" style="margin-bottom: 1em;">';
-            $output .= PMA_SQP_formatHtml(PMA_SQP_parse(implode($queries)));
-            $output .= '</code>';
-            // Display results
-            if ($result) {
-                $output .= "<fieldset><legend>";
-                $output .= sprintf(__('Execution results of routine %s'),
-                                   PMA_backquote(htmlspecialchars($routine['name'])));
-                $output .= "</legend>";
-                $output .= "<table><tr>";
-                foreach (PMA_DBI_get_fields_meta($result) as $key => $field) {
-                    $output .= "<th>" . htmlspecialchars($field->name) . "</th>";
-                }
-                $output .= "</tr>";
-                // Stored routines can only ever return ONE ROW.
-                $data = PMA_DBI_fetch_single_row($result);
-                foreach ($data as $key => $value) {
-                    if ($value === null) {
-                        $value = '<i>NULL</i>';
-                    } else {
-                        $value = htmlspecialchars($value);
-                    }
-                    $output .= "<td class='odd'>" . $value . "</td>";
-                }
-                $output .= "</table></fieldset>";
-            } else {
-                $notice = __('MySQL returned an empty result set (i.e. zero rows).');
-                $output .= PMA_message::notice($notice)->getDisplay();
-            }
-        } else {
-            $output = '';
-            $message = PMA_message::error(sprintf(__('The following query has failed: "%s"'), $query) . '<br /><br />'
-                                                . __('MySQL said: ') . PMA_DBI_getError(null));
-        }
-        // Print/send output
-        if ($GLOBALS['is_ajax_request']) {
-            $extra_data = array('dialog' => false);
-            PMA_ajaxResponse($message->getDisplay() . $output, $message->isSuccess(), $extra_data);
-        } else {
-            echo $message->getDisplay() . $output;
-            if ($message->isError()) {
-                // At least one query has failed, so shouldn't
-                // execute any more queries, so we quit.
-                exit;
-            }
-            unset($_POST);
-            // Now deliberately fall through to displaying the routines list
-        }
-    } else {
-        $message = __('Error in processing request') . ' : '
-                 . sprintf(__('No routine with name %1$s found in database %2$s'),
-                           htmlspecialchars(PMA_backquote($_REQUEST['routine_name'])),
-                           htmlspecialchars(PMA_backquote($db)));
-        $message = PMA_message::error($message);
-        if ($GLOBALS['is_ajax_request']) {
-            PMA_ajaxResponse($message, $message->isSuccess());
-        } else {
-            echo $message->getDisplay();
-            unset($_POST);
-        }
-    }
-} else if (! empty($_GET['execute_dialog']) && ! empty($_GET['routine_name'])) {
-    /**
-     * Display the execute form for a routine.
-     */
-    $routine = PMA_RTN_getRoutineDataFromName($db, $_GET['routine_name'], false);
-    if ($routine !== false) {
-        $form = PMA_RTN_getExecuteForm($routine, $GLOBALS['is_ajax_request']);
-        if ($GLOBALS['is_ajax_request'] == true) {
-            $extra_data = array();
-            $extra_data['dialog'] = true;
-            $extra_data['title']  = __("Execute routine") . " ";
-            $extra_data['title'] .= PMA_backquote(htmlentities($_GET['routine_name'], ENT_QUOTES));
-            PMA_ajaxResponse($form, true, $extra_data);
-        } else {
-            echo "\n\n<h2>" . __("Execute routine") . "</h2>\n\n";
-            echo $form;
-            require './libraries/footer.inc.php';
-            // exit;
-        }
-    } else if (($GLOBALS['is_ajax_request'] == true)) {
-        $message = __('Error in processing request') . ' : '
-                 . sprintf(__('No routine with name %1$s found in database %2$s'),
-                           htmlspecialchars(PMA_backquote($_REQUEST['routine_name'])),
-                           htmlspecialchars(PMA_backquote($db)));
-        $message = PMA_message::error($message);
-        PMA_ajaxResponse($message, false);
-    }
-} else if (! empty($_GET['exportroutine']) && ! empty($_GET['routine_name'])) {
-    /**
-     * Display the export for a routine.
-     */
-    $routine_name = htmlspecialchars(PMA_backquote($_GET['routine_name']));
-    $routine_type = PMA_DBI_fetch_value("SELECT ROUTINE_TYPE "
-                                      . "FROM INFORMATION_SCHEMA.ROUTINES "
-                                      . "WHERE ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' "
-                                      . "AND SPECIFIC_NAME='" . PMA_sqlAddSlashes($_GET['routine_name']) . "';");
-    if (! empty($routine_type) && $create_proc = PMA_DBI_get_definition($db, $routine_type, $_GET['routine_name'])) {
-        $create_proc = '<textarea cols="40" rows="15" style="width: 100%;">' . htmlspecialchars($create_proc) . '</textarea>';
-        if ($GLOBALS['is_ajax_request']) {
-            $extra_data = array('title' => sprintf(__('Export of routine %s'), $routine_name));
-            PMA_ajaxResponse($create_proc, true, $extra_data);
-        } else {
-            echo '<fieldset>' . "\n"
-               . ' <legend>' . sprintf(__('Export of routine %s'), $routine_name) . '</legend>' . "\n"
-               . $create_proc . "\n"
-               . '</fieldset>';
-        }
-    } else {
-        $response = __('Error in processing request') . ' : '
-                  . sprintf(__('No routine with name %1$s found in database %2$s'),
-                            $routine_name, htmlspecialchars(PMA_backquote($db)));
-        $response = PMA_message::error($response);
-        if ($GLOBALS['is_ajax_request']) {
-            PMA_ajaxResponse($response, false);
-        } else {
-            $response->display();
-        }
-    }
-} else if (! empty($_REQUEST['routine_process_addroutine']) || ! empty($_REQUEST['routine_process_editroutine'])) {
-    /**
-     * Handle a request to create/edit a routine
-     */
-    $sql_query = '';
-    $routine_query = PMA_RTN_getQueryFromRequest();
-    if (! count($routine_errors)) { // set by PMA_RTN_getQueryFromRequest()
-        // Execute the created query
-        if (! empty($_REQUEST['routine_process_editroutine'])) {
-            if (! in_array($_REQUEST['routine_original_type'], array('PROCEDURE', 'FUNCTION'))) {
-                $routine_errors[] = sprintf(__('Invalid routine type: "%s"'), htmlspecialchars($_REQUEST['routine_original_type']));
-            } else {
-                // Backup the old routine, in case something goes wrong
-                $create_routine = PMA_DBI_get_definition($db, $_REQUEST['routine_original_type'], $_REQUEST['routine_original_name']);
-                $drop_routine = "DROP {$_REQUEST['routine_original_type']} " . PMA_backquote($_REQUEST['routine_original_name']) . ";\n";
-                $result = PMA_DBI_try_query($drop_routine);
-                if (! $result) {
-                    $routine_errors[] = sprintf(__('The following query has failed: "%s"'), $drop_routine) . '<br />'
-                                      . __('MySQL said: ') . PMA_DBI_getError(null);
-                } else {
-                    $result = PMA_DBI_try_query($routine_query);
-                    if (! $result) {
-                        $routine_errors[] = sprintf(__('The following query has failed: "%s"'), $routine_query) . '<br />'
-                                          . __('MySQL said: ') . PMA_DBI_getError(null);
-                        // We dropped the old routine, but were unable to create the new one
-                        // Try to restore the backup query
-                        $result = PMA_DBI_try_query($create_routine);
-                        if (! $result) {
-                            // OMG, this is really bad! We dropped the query, failed to create a new one
-                            // and now even the backup query does not execute!
-                            // This should not happen, but we better handle this just in case.
-                            $routine_errors[] = __('Sorry, we failed to restore the dropped routine.') . '<br />'
-                                              . __('The backed up query was:') . "\"$create_routine\"" . '<br />'
-                                              . __('MySQL said: ') . PMA_DBI_getError(null);
-                        }
-                    } else {
-                        $message = PMA_Message::success(__('Routine %1$s has been modified.'));
-                        $message->addParam(PMA_backquote($_REQUEST['routine_name']));
-                        $sql_query = $drop_routine . $routine_query;
-                    }
-                }
-            }
-        } else {
-            // 'Add a new routine' mode
-            $result = PMA_DBI_try_query($routine_query);
-            if (! $result) {
-                $routine_errors[] = sprintf(__('The following query has failed: "%s"'), $routine_query) . '<br /><br />'
-                                  . __('MySQL said: ') . PMA_DBI_getError(null);
-            } else {
-                $message = PMA_Message::success(__('Routine %1$s has been created.'));
-                $message->addParam(PMA_backquote($_REQUEST['routine_name']));
-                $sql_query = $routine_query;
-            }
-        }
-    }
-
-    if (count($routine_errors)) {
-        $message = PMA_Message::error(__('<b>One or more errors have occured while processing your request:</b>'));
-        $message->addString('<ul>');
-        foreach ($routine_errors as $num => $string) {
-            $message->addString('<li>' . $string . '</li>');
-        }
-        $message->addString('</ul>');
-    }
-
-    $output = PMA_showMessage($message, $sql_query);
-    if ($GLOBALS['is_ajax_request']) {
-        $extra_data = array();
-        if ($message->isSuccess()) {
-            $columns  = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`, `DTD_IDENTIFIER`, `ROUTINE_DEFINITION`";
-            $where    = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' AND ROUTINE_NAME='" . PMA_sqlAddSlashes($_REQUEST['routine_name']) . "'";
-            $routine  = PMA_DBI_fetch_single_row("SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE $where;");
-            $extra_data['name']      = htmlspecialchars(strtoupper($_REQUEST['routine_name']));
-            $extra_data['new_row']   = PMA_RTN_getRowForRoutinesList($routine, 0, true);
-            $response = $output;
-        } else {
-            $response = $message;
-        }
-        PMA_ajaxResponse($response, $message->isSuccess(), $extra_data);
-    }
-}
+require_once './libraries/rte/rte_routines.lib.php';
 
 /**
- * Display a form used to add/edit a routine, if necessary
+ * Do the magic
  */
-if (count($routine_errors) || ( empty($_REQUEST['routine_process_addroutine']) && empty($_REQUEST['routine_process_editroutine']) &&
-          (! empty($_REQUEST['addroutine']) || ! empty($_REQUEST['editroutine'])
-        || ! empty($_REQUEST['routine_addparameter']) || ! empty($_REQUEST['routine_removeparameter'])
-        || ! empty($_REQUEST['routine_changetype'])))) { // FIXME: this must be simpler than that
-    // Handle requests to add/remove parameters and changing routine type
-    // This is necessary when JS is disabled
-    $operation = '';
-    if (! empty($_REQUEST['routine_addparameter'])) {
-        $operation = 'add';
-    } else if (! empty($_REQUEST['routine_removeparameter'])) {
-        $operation = 'remove';
-    } else if (! empty($_REQUEST['routine_changetype'])) {
-        $operation = 'change';
-    }
-    // Get the data for the form (if any)
-    if (! empty($_REQUEST['addroutine'])) {
-        $title = __("Create routine");
-        $routine = PMA_RTN_getRoutineDataFromRequest();
-        $mode = 'add';
-    } else if (! empty($_REQUEST['editroutine'])) {
-        $title = __("Edit routine");
-        if (! $operation && ! empty($_REQUEST['routine_name']) && empty($_REQUEST['routine_process_editroutine'])) {
-            $routine = PMA_RTN_getRoutineDataFromName($db, $_REQUEST['routine_name']);
-            if ($routine !== false) {
-                $routine['original_name'] = $routine['name'];
-                $routine['original_type'] = $routine['type'];
-            }
-        } else {
-            $routine = PMA_RTN_getRoutineDataFromRequest();
-        }
-        $mode = 'edit';
-    }
-    if ($routine !== false) {
-        // Show form
-        $editor = PMA_RTN_getEditorForm($mode, $operation, $routine, $routine_errors, $GLOBALS['is_ajax_request']);
-        if ($GLOBALS['is_ajax_request']) {
-            $template   = PMA_RTN_getParameterRow();
-            $extra_data = array('title' => $title, 'param_template' => $template, 'type' => $routine['type']);
-            PMA_ajaxResponse($editor, true, $extra_data);
-        }
-        echo "\n\n<h2>$title</h2>\n\n$editor";
-        require './libraries/footer.inc.php';
-        // exit;
-    } else {
-        $message = __('Error in processing request') . ' : '
-                 . sprintf(__('No routine with name %1$s found in database %2$s'),
-                           htmlspecialchars(PMA_backquote($_REQUEST['routine_name'])),
-                           htmlspecialchars(PMA_backquote($db)));
-        $message = PMA_message::error($message);
-        if ($GLOBALS['is_ajax_request']) {
-            PMA_ajaxResponse($message, false);
-        } else {
-            $message->display();
-        }
-    }
-}
-
-/**
- * Display a list of available routines
- */
-echo PMA_RTN_getRoutinesList();
-
-/**
- * Display the form for adding a new routine, if the user has the privileges.
- */
-echo PMA_RTN_getAddRoutineLink();
-
-/**
- * Display a warning for users with PHP's old "mysql" extension.
- */
-if ($GLOBALS['cfg']['Server']['extension'] === 'mysql') {
-    trigger_error(__('You are using PHP\'s deprecated \'mysql\' extension, '
-                   . 'which is not capable of handling multi queries. '
-                   . '<b>The execution of some stored routines may fail!</b> '
-                   . 'Please use the improved \'mysqli\' extension to '
-                   . 'avoid any problems.'), E_USER_WARNING);
-}
-
-if ($GLOBALS['is_ajax_request'] != true) {
-    /**
-     * Displays the footer
-     */
-    require './libraries/footer.inc.php';
-}
+require_once './libraries/rte/rte_main.inc.php';
 
 ?>
diff --git a/db_triggers.php b/db_triggers.php
index 416be77..1bd792e 100644
--- a/db_triggers.php
+++ b/db_triggers.php
@@ -1,38 +1,32 @@
 <?php
-
+/* vim: set expandtab sw=4 ts=4 sts=4: */
 /**
+ * Triggers management.
  *
+ * @package phpMyAdmin
  */
-require_once './libraries/common.inc.php';
-require_once './libraries/common.lib.php';
-
-$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
-$GLOBALS['js_include'][] = 'display_triggers.js';
-
-/**
- * Create labels for the list
- */
-$titles = PMA_buildActionTitles();
 
 /**
- * Displays the header
+ * Include required files
  */
-require_once './libraries/db_common.inc.php';
+require_once './libraries/common.inc.php';
+require_once './libraries/common.lib.php';
 
 /**
- * Displays the tabs
+ * Include JavaScript libraries
  */
-require_once './libraries/db_info.inc.php';
+$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
+$GLOBALS['js_include'][] = 'rte/common.js';
+$GLOBALS['js_include'][] = 'rte/triggers.js';
 
 /**
- * Displays the list of triggers
+ * Include all other files
  */
-require_once './libraries/display_triggers.inc.php';
+require_once './libraries/rte/rte_triggers.lib.php';
 
 /**
- * Displays the footer
+ * Do the magic
  */
-require './libraries/footer.inc.php';
-
+require_once './libraries/rte/rte_main.inc.php';
 
 ?>
diff --git a/js/db_events.js b/js/db_events.js
deleted file mode 100644
index 3a0ccd5..0000000
--- a/js/db_events.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-
diff --git a/js/db_routines.js b/js/db_routines.js
deleted file mode 100644
index ceb0962..0000000
--- a/js/db_routines.js
+++ /dev/null
@@ -1,568 +0,0 @@
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-
-/**
- * Validate routine editor form fields.
- *
- * @param    syntaxHiglighter    an object containing the reference to the
- *                               codemirror editor. This will be used to
- *                               focus the form on the codemirror editor
- *                               if it contains invalid data.
- */
-function validateRoutineEditor(syntaxHiglighter) {
-    /**
-     * @var    inputname    Will contain the value of the name
-     *                      attribute of input fields being checked.
-     */
-    var inputname = '';
-    /**
-     * @var    $elm    a jQuery object containing the reference
-     *                 to an element that is being validated.
-     */
-    var $elm = null;
-    /**
-     * @var    isError    Stores the outcome of the validation.
-     */
-    var isError = false;
-
-    $elm = $('.rte_table').last().find('input[name=routine_name]');
-    if ($elm.val() == '') {
-        $elm.focus();
-        isError = true;
-    } else if ($elm.val().length > 64) {
-        alert(PMA_messages['strValueTooLong']);
-        $elm.focus().select();
-        return false;
-    }
-    if (! isError) {
-        $elm = $('.rte_table').find('textarea[name=routine_definition]');
-        if ($elm.val() == '') {
-            syntaxHiglighter.focus();
-            isError = true;
-        }
-    }
-    if (! isError) {
-        $('.routine_params_table').last().find('tr').each(function() {
-            if (! isError) {
-                $(this).find(':input').each(function() {
-                    inputname = $(this).attr('name');
-                    if (inputname.substr(0, 17) == 'routine_param_dir' ||
-                        inputname.substr(0, 18) == 'routine_param_name' ||
-                        inputname.substr(0, 18) == 'routine_param_type') {
-                        if ($(this).val() == '') {
-                            $(this).focus();
-                            isError = true;
-                            return false;
-                        }
-                    }
-                });
-            }
-        });
-    }
-    if (! isError) {
-        // SET, ENUM, VARCHAR and VARBINARY fields must have length/values
-        $('.routine_params_table').last().find('tr').each(function() {
-            var $inputtyp = $(this).find('select[name^=routine_param_type]');
-            var $inputlen = $(this).find('input[name^=routine_param_length]');
-            if ($inputtyp.length && $inputlen.length) {
-                if (($inputtyp.val() == 'ENUM' || $inputtyp.val() == 'SET' || $inputtyp.val().substr(0,3) == 'VAR')
-                   && $inputlen.val() == '') {
-                    $inputlen.focus();
-                    isError = true;
-                    return false;
-                }
-            }
-        });
-    }
-    if (! isError && $('select[name=routine_type]').find(':selected').val() == 'FUNCTION') {
-        // The length/values of return variable for functions must
-        // be set, if the type is SET, ENUM, VARCHAR or VARBINARY.
-        var $returntyp = $('select[name=routine_returntype]');
-        var $returnlen = $('input[name=routine_returnlength]');
-        if (($returntyp.val() == 'ENUM' || $returntyp.val() == 'SET' || $returntyp.val().substr(0,3) == 'VAR')
-           && $returnlen.val() == '') {
-            $returnlen.focus();
-            isError = true;
-        }
-    }
-    if (! isError && $('select[name=routine_type]').find(':selected').val() == 'FUNCTION') {
-        if ($('.rte_table').find('textarea[name=routine_definition]').val().toLowerCase().indexOf('return') < 0) {
-            syntaxHiglighter.focus();
-            alert(PMA_messages['MissingReturn']);
-            return false;
-        }
-    }
-    if (! isError) {
-        $elm = $('.rte_table').last().find('input[name=routine_comment]');
-        if ($elm.val().length > 64) {
-            alert(PMA_messages['strValueTooLong']);
-            $elm.focus().select();
-            return false;
-        }
-    }
-    if (! isError) {
-        return true;
-    } else {
-        alert(PMA_messages['strFormEmpty']);
-        return false;
-    }
-} // end validateRoutineEditor()
-
-/**
- * Enable/disable the "options" dropdown and "length" input for
- * parameters and the return variable in the routine editor
- * as necessary.
- *
- * @param    $type    a jQuery object containing the reference
- *                    to the "Type" dropdown box
- * @param    $len     a jQuery object containing the reference
- *                    to the "Length" input box
- * @param    $text    a jQuery object containing the reference
- *                    to the dropdown box with options for
- *                    parameters of text type
- * @param    $num     a jQuery object containing the reference
- *                    to the dropdown box with options for
- *                    parameters of numeric type
- */
-function setOptionsForParameter($type, $len, $text, $num) {
-    // Process for parameter options
-    switch ($type.val()) {
-    case 'TINYINT':
-    case 'SMALLINT':
-    case 'MEDIUMINT':
-    case 'INT':
-    case 'BIGINT':
-    case 'DECIMAL':
-    case 'FLOAT':
-    case 'DOUBLE':
-    case 'REAL':
-        $text.parent().hide();
-        $num.parent().show();
-        break;
-    case 'TINYTEXT':
-    case 'TEXT':
-    case 'MEDIUMTEXT':
-    case 'LONGTEXT':
-    case 'CHAR':
-    case 'VARCHAR':
-    case 'SET':
-    case 'ENUM':
-        $text.parent().show();
-        $text.show();
-        $num.parent().hide();
-        break;
-    default:
-        $text.parent().show();
-        $text.hide();
-        $num.parent().hide();
-        break;
-    }
-    // Process for parameter length
-    switch ($type.val()) {
-    case 'DATE':
-    case 'DATETIME':
-    case 'TIME':
-    case 'TINYBLOB':
-    case 'TINYTEXT':
-    case 'BLOB':
-    case 'TEXT':
-    case 'MEDIUMBLOB':
-    case 'MEDIUMTEXT':
-    case 'LONGBLOB':
-    case 'LONGTEXT':
-        $len.hide();
-        break;
-    default:
-        $len.show();
-        break;
-    }
-}
-
-/**
- * Attach Ajax event handlers for the Routines functionalities.
- *
- * @see $cfg['AjaxEnable']
- */
-$(document).ready(function() {
-    /**
-     * @var    $ajaxDialog    jQuery object containing the reference to the
-     *                        dialog that contains the routine editor.
-     */
-    var $ajaxDialog = null;
-    /**
-     * @var    param_template    This variable contains the template for one row
-     *                           of the parameters table that is attached to the
-     *                           dialog when a new parameter is added.
-     */
-    var param_template = '';
-    /**
-     * @var    syntaxHiglighter    Reference to the codemirror editor.
-     */
-    var syntaxHiglighter = null;
-    /**
-     * @var button_options  Object containing options for jQueryUI dialog buttons
-     */
-    var button_options = {};
-
-    /**
-     * Attach Ajax event handlers for the Add/Edit routine functionality.
-     *
-     * @uses    PMA_ajaxShowMessage()
-     * @uses    PMA_ajaxRemoveMessage()
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('.add_routine_anchor, .edit_routine_anchor').live('click', function(event) {
-        event.preventDefault();
-        /**
-         * @var    $edit_row    jQuery object containing the reference to
-         *                      the row of the the routine being edited
-         *                      from the list of routines .
-         */
-        var $edit_row = null;
-        if ($(this).hasClass('edit_routine_anchor')) {
-            // Remeber the row of the routine being edited for later,
-            // so that if the edit is successful, we can replace the
-            // row with info about the modified routine.
-            $edit_row = $(this).parents('tr');
-        }
-        /**
-         * @var    $msg    jQuery object containing the reference to
-         *                 the AJAX message shown to the user.
-         */
-        var $msg = PMA_ajaxShowMessage(PMA_messages['strLoading']);
-        $.get($(this).attr('href'), {'ajax_request': true}, function(data) {
-            if(data.success == true) {
-                PMA_ajaxRemoveMessage($msg);
-                button_options[PMA_messages['strGo']] = function() {
-                    syntaxHiglighter.save();
-                    // Validate editor and submit request, if passed.
-                    if (validateRoutineEditor(syntaxHiglighter)) {
-                        /**
-                         * @var    data    Form data to be sent in the AJAX request.
-                         */
-                        var data = $('.rte_form').last().serialize();
-                        $msg = PMA_ajaxShowMessage(PMA_messages['strLoading']);
-                        $.post('db_routines.php', data, function (data) {
-                            if(data.success == true) {
-                                // Routine created successfully
-                                PMA_ajaxRemoveMessage($msg);
-                                PMA_slidingMessage(data.message);
-                                $ajaxDialog.dialog('close');
-                                // If we are in 'edit' mode, we must remove the reference to the old row.
-                                if (mode == 'edit') {
-                                    $edit_row.remove();
-                                }
-                                // Insert the new row at the correct location in the list of routines
-                                /**
-                                 * @var    text    Contains the name of a routine from the list
-                                 *                 that is used in comparisons to find the correct
-                                 *                 location where to insert a new row.
-                                 */
-                                var text = '';
-                                /**
-                                 * @var    inserted    Whether a new has been inserted
-                                 *                     in the list of routines or not.
-                                 */
-                                var inserted = false;
-                                $('table.data').find('tr').each(function() {
-                                    text = $(this).children('td').eq(0).find('strong').text().toUpperCase();
-                                    if (text != '' && text > data.name) {
-                                        $(this).before(data.new_row);
-                                        inserted = true;
-                                        return false;
-                                    }
-                                });
-                                if (! inserted) {
-                                    $('table.data').append(data.new_row);
-                                }
-                                // Fade-in the new row
-                                $('.ajaxInsert').show('slow').removeClass('ajaxInsert');
-                                // Now we have inserted the row at the correct position, but surely
-                                // at least some row classes are wrong now. So we will itirate
-                                // throught all rows and assign correct classes to them.
-                                /**
-                                 * @var    ct    Count of processed rows.
-                                 */
-                                var ct = 0;
-                                $('table.data').find('tr').has('td').each(function() {
-                                    rowclass = (ct % 2 == 0) ? 'even' : 'odd';
-                                    $(this).removeClass().addClass(rowclass);
-                                    ct++;
-                                });
-                                // If this is the first routine being added, remove the
-                                // "No routines" message and show the list of routines.
-                                if ($('table.data').find('tr').has('td').length > 0 && $('#nothing2display').is(':visible')) {
-                                    $('#nothing2display').hide("slow", function () {
-                                        $('table.data').show("slow");
-                                    });
-                                }
-                            } else {
-                                PMA_ajaxShowMessage(data.error);
-                            }
-                        });
-                    }
-                } // end of function that handles the submission of the Editor
-                button_options[PMA_messages['strClose']] = function() {
-                    $(this).dialog("close");
-                }
-                /**
-                 * Display the dialog to the user
-                 */
-                $ajaxDialog = $('<div>'+data.message+'</div>').dialog({
-                                width: 700,  // TODO: make a better decision about the size
-                                height: 550, // of the dialog based on the size of the viewport
-                                buttons: button_options,
-                                title: data.title,
-                                modal: true,
-                                close: function () {
-                                    $(this).remove();
-                                }
-                        });
-                $ajaxDialog.find('input[name=routine_name]').focus();
-                /**
-                 * @var    mode    Used to remeber whether the editor is in
-                 *                 "Edit Routine" or "Add Routine" mode.
-                 */
-                var mode = 'add';
-                if ($('input[name=routine_process_editroutine]').length > 0) {
-                    mode = 'edit';
-                }
-                // Cache the template for a parameter table row
-                param_template = data.param_template;
-                // Make adjustments in the dialog to make it AJAX compatible
-                $('.routine_param_remove').show();
-                $('input[name=routine_removeparameter]').remove();
-                $('input[name=routine_addparameter]').css('width', '100%');
-                // Enable/disable the 'options' dropdowns for parameters as necessary
-                $('.routine_params_table').last().find('th[colspan=2]').attr('colspan', '1');
-                $('.routine_params_table').last().find('tr').has('td').each(function() {
-                    setOptionsForParameter(
-                        $(this).find('select[name^=routine_param_type]'),
-                        $(this).find('input[name^=routine_param_length]'),
-                        $(this).find('select[name^=routine_param_opts_text]'),
-                        $(this).find('select[name^=routine_param_opts_num]')
-                    );
-                });
-                // Enable/disable the 'options' dropdowns for function return value as necessary
-                setOptionsForParameter(
-                    $('.rte_table').last().find('select[name=routine_returntype]'),
-                    $('.rte_table').last().find('input[name=routine_returnlength]'),
-                    $('.rte_table').last().find('select[name=routine_returnopts_text]'),
-                    $('.rte_table').last().find('select[name=routine_returnopts_num]')
-                );
-                // Attach syntax highlited editor to routine definition
-                /**
-                 * @var    $elm    jQuery object containing the reference to
-                 *                 the "Routine Definition" textarea.
-                 */
-                var $elm = $('textarea[name=routine_definition]').last();
-                /**
-                 * @var    opts    Options to pass to the codemirror editor.
-                 */
-                var opts = {lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql"};
-                syntaxHiglighter = CodeMirror.fromTextArea($elm[0], opts);
-                // Hack to prevent the syntax highlighter from expanding beyond dialog boundries
-                $('.CodeMirror-scroll').find('div').first().css('width', '1px');
-            } else {
-                PMA_ajaxShowMessage(data.error);
-            }
-        }) // end $.get()
-    }); // end $.live()
-
-    /**
-     * Attach Ajax event handlers for the "Add parameter to routine" functionality.
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('input[name=routine_addparameter]').live('click', function(event) {
-        event.preventDefault();
-        /**
-         * @var    $routine_params_table    jQuery object containing the reference
-         *                                  to the routine parameters table.
-         */
-        var $routine_params_table = $('.routine_params_table').last();
-        /**
-         * @var    $new_param_row    A string containing the HTML code for the
-         *                           new row for the routine paramaters table.
-         */
-        var new_param_row = param_template.replace(/%s/g, $routine_params_table.find('tr').length-1);
-        $routine_params_table.append(new_param_row);
-        if ($('.rte_table').find('select[name=routine_type]').val() == 'FUNCTION') {
-            $('.routine_return_row').show();
-            $('.routine_direction_cell').hide();
-        }
-        /**
-         * @var    $newrow    jQuery object containing the reference to the newly
-         *                    inserted row in the routine parameters table.
-         */
-        var $newrow = $('.routine_params_table').last().find('tr').has('td').last();
-        setOptionsForParameter(
-            $newrow.find('select[name^=routine_param_type]'),
-            $newrow.find('input[name^=routine_param_length]'),
-            $newrow.find('select[name^=routine_param_opts_text]'),
-            $newrow.find('select[name^=routine_param_opts_num]')
-        );
-    }); // end $.live()
-
-    /**
-     * Attach Ajax event handlers for the "Remove parameter from routine" functionality.
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('.routine_param_remove_anchor').live('click', function (event) {
-        event.preventDefault();
-        $(this).parent().parent().remove();
-        // After removing a parameter, the indices of the name attributes in
-        // the input fields lose the correct order and need to be reordered.
-        /**
-         * @var    index    Counter used for reindexing the input
-         *                  fields in the routine parameters table.
-         */
-        var index = 0;
-        $('.routine_params_table').last().find('tr').has('td').each(function() {
-            $(this).find(':input').each(function() {
-                /**
-                 * @var    inputname    The value of the name attribute of
-                 *                      the input field being reindexed.
-                 */
-                var inputname = $(this).attr('name');
-                if (inputname.substr(0, 17) == 'routine_param_dir') {
-                    $(this).attr('name', inputname.substr(0, 17) + '[' + index + ']');
-                } else if (inputname.substr(0, 18) == 'routine_param_name') {
-                    $(this).attr('name', inputname.substr(0, 18) + '[' + index + ']');
-                } else if (inputname.substr(0, 18) == 'routine_param_type') {
-                    $(this).attr('name', inputname.substr(0, 18) + '[' + index + ']');
-                } else if (inputname.substr(0, 20) == 'routine_param_length') {
-                    $(this).attr('name', inputname.substr(0, 20) + '[' + index + ']');
-                } else if (inputname.substr(0, 23) == 'routine_param_opts_text') {
-                    $(this).attr('name', inputname.substr(0, 23) + '[' + index + ']');
-                } else if (inputname.substr(0, 22) == 'routine_param_opts_num') {
-                    $(this).attr('name', inputname.substr(0, 22) + '[' + index + ']');
-                }
-            });
-            index++;
-        });
-    }); // end $.live()
-
-    /**
-     * Attach Ajax event handlers for the "Change routine type" functionality.
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('select[name=routine_type]').live('change', function() {
-        $('.routine_return_row, .routine_direction_cell').toggle();
-    }); // end $.live()
-
-    /**
-     * Attach Ajax event handlers for the "Change parameter type" functionality.
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('select[name^=routine_param_type]').live('change', function() {
-        /**
-         * @var    $row    jQuery object containing the reference to
-         *                 a row in the routine parameters table.
-         */
-        var $row = $(this).parents('tr').first();
-        setOptionsForParameter(
-            $row.find('select[name^=routine_param_type]'),
-            $row.find('input[name^=routine_param_length]'),
-            $row.find('select[name^=routine_param_opts_text]'),
-            $row.find('select[name^=routine_param_opts_num]')
-        );
-    });
-
-    /**
-     * Attach Ajax event handlers for the "Change the type of return
-     * variable of function" functionality.
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('select[name=routine_returntype]').live('change', function() {
-        setOptionsForParameter(
-            $('.rte_table').find('select[name=routine_returntype]'),
-            $('.rte_table').find('input[name=routine_returnlength]'),
-            $('.rte_table').find('select[name=routine_returnopts_text]'),
-            $('.rte_table').find('select[name=routine_returnopts_num]')
-        );
-    });
-
-    /**
-     * Attach Ajax event handlers for the Execute routine functionality.
-     *
-     * @uses    PMA_ajaxShowMessage()
-     * @uses    PMA_ajaxRemoveMessage()
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('.exec_routine_anchor').live('click', function(event) {
-        event.preventDefault();
-        /**
-         * @var    $msg    jQuery object containing the reference to
-         *                 the AJAX message shown to the user.
-         */
-        var $msg = PMA_ajaxShowMessage(PMA_messages['strLoading']);
-        $.get($(this).attr('href'), {'ajax_request': true}, function(data) {
-            if(data.success == true) {
-                PMA_ajaxRemoveMessage($msg);
-                if (data.dialog) {
-                    button_options[PMA_messages['strGo']] = function() {
-                        /**
-                         * @var    data    Form data to be sent in the AJAX request.
-                         */
-                        var data = $('.rte_form').last().serialize();
-                        $msg = PMA_ajaxShowMessage(PMA_messages['strLoading']);
-                        $.post('db_routines.php', data, function (data) {
-                           if(data.success == true) {
-                                // Routine executed successfully
-                                PMA_ajaxRemoveMessage($msg);
-                                PMA_slidingMessage(data.message);
-                                $ajaxDialog.dialog('close');
-                            } else {
-                                PMA_ajaxShowMessage(data.error);
-                            }
-                        });
-                    }
-                    button_options[PMA_messages['strClose']] = function() {
-                        $(this).dialog("close");
-                    }
-                    /**
-                     * Display the dialog to the user
-                     */
-                    $ajaxDialog = $('<div>'+data.message+'</div>').dialog({
-                                    width: 650,  // TODO: make a better decision about the size
-                                                 // of the dialog based on the size of the viewport
-                                    buttons: button_options,
-                                    title: data.title,
-                                    modal: true,
-                                    close: function () {
-                                        $(this).remove();
-                                    }
-                            });
-                    $ajaxDialog.find('input[name^=params]').first().focus();
-                } else {
-                    // Routine executed successfully
-                    PMA_slidingMessage(data.message);
-                }
-            } else {
-                PMA_ajaxShowMessage(data.error);
-            }
-        });
-    });
-
-    /**
-     * Attach Ajax event handlers for input fields in the routines editor
-     * and the routine execution dialog used to submit the Ajax request
-     * when the ENTER key is pressed.
-     *
-     * @see $cfg['AjaxEnable']
-     */
-    $('input[name^=routine], input[name^=params]').live('keydown', function(e) {
-        if (e.which == 13) {
-            e.preventDefault();
-            if (typeof button_options[PMA_messages['strGo']] == 'function') {
-                button_options[PMA_messages['strGo']].call();
-            }
-        }
-    });
-}); // end of $(document).ready() for the Routine Functionalities
diff --git a/js/display_triggers.js b/js/display_triggers.js
deleted file mode 100644
index 3a0ccd5..0000000
--- a/js/display_triggers.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-
diff --git a/js/functions.js b/js/functions.js
index 9367797..1b874ca 100644
--- a/js/functions.js
+++ b/js/functions.js
@@ -2426,6 +2426,136 @@ function PMA_init_slider() {
 }
 
 /**
+ * var  toggleButton  This is a function that creates a toggle
+ *                    sliding button given a jQuery reference
+ *                    to the correct DOM element
+ */
+var toggleButton = function ($obj) {
+    // In rtl mode the toggle switch is flipped horizontally
+    // so we need to take that into account
+    if ($('.text_direction', $obj).text() == 'ltr') {
+        var right = 'right';
+    } else {
+        var right = 'left';
+    }
+	/**
+	 *  var  h  Height of the button, used to scale the
+	 *          background image and position the layers
+	 */
+	var h = $obj.height();
+	$('img', $obj).height(h);
+	$('table', $obj).css('bottom', h-1);
+	/**
+	 *  var  on   Width of the "ON" part of the toggle switch
+	 *  var  off  Width of the "OFF" part of the toggle switch
+	 */
+	var on  = $('.toggleOn', $obj).width();
+	var off = $('.toggleOff', $obj).width();
+	// Make the "ON" and "OFF" parts of the switch the same size
+	$('.toggleOn > div', $obj).width(Math.max(on, off));
+	$('.toggleOff > div', $obj).width(Math.max(on, off));
+	/**
+	 *  var  w  Width of the central part of the switch
+	 */
+	var w = parseInt(($('img', $obj).height() / 16) * 22, 10);
+	// Resize the central part of the switch on the top
+	// layer to match the background
+	$('table td:nth-child(2) > div', $obj).width(w);
+	/**
+	 *  var  imgw    Width of the background image
+	 *  var  tblw    Width of the foreground layer
+	 *  var  offset  By how many pixels to move the background
+	 *               image, so that it matches the top layer
+	 */
+	var imgw = $('img', $obj).width();
+	var tblw = $('table', $obj).width();
+	var offset = parseInt(((imgw - tblw) / 2), 10);
+	// Move the background to match the layout of the top layer
+	$obj.find('img').css(right, offset);
+	/**
+	 *  var  offw    Outer width of the "ON" part of the toggle switch
+	 *  var  btnw    Outer width of the central part of the switch
+	 */
+	var offw = $('.toggleOff', $obj).outerWidth();
+	var btnw = $('table td:nth-child(2)', $obj).outerWidth();
+	// Resize the main div so that exactly one side of
+	// the switch plus the central part fit into it.
+	$obj.width(offw + btnw + 2);
+	/**
+	 *  var  move  How many pixels to move the
+	 *             switch by when toggling
+	 */
+	var move = $('.toggleOff', $obj).outerWidth();
+	// If the switch is initialized to the
+	// OFF state we need to move it now.
+	if ($('.container', $obj).hasClass('off')) {
+        if (right == 'right') {
+    		$('table, img', $obj).animate({'left': '-=' + move + 'px'}, 0);
+        } else {
+    		$('table, img', $obj).animate({'left': '+=' + move + 'px'}, 0);
+        }
+	}
+	// Attach an 'onclick' event to the switch
+	$('.container', $obj).click(function () {
+        if ($(this).hasClass('isActive')) {
+            return false;
+        } else {
+            $(this).addClass('isActive');
+        }
+        var $msg = PMA_ajaxShowMessage(PMA_messages['strLoading']);
+        var $container = $(this);
+        var callback = $('.callback', this).text();
+		// Perform the actual toggle
+		if ($(this).hasClass('on')) {
+            if (right == 'right') {
+                var operator = '-=';
+            } else {
+                var operator = '+=';
+            }
+            var url = $(this).find('.toggleOff > span').text();
+            var removeClass = 'on';
+            var addClass = 'off';
+		} else {
+            if (right == 'right') {
+                var operator = '+=';
+            } else {
+                var operator = '-=';
+            }
+            var url = $(this).find('.toggleOn > span').text();
+            var removeClass = 'off';
+            var addClass = 'on';
+        }
+        $.post(url, {'ajax_request': true}, function(data) {
+            if(data.success == true) {
+                PMA_ajaxRemoveMessage($msg);
+		        $container
+		        .removeClass(removeClass)
+		        .addClass(addClass)
+		        .animate({'left': operator + move + 'px'}, function () {
+                    $container.removeClass('isActive');
+                });
+                eval(callback);
+            } else {
+                PMA_ajaxShowMessage(data.error);
+                $container.removeClass('isActive');
+            }
+        });
+	});
+};
+
+/**
+ * Initialise all toggle buttons
+ */
+$(window).load(function () {
+    $('.toggleAjax').each(function () {
+        $(this)
+        .show()
+        .find('.toggleButton')
+		toggleButton($(this));
+	});
+});
+
+/**
  * Vertical pointer
  */
 $(document).ready(function() {
@@ -2529,44 +2659,6 @@ $(document).ready(function() {
 }) // end of $(document).ready()
 
 /**
- * Attach Ajax event handlers for Export of Routines, Triggers and Events.
- *
- * @uses    PMA_ajaxShowMessage()
- * @uses    PMA_ajaxRemoveMessage()
- *
- * @see $cfg['AjaxEnable']
- */
-$(document).ready(function() {
-    $('.export_routine_anchor, .export_trigger_anchor, .export_event_anchor').live('click', function(event) {
-        event.preventDefault();
-        var $msg = PMA_ajaxShowMessage(PMA_messages['strLoading']);
-        $.get($(this).attr('href'), {'ajax_request': true}, function(data) {
-            if(data.success == true) {
-                PMA_ajaxRemoveMessage($msg);
-                /**
-                 * @var button_options  Object containing options for jQueryUI dialog buttons
-                 */
-                var button_options = {};
-                button_options[PMA_messages['strClose']] = function() {$(this).dialog("close").remove();}
-                /**
-                 * Display the dialog to the user
-                 */
-                var $ajaxDialog = $('<div>'+data.message+'</div>').dialog({
-                                      width: 500,
-                                      buttons: button_options,
-                                      title: data.title
-                                  });
-                // Attach syntax highlited editor to export dialog
-                var elm = $ajaxDialog.find('textarea');
-                CodeMirror.fromTextArea(elm[0], {lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql"});
-            } else {
-                PMA_ajaxShowMessage(data.error);
-            }
-        }) // end $.get()
-    }); // end $.live()
-}); // end of $(document).ready() for Export of Routines, Triggers and Events.
-
-/**
  * Creates a message inside an object with a sliding effect
  *
  * @param   msg    A string containing the text to display
@@ -2644,69 +2736,6 @@ function PMA_slidingMessage(msg, $obj) {
 } // end PMA_slidingMessage()
 
 /**
- * Attach Ajax event handlers for Drop functionality of Routines, Triggers and Events.
- *
- * @uses    $.PMA_confirm()
- * @uses    PMA_ajaxShowMessage()
- * @see     $cfg['AjaxEnable']
- */
-$(document).ready(function() {
-    $('.drop_routine_anchor, .drop_trigger_anchor, .drop_event_anchor').live('click', function(event) {
-        event.preventDefault();
-        /**
-         * @var $curr_row    Object containing reference to the current row
-         */
-        var $curr_row = $(this).parents('tr');
-        /**
-         * @var question    String containing the question to be asked for confirmation
-         */
-        var question = $('<div></div>').text($curr_row.children('td').children('.drop_sql').html());
-        $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
-            /**
-             * @var    $msg    jQuery object containing the reference to
-             *                 the AJAX message shown to the user.
-             */
-            var $msg = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
-            $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
-                if(data.success == true) {
-                    /**
-                     * @var $table    Object containing reference to the main list of elements.
-                     */
-                    var $table = $curr_row.parent();
-                    if ($table.find('tr').length == 2) {
-                        $table.hide("slow", function () {
-                            $(this).find('tr.even, tr.odd').remove();
-                            $('#nothing2display').show("slow");
-                        });
-                    } else {
-                        $curr_row.hide("slow", function () {
-                            $(this).remove();
-                            // Now we have removed the row from the list, but maybe
-                            // some row classes are wrong now. So we will itirate
-                            // throught all rows and assign correct classes to them.
-                            /**
-                             * @var    ct    Count of processed rows.
-                             */
-                            var ct = 0;
-                            $table.find('tr').has('td').each(function() {
-                                rowclass = (ct % 2 == 0) ? 'even' : 'odd';
-                                $(this).removeClass().addClass(rowclass);
-                                ct++;
-                            });
-                        });
-                    }
-                    // Show the query that we just executed
-                    PMA_ajaxRemoveMessage($msg);
-                    PMA_slidingMessage(data.sql_query);
-                } else {
-                    PMA_ajaxShowMessage(PMA_messages['strErrorProcessingRequest'] + " : " + data.error);
-                }
-            }) // end $.get()
-        }) // end $.PMA_confirm()
-    }); // end $.live()
-}); //end $(document).ready() for Drop functionality of Routines, Triggers and Events.
-
-/**
  * Attach Ajax event handlers for Drop Table.
  *
  * @uses    $.PMA_confirm()
diff --git a/js/messages.php b/js/messages.php
index b8ac2ba..4bf5d7c 100644
--- a/js/messages.php
+++ b/js/messages.php
@@ -122,7 +122,6 @@ $js_messages['strDeleting'] = __('Deleting');
 
 /* For db_routines.js */
 $js_messages['MissingReturn'] = __('The definition of a stored function must contain a RETURN statement!');
-$js_messages['strValueTooLong'] = __('Value too long in the form!');
 
 /* For import.js */
 $js_messages['strImportCSV'] = __('Note: If the file contains multiple tables, they will be combined into one');
diff --git a/js/rte/common.js b/js/rte/common.js
new file mode 100644
index 0000000..4e3893e
--- /dev/null
+++ b/js/rte/common.js
@@ -0,0 +1,380 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+
+/**
+ * @var    RTE    a JavaScript namespace containing the functionality
+ *                for Routines, Triggers and Events.
+ *
+ *                This namespace is extended by the functionality required
+ *                to handle a specific item (a routine, trigger or event)
+ *                in the relevant javascript files in this folder.
+ */
+var RTE = {
+    /**
+     * @var    $ajaxDialog        jQuery object containing the reference to the
+     *                            dialog that contains the editor.
+     */
+    $ajaxDialog: null,
+    /**
+     * @var    syntaxHiglighter   Reference to the codemirror editor.
+     */
+    syntaxHiglighter: null,
+    /**
+     * @var    buttonOptions      Object containing options for
+     *                            the jQueryUI dialog buttons
+     */
+    buttonOptions: {},
+    /**
+     * Validate editor form fields.
+     */
+    validate: function () {
+        /**
+         * @var    $elm    a jQuery object containing the reference
+         *                 to an element that is being validated.
+         */
+        var $elm = null;
+        // Common validation. At the very least the name
+        // and the definition must be provided for an item
+        $elm = $('.rte_table').last().find('input[name=item_name]');
+        if ($elm.val() === '') {
+            $elm.focus();
+            alert(PMA_messages['strFormEmpty']);
+            return false;
+        }
+        $elm = $('.rte_table').find('textarea[name=item_definition]');
+        if ($elm.val() === '') {
+            this.syntaxHiglighter.focus();
+            alert(PMA_messages['strFormEmpty']);
+            return false;
+        }
+        // The validation has so far passed, so now
+        // we can validate item-specific fields.
+        return RTE.validateCustom();
+    }, // end validate()
+    /**
+     * Validate custom editor form fields.
+     * This function can be overridden by
+     * other files in this folder.
+     */
+    validateCustom: function () {
+        return true;
+    }, // end validateCustom()
+    /**
+     * Execute some code after the ajax
+     * dialog for the ditor is shown.
+     * This function can be overridden by
+     * other files in this folder.
+     */
+    postDialogShow: function () {
+        // Nothing by default
+    } // end postDialogShow()
+}; // end RTE namespace
+
+/**
+ * Attach Ajax event handlers for the Routines, Triggers and Events editor.
+ *
+ * @see $cfg['AjaxEnable']
+ */
+$(document).ready(function () {
+    /**
+     * Attach Ajax event handlers for the Add/Edit functionality.
+     */
+    $('.ajax_add_anchor, .ajax_edit_anchor').live('click', function (event) {
+        event.preventDefault();
+        /**
+         * @var    $edit_row    jQuery object containing the reference to
+         *                      the row of the the item being edited
+         *                      from the list of items .
+         */
+        var $edit_row = null;
+        if ($(this).hasClass('ajax_edit_anchor')) {
+            // Remeber the row of the item being edited for later,
+            // so that if the edit is successful, we can replace the
+            // row with info about the modified item.
+            $edit_row = $(this).parents('tr');
+        }
+        /**
+         * @var    $msg    jQuery object containing the reference to
+         *                 the AJAX message shown to the user.
+         */
+        var $msg = PMA_ajaxShowMessage();
+        $.get($(this).attr('href'), {'ajax_request': true}, function (data) {
+            if (data.success === true) {
+                // We have successfully fetched the editor form
+                PMA_ajaxRemoveMessage($msg);
+                // Now define the function that is called when
+                // the user presses the "Go" button
+                RTE.buttonOptions[PMA_messages['strGo']] = function () {
+                    // Move the data from the codemirror editor back to the
+                    // textarea, where it can be used in the form submission.
+                    RTE.syntaxHiglighter.save();
+                    // Validate editor and submit request, if passed.
+                    if (RTE.validate()) {
+                        /**
+                         * @var    data    Form data to be sent in the AJAX request.
+                         */
+                        var data = $('.rte_form').last().serialize();
+                        $msg = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
+                        $.post($('.rte_form').last().attr('action'), data, function (data) {
+                            if (data.success === true) {
+                                // Item created successfully
+                                PMA_ajaxRemoveMessage($msg);
+                                PMA_slidingMessage(data.message);
+                                RTE.$ajaxDialog.dialog('close');
+                                // If we are in 'edit' mode, we must remove the reference to the old row.
+                                if (mode === 'edit') {
+                                    $edit_row.remove();
+                                }
+                                // Sometimes, like when moving a trigger from a table to
+                                // another one, the new row should not be inserted into the
+                                // list. In this case "data.insert" will be set to false.
+                                if (data.insert) {
+                                    // Insert the new row at the correct location in the list of items
+                                    /**
+                                     * @var    text    Contains the name of an item from the list
+                                     *                 that is used in comparisons to find the correct
+                                     *                 location where to insert a new row.
+                                     */
+                                    var text = '';
+                                    /**
+                                     * @var    inserted    Whether a new item has been inserted
+                                     *                     in the list or not.
+                                     */
+                                    var inserted = false;
+                                    $('table.data').find('tr').each(function () {
+                                        text = $(this)
+                                                .children('td')
+                                                .eq(0)
+                                                .find('strong')
+                                                .text()
+                                                .toUpperCase();
+                                        text = $.trim(text);
+                                        if (text !== '' && text > data.name) {
+                                            $(this).before(data.new_row);
+                                            inserted = true;
+                                            return false;
+                                        }
+                                    });
+                                    if (! inserted) {
+                                        // If we didn't manage to insert the row yet,
+                                        // it must belong at the end of the list,
+                                        // so we insert it there.
+                                        $('table.data').append(data.new_row);
+                                    }
+                                    // Fade-in the new row
+                                    $('.ajaxInsert').show('slow').removeClass('ajaxInsert');
+                                } else if ($('table.data').find('tr').has('td').length === 0) {
+                                    // If we are not supposed to insert the new row, we will now
+                                    // check if the table is empty and needs to be hidden. This
+                                    // will be the case if we were editing the only item in the
+                                    // list, which we removed and will not be inserting something
+                                    // else in its place.
+                                    $('table.data').hide("slow", function () {
+                                        $('#nothing2display').show("slow");
+                                    });
+                                }
+                                // Now we have inserted the row at the correct position, but surely
+                                // at least some row classes are wrong now. So we will itirate
+                                // throught all rows and assign correct classes to them.
+                                /**
+                                 * @var    ct          Count of processed rows.
+                                 */
+                                var ct = 0;
+                                /**
+                                 * @var    rowclass    Class to be attached to the row
+                                 *                     that is being processed
+                                 */
+                                var rowclass = '';
+                                $('table.data').find('tr').has('td').each(function () {
+                                    rowclass = (ct % 2 === 0) ? 'even' : 'odd';
+                                    $(this).removeClass().addClass(rowclass);
+                                    ct++;
+                                });
+                                // If this is the first item being added, remove
+                                // the "No items" message and show the list.
+                                if ($('table.data').find('tr').has('td').length > 0
+                                    && $('#nothing2display').is(':visible')) {
+                                    $('#nothing2display').hide("slow", function () {
+                                        $('table.data').show("slow");
+                                    });
+                                }
+                            } else {
+                                PMA_ajaxShowMessage(data.error);
+                            }
+                        }); // end $.post()
+                    } // end "if (RTE.validate())"
+                }; // end of function that handles the submission of the Editor
+                RTE.buttonOptions[PMA_messages['strClose']] = function () {
+                    $(this).dialog("close");
+                };
+                /**
+                 * Display the dialog to the user
+                 */
+                RTE.$ajaxDialog = $('<div>' + data.message + '</div>').dialog({
+                                width: 700,
+                                height: 555,
+                                buttons: RTE.buttonOptions,
+                                title: data.title,
+                                modal: true,
+                                close: function () {
+                                    $(this).remove();
+                                }
+                        });
+                RTE.$ajaxDialog.find('input[name=item_name]').focus();
+                RTE.$ajaxDialog.find('.datefield, .datetimefield').each(function () {
+                    PMA_addDatepicker($(this).css('width', '95%'));
+                });
+                /**
+                 * @var    mode    Used to remeber whether the editor is in
+                 *                 "Edit" or "Add" mode.
+                 */
+                var mode = 'add';
+                if ($('input[name=editor_process_edit]').length > 0) {
+                    mode = 'edit';
+                }
+                // Attach syntax highlited editor to the definition
+                /**
+                 * @var    $elm    jQuery object containing the reference to
+                 *                 the Definition textarea.
+                 */
+                var $elm = $('textarea[name=item_definition]').last();
+                /**
+                 * @var    opts    Options to pass to the codemirror editor.
+                 */
+                var opts = {lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql"};
+                RTE.syntaxHiglighter = CodeMirror.fromTextArea($elm[0], opts);
+                // Hack to prevent the syntax highlighter from expanding beyond dialog boundries
+                $('.CodeMirror-scroll').find('div').first().css('width', '1px');
+                // Execute item-specific code
+                RTE.postDialogShow(data);
+            } else {
+                PMA_ajaxShowMessage(data.error);
+            }
+        }); // end $.get()
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for input fields in the editor
+     * and the routine execution dialog used to submit the Ajax
+     * request when the ENTER key is pressed.
+     */
+    $('.rte_table').find('input[name^=item], input[name^=params]').live('keydown', function (e) {
+        if (e.which === 13) { // 13 is the ENTER key
+            e.preventDefault();
+            if (typeof RTE.buttonOptions[PMA_messages['strGo']] === 'function') {
+                RTE.buttonOptions[PMA_messages['strGo']].call();
+            }
+        }
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for Export of Routines, Triggers and Events.
+     */
+    $('.ajax_export_anchor').live('click', function (event) {
+        event.preventDefault();
+        var $msg = PMA_ajaxShowMessage();
+        // Fire the ajax request straight away
+        $.get($(this).attr('href'), {'ajax_request': true}, function (data) {
+            if (data.success === true) {
+                PMA_ajaxRemoveMessage($msg);
+                /**
+                 * @var button_options  Object containing options for jQueryUI dialog buttons
+                 */
+                var button_options = {};
+                button_options[PMA_messages['strClose']] = function () {
+                    $(this).dialog("close").remove();
+                };
+                /**
+                 * Display the dialog to the user
+                 */
+                var $ajaxDialog = $('<div>' + data.message + '</div>').dialog({
+                                      width: 500,
+                                      buttons: button_options,
+                                      title: data.title
+                                  });
+                // Attach syntax highlited editor to export dialog
+                /**
+                 * @var    $elm    jQuery object containing the reference
+                 *                 to the Export textarea.
+                 */
+                var $elm = $ajaxDialog.find('textarea');
+                /**
+                 * @var    opts    Options to pass to the codemirror editor.
+                 */
+                var opts = {lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql"};
+                CodeMirror.fromTextArea($elm[0], opts);
+            } else {
+                PMA_ajaxShowMessage(data.error);
+            }
+        }); // end $.get()
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for Drop functionality of Routines, Triggers and Events.
+     */
+    $('.ajax_drop_anchor').live('click', function (event) {
+        event.preventDefault();
+        /**
+         * @var $curr_row    Object containing reference to the current row
+         */
+        var $curr_row = $(this).parents('tr');
+        /**
+         * @var question    String containing the question to be asked for confirmation
+         */
+        var question = $('<div></div>').text($curr_row.children('td').children('.drop_sql').html());
+        // We ask for confirmation first here, before submitting the ajax request
+        $(this).PMA_confirm(question, $(this).attr('href'), function (url) {
+            /**
+             * @var    $msg    jQuery object containing the reference to
+             *                 the AJAX message shown to the user.
+             */
+            var $msg = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
+            $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function (data) {
+                if (data.success === true) {
+                    /**
+                     * @var $table    Object containing reference to the main list of elements.
+                     */
+                    var $table = $curr_row.parent();
+                    // Check how many rows will be left after we remove
+                    // the one that the user has requested us to remove
+                    if ($table.find('tr').length === 2) {
+                        // If there are two rows left, it means that they are
+                        // the header of the table and the rows that we are
+                        // about to remove, so after the removal there will be
+                        // nothing to show in the table, so we hide it.
+                        $table.hide("slow", function () {
+                            $(this).find('tr.even, tr.odd').remove();
+                            $('#nothing2display').show("slow");
+                        });
+                    } else {
+                        $curr_row.hide("slow", function () {
+                            $(this).remove();
+                            // Now we have removed the row from the list, but maybe
+                            // some row classes are wrong now. So we will itirate
+                            // throught all rows and assign correct classes to them.
+                            /**
+                             * @var    ct          Count of processed rows.
+                             */
+                            var ct = 0;
+                            /**
+                             * @var    rowclass    Class to be attached to the row
+                             *                     that is being processed
+                             */
+                            var rowclass = '';
+                            $table.find('tr').has('td').each(function () {
+                                rowclass = (ct % 2 === 0) ? 'even' : 'odd';
+                                $(this).removeClass().addClass(rowclass);
+                                ct++;
+                            });
+                        });
+                    }
+                    // Get rid of the "Loading" message
+                    PMA_ajaxRemoveMessage($msg);
+                    // Show the query that we just executed
+                    PMA_slidingMessage(data.sql_query);
+                } else {
+                    PMA_ajaxShowMessage(PMA_messages['strErrorProcessingRequest'] + " : " + data.error);
+                }
+            }); // end $.get()
+        }); // end $.PMA_confirm()
+    }); // end $.live()
+}); // end of $(document).ready()
diff --git a/js/rte/events.js b/js/rte/events.js
new file mode 100644
index 0000000..257a17d
--- /dev/null
+++ b/js/rte/events.js
@@ -0,0 +1,43 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+
+/**
+ * Overriding the validateCustom() function defined in common.js
+ */
+RTE.validateCustom = function () {
+    /**
+     * @var    $elm    a jQuery object containing the reference
+     *                 to an element that is being validated.
+     */
+    var $elm = null;
+    if ($('select[name=item_type]').find(':selected').val() === 'RECURRING') {
+        // The interval field must not be empty for recurring events
+        $elm = $('input[name=item_interval_value]');
+        if ($elm.val() === '') {
+            $elm.focus();
+            alert(PMA_messages['strFormEmpty']);
+            return false;
+        }
+    } else {
+        // The execute_at field must not be empty for "once off" events
+        $elm = $('input[name=item_execute_at]');
+        if ($elm.val() === '') {
+            $elm.focus();
+            alert(PMA_messages['strFormEmpty']);
+            return false;
+        }
+    }
+    return true;
+}; // end RTE.validateCustom()
+
+/**
+ * Attach Ajax event handlers for the "Change event type"
+ * functionality in the events editor, so that the correct
+ * rows are shown in the editor when changing the event type
+ *
+ * @see $cfg['AjaxEnable']
+ */
+$(document).ready(function () {
+    $('select[name=item_type]').live('change', function () {
+        $('.recurring_event_row, .onetime_event_row').toggle();
+    }); // end $.live()
+}); // end of $(document).ready()
diff --git a/js/rte/routines.js b/js/rte/routines.js
new file mode 100644
index 0000000..50c4f00
--- /dev/null
+++ b/js/rte/routines.js
@@ -0,0 +1,395 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+
+/**
+ * @var    param_template    This variable contains the template for one row
+ *                           of the parameters table that is attached to the
+ *                           dialog when a new parameter is added.
+ */
+RTE.param_template = '';
+
+/**
+ * Overriding the postDialogShow() function defined in common.js
+ *
+ * @param   data   JSON-encoded data from the ajax request
+ */
+RTE.postDialogShow = function (data) {
+    // Cache the template for a parameter table row
+    RTE.param_template = data.param_template;
+    // Make adjustments in the dialog to make it AJAX compatible
+    $('.routine_param_remove').show();
+    $('input[name=routine_removeparameter]').remove();
+    $('input[name=routine_addparameter]').css('width', '100%');
+    // Enable/disable the 'options' dropdowns for parameters as necessary
+    $('.routine_params_table').last().find('th[colspan=2]').attr('colspan', '1');
+    $('.routine_params_table').last().find('tr').has('td').each(function () {
+        RTE.setOptionsForParameter(
+            $(this).find('select[name^=item_param_type]'),
+            $(this).find('input[name^=item_param_length]'),
+            $(this).find('select[name^=item_param_opts_text]'),
+            $(this).find('select[name^=item_param_opts_num]')
+        );
+    });
+    // Enable/disable the 'options' dropdowns for
+    // function return value as necessary
+    RTE.setOptionsForParameter(
+        $('.rte_table').last().find('select[name=item_returntype]'),
+        $('.rte_table').last().find('input[name=item_returnlength]'),
+        $('.rte_table').last().find('select[name=item_returnopts_text]'),
+        $('.rte_table').last().find('select[name=item_returnopts_num]')
+    );
+}; // end RTE.postDialogShow()
+
+/**
+ * Overriding the validateCustom() function defined in common.js
+ */
+RTE.validateCustom = function () {
+    /**
+     * @var   isSuccess   Stores the outcome of the validation
+     */
+    var isSuccess = true;
+    /**
+     * @var   inputname   The value of the "name" attribute for
+     *                    the field that is being processed
+     */
+    var inputname = '';
+    $('.routine_params_table').last().find('tr').each(function () {
+        // Every parameter of a routine must have
+        // a non-empty direction, name and type
+        if (isSuccess) {
+            $(this).find(':input').each(function () {
+                inputname = $(this).attr('name');
+                if (inputname.substr(0, 17) === 'item_param_dir' ||
+                    inputname.substr(0, 18) === 'item_param_name' ||
+                    inputname.substr(0, 18) === 'item_param_type') {
+                    if ($(this).val() === '') {
+                        $(this).focus();
+                        isSuccess = false;
+                        return false;
+                    }
+                }
+            });
+        } else {
+            return false;
+        }
+    });
+    if (! isSuccess) {
+        alert(PMA_messages['strFormEmpty']);
+        return false;
+    }
+    $('.routine_params_table').last().find('tr').each(function () {
+        // SET, ENUM, VARCHAR and VARBINARY fields must have length/values
+        var $inputtyp = $(this).find('select[name^=item_param_type]');
+        var $inputlen = $(this).find('input[name^=item_param_length]');
+        if ($inputtyp.length && $inputlen.length) {
+            if (($inputtyp.val() === 'ENUM' || $inputtyp.val() === 'SET' || $inputtyp.val().substr(0, 3) === 'VAR')
+               && $inputlen.val() === '') {
+                $inputlen.focus();
+                isSuccess = false;
+                return false;
+            }
+        }
+    });
+    if (! isSuccess) {
+        alert(PMA_messages['strFormEmpty']);
+        return false;
+    }
+    if ($('select[name=item_type]').find(':selected').val() === 'FUNCTION') {
+        // The length/values of return variable for functions must
+        // be set, if the type is SET, ENUM, VARCHAR or VARBINARY.
+        var $returntyp = $('select[name=item_returntype]');
+        var $returnlen = $('input[name=item_returnlength]');
+        if (($returntyp.val() === 'ENUM' || $returntyp.val() === 'SET' || $returntyp.val().substr(0, 3) === 'VAR')
+           && $returnlen.val() === '') {
+            $returnlen.focus();
+            alert(PMA_messages['strFormEmpty']);
+            return false;
+        }
+    }
+    if ($('select[name=item_type]').find(':selected').val() === 'FUNCTION') {
+        // A function must contain a RETURN statement in its definition
+        if ($('.rte_table').find('textarea[name=item_definition]').val().toUpperCase().indexOf('RETURN') < 0) {
+            RTE.syntaxHiglighter.focus();
+            alert(PMA_messages['MissingReturn']);
+            return false;
+        }
+    }
+    return true;
+}; // end RTE.validateCustom()
+
+/**
+ * Enable/disable the "options" dropdown and "length" input for
+ * parameters and the return variable in the routine editor
+ * as necessary.
+ *
+ * @param    $type    a jQuery object containing the reference
+ *                    to the "Type" dropdown box
+ * @param    $len     a jQuery object containing the reference
+ *                    to the "Length" input box
+ * @param    $text    a jQuery object containing the reference
+ *                    to the dropdown box with options for
+ *                    parameters of text type
+ * @param    $num     a jQuery object containing the reference
+ *                    to the dropdown box with options for
+ *                    parameters of numeric type
+ */
+RTE.setOptionsForParameter = function ($type, $len, $text, $num) {
+    /**
+     * @var   $no_opts   a jQuery object containing the reference
+     *                   to an element to be displayed when no
+     *                   options are available
+     */
+    var $no_opts = $text.parent().parent().find('.no_opts');
+    /**
+     * @var   $no_len    a jQuery object containing the reference
+     *                   to an element to be displayed when no
+     *                  "length/values" field is available
+     */
+    var $no_len  = $len.parent().parent().find('.no_len');
+
+    // Process for parameter options
+    switch ($type.val()) {
+    case 'TINYINT':
+    case 'SMALLINT':
+    case 'MEDIUMINT':
+    case 'INT':
+    case 'BIGINT':
+    case 'DECIMAL':
+    case 'FLOAT':
+    case 'DOUBLE':
+    case 'REAL':
+        $text.parent().hide();
+        $num.parent().show();
+        $no_opts.hide();
+        break;
+    case 'TINYTEXT':
+    case 'TEXT':
+    case 'MEDIUMTEXT':
+    case 'LONGTEXT':
+    case 'CHAR':
+    case 'VARCHAR':
+    case 'SET':
+    case 'ENUM':
+        $text.parent().show();
+        $num.parent().hide();
+        $no_opts.hide();
+        break;
+    default:
+        $text.parent().hide();
+        $num.parent().hide();
+        $no_opts.show();
+        break;
+    }
+    // Process for parameter length
+    switch ($type.val()) {
+    case 'DATE':
+    case 'DATETIME':
+    case 'TIME':
+    case 'TINYBLOB':
+    case 'TINYTEXT':
+    case 'BLOB':
+    case 'TEXT':
+    case 'MEDIUMBLOB':
+    case 'MEDIUMTEXT':
+    case 'LONGBLOB':
+    case 'LONGTEXT':
+        $len.parent().hide();
+        $no_len.show();
+        break;
+    default:
+        $len.parent().show();
+        $no_len.hide();
+        break;
+    }
+}; // end RTE.setOptionsForParameter()
+
+/**
+ * Attach Ajax event handlers for the Routines functionalities.
+ *
+ * @see $cfg['AjaxEnable']
+ */
+$(document).ready(function () {
+    /**
+     * Attach Ajax event handlers for the "Add parameter to routine" functionality.
+     */
+    $('input[name=routine_addparameter]').live('click', function (event) {
+        event.preventDefault();
+        /**
+         * @var    $routine_params_table    jQuery object containing the reference
+         *                                  to the routine parameters table.
+         */
+        var $routine_params_table = $('.routine_params_table').last();
+        /**
+         * @var    $new_param_row    A string containing the HTML code for the
+         *                           new row for the routine paramaters table.
+         */
+        var new_param_row = RTE.param_template.replace(/%s/g, $routine_params_table.find('tr').length - 1);
+        // Append the new row to the parameters table
+        $routine_params_table.append(new_param_row);
+        // Make sure that the row is correctly shown according to the type of routine
+        if ($('.rte_table').find('select[name=item_type]').val() === 'FUNCTION') {
+            $('.routine_return_row').show();
+            $('.routine_direction_cell').hide();
+        }
+        /**
+         * @var    $newrow    jQuery object containing the reference to the newly
+         *                    inserted row in the routine parameters table.
+         */
+        var $newrow = $('.routine_params_table').last().find('tr').has('td').last();
+        // Enable/disable the 'options' dropdowns for parameters as necessary
+        RTE.setOptionsForParameter(
+            $newrow.find('select[name^=item_param_type]'),
+            $newrow.find('input[name^=item_param_length]'),
+            $newrow.find('select[name^=item_param_opts_text]'),
+            $newrow.find('select[name^=item_param_opts_num]')
+        );
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for the "Remove parameter from routine" functionality.
+     */
+    $('.routine_param_remove_anchor').live('click', function (event) {
+        event.preventDefault();
+        $(this).parent().parent().remove();
+        // After removing a parameter, the indices of the name attributes in
+        // the input fields lose the correct order and need to be reordered.
+        /**
+         * @var    index    Counter used for reindexing the input
+         *                  fields in the routine parameters table.
+         */
+        var index = 0;
+        $('.routine_params_table').last().find('tr').has('td').each(function () {
+            $(this).find(':input').each(function () {
+                /**
+                 * @var    inputname    The value of the name attribute of
+                 *                      the input field being reindexed.
+                 */
+                var inputname = $(this).attr('name');
+                if (inputname.substr(0, 17) === 'item_param_dir') {
+                    $(this).attr('name', inputname.substr(0, 17) + '[' + index + ']');
+                } else if (inputname.substr(0, 18) === 'item_param_name') {
+                    $(this).attr('name', inputname.substr(0, 18) + '[' + index + ']');
+                } else if (inputname.substr(0, 18) === 'item_param_type') {
+                    $(this).attr('name', inputname.substr(0, 18) + '[' + index + ']');
+                } else if (inputname.substr(0, 20) === 'item_param_length') {
+                    $(this).attr('name', inputname.substr(0, 20) + '[' + index + ']');
+                } else if (inputname.substr(0, 23) === 'item_param_opts_text') {
+                    $(this).attr('name', inputname.substr(0, 23) + '[' + index + ']');
+                } else if (inputname.substr(0, 22) === 'item_param_opts_num') {
+                    $(this).attr('name', inputname.substr(0, 22) + '[' + index + ']');
+                }
+            });
+            index++;
+        });
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for the "Change routine type"
+     * functionality in the routines editor, so that the correct
+     * fields are shown in the editor when changing the routine type
+     */
+    $('select[name=item_type]').live('change', function () {
+        $('.routine_return_row, .routine_direction_cell').toggle();
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for the "Change parameter type"
+     * functionality in the routines editor, so that the correct
+     * option/length fields, if any, are shown when changing
+     * a parameter type
+     */
+    $('select[name^=item_param_type]').live('change', function () {
+        /**
+         * @var    $row    jQuery object containing the reference to
+         *                 a row in the routine parameters table
+         */
+        var $row = $(this).parents('tr').first();
+        RTE.setOptionsForParameter(
+            $row.find('select[name^=item_param_type]'),
+            $row.find('input[name^=item_param_length]'),
+            $row.find('select[name^=item_param_opts_text]'),
+            $row.find('select[name^=item_param_opts_num]')
+        );
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for the "Change the type of return
+     * variable of function" functionality, so that the correct fields,
+     * if any, are shown when changing the function return type type
+     */
+    $('select[name=item_returntype]').live('change', function () {
+        RTE.setOptionsForParameter(
+            $('.rte_table').find('select[name=item_returntype]'),
+            $('.rte_table').find('input[name=item_returnlength]'),
+            $('.rte_table').find('select[name=item_returnopts_text]'),
+            $('.rte_table').find('select[name=item_returnopts_num]')
+        );
+    }); // end $.live()
+
+    /**
+     * Attach Ajax event handlers for the Execute routine functionality.
+     */
+    $('.ajax_exec_anchor').live('click', function (event) {
+        event.preventDefault();
+        /**
+         * @var    $msg    jQuery object containing the reference to
+         *                 the AJAX message shown to the user
+         */
+        var $msg = PMA_ajaxShowMessage();
+        $.get($(this).attr('href'), {'ajax_request': true}, function (data) {
+            if (data.success === true) {
+                PMA_ajaxRemoveMessage($msg);
+                // If 'data.dialog' is true we show a dialog with a form
+                // to get the input parameters for routine, otherwise
+                // we just show the results of the query
+                if (data.dialog) {
+                    // Define the function that is called when
+                    // the user presses the "Go" button
+                    RTE.buttonOptions[PMA_messages['strGo']] = function () {
+                        /**
+                         * @var    data    Form data to be sent in the AJAX request.
+                         */
+                        var data = $('.rte_form').last().serialize();
+                        $msg = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
+                        $.post('db_routines.php', data, function (data) {
+                            if (data.success === true) {
+                                // Routine executed successfully
+                                PMA_ajaxRemoveMessage($msg);
+                                PMA_slidingMessage(data.message);
+                                $ajaxDialog.dialog('close');
+                            } else {
+                                PMA_ajaxShowMessage(data.error);
+                            }
+                        });
+                    };
+                    RTE.buttonOptions[PMA_messages['strClose']] = function () {
+                        $(this).dialog("close");
+                    };
+                    /**
+                     * Display the dialog to the user
+                     */
+                    $ajaxDialog = $('<div>' + data.message + '</div>').dialog({
+                                    width: 650,
+                                    buttons: RTE.buttonOptions,
+                                    title: data.title,
+                                    modal: true,
+                                    close: function () {
+                                        $(this).remove();
+                                    }
+                            });
+                    $ajaxDialog.find('input[name^=params]').first().focus();
+                    /**
+                     * Attach the datepickers to the relevant form fields
+                     */
+                    $ajaxDialog.find('.datefield, .datetimefield').each(function () {
+                        PMA_addDatepicker($(this).css('width', '95%'));
+                    });
+                } else {
+                    // Routine executed successfully
+                    PMA_slidingMessage(data.message);
+                }
+            } else {
+                PMA_ajaxShowMessage(data.error);
+            }
+        }); // end $.get()
+    }); // end $.live()
+}); // end of $(document).ready() for the Routine Functionalities
diff --git a/js/rte/triggers.js b/js/rte/triggers.js
new file mode 100644
index 0000000..826cd55
--- /dev/null
+++ b/js/rte/triggers.js
@@ -0,0 +1,8 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+
+/**
+ * So far it looks like triggers don't need
+ * any special treatment as far as JavaScript
+ * goes, but leaving this file here in case
+ * the need for custom code will arise.
+ */
diff --git a/libraries/common.inc.php b/libraries/common.inc.php
index 8ccc7c0..1abe885 100644
--- a/libraries/common.inc.php
+++ b/libraries/common.inc.php
@@ -363,6 +363,7 @@ $goto_whitelist = array(
     'db_create.php',
     'db_datadict.php',
     'db_sql.php',
+    'db_events.php',
     'db_export.php',
     'db_importdocsql.php',
     'db_qbe.php',
diff --git a/libraries/common.lib.php b/libraries/common.lib.php
index 6d64cb6..7d9564e 100644
--- a/libraries/common.lib.php
+++ b/libraries/common.lib.php
@@ -2402,6 +2402,87 @@ function PMA_generate_slider_effect($id, $message)
 }
 
 /**
+ * Creates an AJAX sliding toggle button (or and equivalent form when AJAX is disabled)
+ *
+ * @param    string   $action        The URL for the request to be executed
+ * @param    string   $select_name   The name for the dropdown box
+ * @param    array    $options       An array of options (see rte_footer.lib.php)
+ * @param    string   $callback      A JS snippet to execute when the request is
+ *                                   successfully processed
+ *
+ * @return   string   HTML code for the toggle button
+ */
+function PMA_toggleButton($action, $select_name, $options, $callback)
+{
+    // Do the logic first
+    $link_on = "$action&$select_name=" . urlencode($options[1]['value']);
+    $link_off = "$action&$select_name=" . urlencode($options[0]['value']);
+    if ($options[1]['selected'] == true) {
+        $state = 'on';
+    } else if ($options[0]['selected'] == true) {
+        $state = 'off';
+    } else {
+        $state = 'on';
+    }
+    $selected1 = '';
+    $selected0 = '';
+    if ($options[1]['selected'] == true) {
+        $selected1 = " selected='selected'";
+    } else if ($options[0]['selected'] == true) {
+        $selected0 = " selected='selected'";
+    }
+    // Generate output
+    $retval  = "<!-- TOGGLE START -->\n";
+    if ($GLOBALS['cfg']['AjaxEnable']) {
+        $retval .= "<noscript>\n";
+    }
+    $retval .= "<div class='wrapper'>\n";
+    $retval .= "    <form action='$action' method='post'>\n";
+    $retval .= "        <select name='$select_name'>\n";
+    $retval .= "            <option value='{$options[1]['value']}'$selected1>";
+    $retval .= "                {$options[1]['label']}\n";
+    $retval .= "            </option>\n";
+    $retval .= "            <option value='{$options[0]['value']}'$selected0>";
+    $retval .= "                {$options[0]['label']}\n";
+    $retval .= "            </option>\n";
+    $retval .= "        </select>\n";
+    $retval .= "        <input type='submit' value='" . __('Change') . "'/>\n";
+    $retval .= "    </form>\n";
+    $retval .= "</div>\n";
+    if ($GLOBALS['cfg']['AjaxEnable']) {
+        $retval .= "</noscript>\n";
+        $retval .= "<div class='wrapper toggleAjax hide'>\n";
+        $retval .= "    <div class='toggleButton'>\n";
+        $retval .= "        <div title='" . __('Click to toggle') . "' class='container $state'>\n";
+        $retval .= "            <img src='{$GLOBALS['pmaThemeImage']}toggle-{$GLOBALS['text_dir']}.png'\n";
+        $retval .= "                 alt='' />\n";
+        $retval .= "            <table cellspacing='0' cellpadding='0'><tr>\n";
+        $retval .= "                <tbody>\n";
+        $retval .= "                <td class='toggleOn'>\n";
+        $retval .= "                    <span class='hide'>$link_on</span>\n";
+        $retval .= "                    <div>";
+        $retval .= str_replace(' ', ' ', $options[1]['label']) . "</div>\n";
+        $retval .= "                </td>\n";
+        $retval .= "                <td><div> </div></td>\n";
+        $retval .= "                <td class='toggleOff'>\n";
+        $retval .= "                    <span class='hide'>$link_off</span>\n";
+        $retval .= "                    <div>";
+        $retval .= str_replace(' ', ' ', $options[0]['label']) . "</div>\n";
+        $retval .= "                    </div>\n";
+        $retval .= "                </tbody>\n";
+        $retval .= "            </tr></table>\n";
+        $retval .= "            <span class='hide callback'>$callback</span>\n";
+        $retval .= "            <span class='hide text_direction'>{$GLOBALS['text_dir']}</span>\n";
+        $retval .= "        </div>\n";
+        $retval .= "    </div>\n";
+        $retval .= "</div>\n";
+    }
+    $retval .= "<!-- TOGGLE END -->";
+
+    return $retval;
+} // end PMA_toggleButton()
+
+/**
  * Clears cache content which needs to be refreshed on user change.
  */
 function PMA_clearUserCache() {
diff --git a/libraries/database_interface.lib.php b/libraries/database_interface.lib.php
index e6d4094..ef2783d 100644
--- a/libraries/database_interface.lib.php
+++ b/libraries/database_interface.lib.php
@@ -1300,7 +1300,7 @@ function PMA_DBI_get_triggers($db, $table = '', $delimiter = '//')
         // Note: in http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html
         // their example uses WHERE TRIGGER_SCHEMA='dbname' so let's use this
         // instead of WHERE EVENT_OBJECT_SCHEMA='dbname'
-        $query = "SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING, ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA= '" . PMA_sqlAddSlashes($db,true) . "';";
+        $query = "SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING, ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA= '" . PMA_sqlAddSlashes($db,true) . "';";
         if (! empty($table)) {
             $query .= " AND EVENT_OBJECT_TABLE = '" . PMA_sqlAddSlashes($table, true) . "';";
         }
@@ -1319,12 +1319,15 @@ function PMA_DBI_get_triggers($db, $table = '', $delimiter = '//')
                 $trigger['EVENT_MANIPULATION'] = $trigger['Event'];
                 $trigger['EVENT_OBJECT_TABLE'] = $trigger['Table'];
                 $trigger['ACTION_STATEMENT'] = $trigger['Statement'];
+                $trigger['DEFINER'] = $trigger['Definer'];
             }
             $one_result = array();
             $one_result['name'] = $trigger['TRIGGER_NAME'];
             $one_result['table'] = $trigger['EVENT_OBJECT_TABLE'];
             $one_result['action_timing'] = $trigger['ACTION_TIMING'];
             $one_result['event_manipulation'] = $trigger['EVENT_MANIPULATION'];
+            $one_result['definition'] = $trigger['ACTION_STATEMENT'];
+            $one_result['definer'] = $trigger['DEFINER'];
 
             // do not prepend the schema name; this way, importing the
             // definition into another schema will work
@@ -1335,6 +1338,14 @@ function PMA_DBI_get_triggers($db, $table = '', $delimiter = '//')
             $result[] = $one_result;
         }
     }
+
+    // Sort results by name
+    $name = array();
+    foreach($result as $key => $value) {
+        $name[] = $value['name'];
+    }
+    array_multisort($name, SORT_ASC, $result);
+
     return($result);
 }
 
diff --git a/libraries/db_events.inc.php b/libraries/db_events.inc.php
deleted file mode 100644
index adf265e..0000000
--- a/libraries/db_events.inc.php
+++ /dev/null
@@ -1,150 +0,0 @@
-<?php
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-/**
- *
- * @package phpMyAdmin
- */
-if (! defined('PHPMYADMIN')) {
-    exit;
-}
-
-$events = PMA_DBI_fetch_result('SELECT EVENT_NAME, EVENT_TYPE FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'' . PMA_sqlAddSlashes($db,true) . '\';');
-
-$conditional_class_add    = '';
-$conditional_class_drop   = '';
-$conditional_class_export = '';
-if ($GLOBALS['cfg']['AjaxEnable']) {
-    $conditional_class_add    = 'class="add_event_anchor"';
-    $conditional_class_drop   = 'class="drop_event_anchor"';
-    $conditional_class_export = 'class="export_event_anchor"';
-}
-
-/**
- * Display the export for a event. This is for when JS is disabled.
- */
-if (! empty($_GET['exportevent']) && ! empty($_GET['eventname'])) {
-    $event_name = htmlspecialchars(PMA_backquote($_GET['eventname']));
-    if ($create_event = PMA_DBI_get_definition($db, 'EVENT', $_GET['eventname'])) {
-        $create_event = '<textarea cols="40" rows="15" style="width: 100%;">' . $create_event . '</textarea>';
-        if (! empty($_REQUEST['ajax_request'])) {
-            $extra_data = array('title' => sprintf(__('Export of event %s'), $event_name));
-            PMA_ajaxResponse($create_event, true, $extra_data);
-        } else {
-            echo '<fieldset>' . "\n"
-               . ' <legend>' . sprintf(__('Export of event "%s"'), $event_name) . '</legend>' . "\n"
-               . $create_event
-               . '</fieldset>';
-        }
-    } else {
-        $response = __('Error in Processing Request') . ' : '
-                  . sprintf(__('No event with name %s found in database %s'),
-                            $event_name, htmlspecialchars(PMA_backquote($db)));
-        $response = PMA_message::error($response);
-        if (! empty($_REQUEST['ajax_request'])) {
-            PMA_ajaxResponse($response, false);
-        } else {
-            $response->display();
-        }
-    }
-}
-
-/**
- * Display a list of available events
- */
-echo "\n\n<span id='js_query_display'></span>\n\n";
-echo '<fieldset>' . "\n";
-echo ' <legend>' . __('Events') . '</legend>' . "\n";
-if (! $events) {
-    echo __('There are no events to display.');
-} else {
-    echo '<div class="hide" id="nothing2display">' . __('There are no events to display.') . '</div>';
-    echo '<table class="data">';
-    echo sprintf('<tr>
-                      <th>%s</th>
-                      <th colspan="3">%s</th>
-                      <th>%s</th>
-                </tr>',
-          __('Name'),
-          __('Action'),
-          __('Type'));
-    $ct=0;
-    $delimiter = '//';
-    foreach ($events as $event) {
-
-        // information_schema (at least in MySQL 5.1.22) does not return
-        // the full CREATE EVENT statement in a way that could be useful for us
-        // so we rely on PMA_DBI_get_definition() which uses SHOW CREATE EVENT
-
-        $create_event = PMA_DBI_get_definition($db, 'EVENT', $event['EVENT_NAME']);
-        $definition = 'DROP EVENT IF EXISTS ' . PMA_backquote($event['EVENT_NAME'])
-                    . $delimiter . "\n" . $create_event . "\n";
-
-        $sqlDrop = 'DROP EVENT ' . PMA_backquote($event['EVENT_NAME']);
-        echo sprintf('<tr class="%s">
-                          <td><span class="drop_sql" style="display:none;">%s</span><strong>%s</strong></td>
-                          <td>%s</td>
-                          <td><div class="create_sql" style="display: none;">%s</div>%s</td>
-                          <td>%s</td>
-                          <td>%s</td>
-                     </tr>',
-                     ($ct%2 == 0) ? 'even' : 'odd',
-                     $sqlDrop,
-                     $event['EVENT_NAME'],
-                     ! empty($definition) ? PMA_linkOrButton('db_sql.php?' . $url_query . '&sql_query=' . urlencode($definition) . '&show_query=1&db_query_force=1&delimiter=' . urlencode($delimiter), $titles['Edit']) : ' ',
-                     $create_event,
-                     '<a ' . $conditional_class_export . ' href="db_events.php?' . $url_query
-                           . '&exportevent=1'
-                           . '&eventname=' . urlencode($event['EVENT_NAME'])
-                           . '">' . $titles['Export'] . '</a>',
-                     '<a ' . $conditional_class_drop . ' href="sql.php?' . $url_query . '&sql_query=' . urlencode($sqlDrop) . '" >' . $titles['Drop'] . '</a>',
-                     $event['EVENT_TYPE']);
-        $ct++;
-    }
-    echo '</table>';
-}
-echo '</fieldset>' . "\n";
-
-/**
- * If there has been a request to change the state
- * of the event scheduler, process it now.
- */
-if (! empty($_GET['toggle_scheduler'])) {
-    $new_scheduler_state = $_GET['toggle_scheduler'];
-    if ($new_scheduler_state === 'ON' || $new_scheduler_state === 'OFF') {
-        PMA_DBI_query("SET GLOBAL event_scheduler='$new_scheduler_state'");
-    }
-}
-
-/**
- * Prepare to show the event scheduler fieldset, if necessary
- */
-$tableStart = '';
-$schedulerFieldset = '';
-$es_state = PMA_DBI_fetch_value("SHOW GLOBAL VARIABLES LIKE 'event_scheduler'", 0, 1);
-if ($es_state === 'ON' || $es_state === 'OFF') {
-    $es_change = ($es_state == 'ON') ? 'OFF' : 'ON';
-    $tableStart = '<table style="width: 100%;"><tr><td style="width: 50%;">';
-    $schedulerFieldset = '</td><td><fieldset style="margin: 1em 0;">' . "\n"
-       . PMA_getIcon('b_events.png')
-       . ($es_state === 'ON' ? __('The event scheduler is enabled') : __('The event scheduler is disabled')) . ':'
-       . '    <a href="db_events.php?' . $url_query . '&toggle_scheduler=' . $es_change . '">'
-       . ($es_change === 'ON' ? __('Turn it on') : __('Turn it off'))
-       .  '</a>' . "\n"
-       . '</fieldset></td></tr></table>' . "\n";
-}
-
-/**
- * Display the form for adding a new event
- */
-echo $tableStart . '<fieldset style="margin: 1em 0;">' . "\n"
-   . '    <a href="db_events.php?' . $url_query . '&addevent=1" ' . $conditional_class_add . '>' . "\n"
-   . PMA_getIcon('b_event_add.png') . __('Add an event') . '</a>' . "\n"
-   . '</fieldset>' . "\n";
-
-/**
- * Display the state of the event scheduler
- * and offer an option to toggle it.
- */
-echo $schedulerFieldset;
-
-?>
diff --git a/libraries/db_links.inc.php b/libraries/db_links.inc.php
index d1579e9..87fb98c 100644
--- a/libraries/db_links.inc.php
+++ b/libraries/db_links.inc.php
@@ -125,12 +125,14 @@ if (! $db_is_information_schema) {
         $tabs[] =& $tab_routines;
     }
     if (PMA_MYSQL_INT_VERSION >= 50106 && ! PMA_DRIZZLE) {
-        // Temporarily hiding this unfinished feature
-        // $tabs[] =& $tab_events;
+        if (PMA_currentUserHasPrivilege('EVENT', $db)) {
+            $tabs[] =& $tab_events;
+        }
     }
     if (PMA_MYSQL_INT_VERSION >= 50002 && ! PMA_DRIZZLE) {
-        // Temporarily hiding this unfinished feature
-        // $tabs[] =& $tab_triggers;
+        if (PMA_currentUserHasPrivilege('TRIGGER', $db)) {
+            $tabs[] =& $tab_triggers;
+        }
     }
 }
 if (PMA_Tracker::isActive()) {
diff --git a/libraries/db_routines.lib.php b/libraries/db_routines.lib.php
deleted file mode 100644
index 7591d39..0000000
--- a/libraries/db_routines.lib.php
+++ /dev/null
@@ -1,1204 +0,0 @@
-<?php
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-/**
- * @package phpMyAdmin
- */
-if (! defined('PHPMYADMIN')) {
-    exit;
-}
-
-/**
- * This function parses a string containing one parameter of a routine,
- * as returned by PMA_RTN_parseAllParameters() and returns an array containing
- * the information about this parameter.
- *
- * @param   string  $value    A string containing one parameter of a routine
- *
- * @return  array             Parsed information about the input parameter
- *
- */
-function PMA_RTN_parseOneParameter($value)
-{
-    global $param_directions;
-
-    $retval = array(0 => '',
-                    1 => '',
-                    2 => '',
-                    3 => '',
-                    4 => '');
-    $parsed_param = PMA_SQP_parse($value);
-    $pos = 0;
-    if (in_array(strtoupper($parsed_param[$pos]['data']), $param_directions)) {
-        $retval[0] = strtoupper($parsed_param[0]['data']);
-        $pos++;
-    }
-    if ($parsed_param[$pos]['type'] == 'alpha_identifier' || $parsed_param[$pos]['type'] == 'quote_backtick') {
-        $retval[1] = PMA_unQuote($parsed_param[$pos]['data']);
-        $pos++;
-    }
-    $depth = 0;
-    $param_length = '';
-    $param_opts = array();
-    for ($i=$pos; $i<$parsed_param['len']; $i++) {
-        if (($parsed_param[$i]['type'] == 'alpha_columnType'
-           || $parsed_param[$i]['type'] == 'alpha_functionName') // "CHAR" seems to be mistaken for a function by the parser
-           && $depth == 0) {
-            $retval[2] = strtoupper($parsed_param[$i]['data']);
-        } else if ($parsed_param[$i]['type'] == 'punct_bracket_open_round' && $depth == 0) {
-            $depth = 1;
-        } else if ($parsed_param[$i]['type'] == 'punct_bracket_close_round' && $depth == 1) {
-            $depth = 0;
-        } else if ($depth == 1) {
-            $param_length .= $parsed_param[$i]['data'];
-        } else if ($parsed_param[$i]['type'] == 'alpha_reservedWord' && strtoupper($parsed_param[$i]['data']) == 'CHARSET' && $depth == 0) {
-            if ($parsed_param[$i+1]['type'] == 'alpha_charset' || $parsed_param[$i+1]['type'] == 'alpha_identifier') {
-                $param_opts[] = strtolower($parsed_param[$i+1]['data']);
-            }
-        } else if ($parsed_param[$i]['type'] == 'alpha_columnAttrib' && $depth == 0) {
-            $param_opts[] = strtoupper($parsed_param[$i]['data']);
-        }
-    }
-    $retval[3] = $param_length;
-    sort($param_opts);
-    $retval[4] = implode(' ', $param_opts);
-
-    return $retval;
-} // end PMA_RTN_parseOneParameter()
-
-
-/**
- * This function looks through the contents of a parsed
- * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts
- * information about the routine's parameters.
- *
- * @param   array   $parsed_query  Parsed query, returned by by PMA_SQP_parse()
- * @param   string  $routine_type  Routine type: 'PROCEDURE' or 'FUNCTION'
- *
- * @return  array   Information about the parameteres of a routine.
- *
- */
-function PMA_RTN_parseAllParameters($parsed_query, $routine_type)
-{
-    global $param_directions;
-
-    $retval = array();
-    $retval['num'] = 0;
-
-    // First get the list of parameters from the query
-    $buffer = '';
-    $params = array();
-    $fetching = false;
-    $depth = 0;
-    for ($i=0; $i<$parsed_query['len']; $i++) {
-        if ($parsed_query[$i]['type'] == 'alpha_reservedWord' && $parsed_query[$i]['data'] == $routine_type) {
-            $fetching = true;
-        } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_bracket_open_round') {
-            $depth++;
-            if ($depth > 1) {
-                $buffer .= $parsed_query[$i]['data'] . ' ';
-            }
-        } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_bracket_close_round') {
-            $depth--;
-            if ($depth > 0) {
-                $buffer .= $parsed_query[$i]['data'] . ' ';
-            } else {
-                break;
-            }
-        } else if ($parsed_query[$i]['type'] == 'punct_listsep' && $depth == 1) {
-            $params[] = $buffer;
-            $retval['num']++;
-            $buffer = '';
-        } else if ($fetching == true && $depth > 0) {
-            $buffer .= $parsed_query[$i]['data'] . ' ';
-        }
-    }
-    if (! empty($buffer)) {
-        $params[] = $buffer;
-        $retval['num']++;
-    }
-    // Now parse each parameter individually
-    foreach ($params as $key => $value) {
-        list($retval['dir'][],
-             $retval['name'][],
-             $retval['type'][],
-             $retval['length'][],
-             $retval['opts'][]) = PMA_RTN_parseOneParameter($value);
-    }
-    // Since some indices of $retval may be still undefined, we fill
-    // them each with an empty array to avoid E_ALL errors in PHP.
-    foreach (array('dir', 'name', 'type', 'length', 'opts') as $key => $index) {
-        if (! isset($retval[$index])) {
-            $retval[$index] = array();
-        }
-    }
-
-    return $retval;
-} // end PMA_RTN_parseAllParameters()
-
-/**
- * This function looks through the contents of a parsed
- * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts
- * information about the routine's definer.
- *
- * @param   array   $parsed_query   Parsed query, returned by PMA_SQP_parse()
- *
- * @return  string  The definer of a routine.
- *
- */
-function PMA_RTN_parseRoutineDefiner($parsed_query)
-{
-    $retval = '';
-    $fetching = false;
-    for ($i=0; $i<$parsed_query['len']; $i++) {
-        if ($parsed_query[$i]['type'] == 'alpha_reservedWord' && $parsed_query[$i]['data'] == 'DEFINER') {
-            $fetching = true;
-        } else if ($fetching == true &&
-                  ($parsed_query[$i]['type'] != 'quote_backtick' && substr($parsed_query[$i]['type'], 0, 5) != 'punct')) {
-            break;
-        } else if ($fetching == true && $parsed_query[$i]['type'] == 'quote_backtick') {
-            $retval .= PMA_unQuote($parsed_query[$i]['data']);
-        } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_user') {
-            $retval .= $parsed_query[$i]['data'];
-        }
-    }
-    return $retval;
-} // end PMA_RTN_parseRoutineDefiner()
-
-/**
- * This function will generate the values that are required to complete
- * the "Edit routine" form given the name of a routine.
- *
- * @param   string   $db     The database that the routine belogs to.
- * @param   string   $name   The name of the routine.
- * @param   bool     $all    Whether to return all data or just
- *                           the info about parameters.
- *
- * @return  array    Data necessary to create the routine editor.
- *
- */
-function PMA_RTN_getRoutineDataFromName($db, $name, $all = true)
-{
-    global $param_directions, $param_sqldataaccess;
-
-    $retval  = array();
-
-    // Build and execute the query
-    $fields  = "SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, "
-             . "ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, "
-             . "ROUTINE_COMMENT, SECURITY_TYPE";
-    $where   = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' "
-             . "AND SPECIFIC_NAME='" . PMA_sqlAddSlashes($name) . "'";
-    $query   = "SELECT $fields FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;";
-
-    $routine = PMA_DBI_fetch_single_row($query);
-
-    if (! $routine) {
-        return false;
-    }
-
-    // Get required data
-    $retval['name'] = $routine['SPECIFIC_NAME'];
-    $retval['type'] = $routine['ROUTINE_TYPE'];
-    $parsed_query = PMA_SQP_parse(
-                        PMA_DBI_get_definition(
-                            $db,
-                            $routine['ROUTINE_TYPE'],
-                            $routine['SPECIFIC_NAME']
-                        )
-                    );
-    $params = PMA_RTN_parseAllParameters($parsed_query, $routine['ROUTINE_TYPE']);
-    $retval['num_params']      = $params['num'];
-    $retval['param_dir']       = $params['dir'];
-    $retval['param_name']      = $params['name'];
-    $retval['param_type']      = $params['type'];
-    $retval['param_length']    = $params['length'];
-    $retval['param_opts_num']  = $params['opts'];
-    $retval['param_opts_text'] = $params['opts'];
-
-    // Get extra data
-    if ($all) {
-        if ($retval['type'] == 'FUNCTION') {
-            $retval['type_toggle'] = 'PROCEDURE';
-        } else {
-            $retval['type_toggle'] = 'FUNCTION';
-        }
-        $retval['returntype']   = '';
-        $retval['returnlength'] = '';
-        $retval['returnopts_num']  = '';
-        $retval['returnopts_text'] = '';
-        if (! empty($routine['DTD_IDENTIFIER'])) {
-            if (strlen($routine['DTD_IDENTIFIER']) > 63) {
-                // If the DTD_IDENTIFIER string from INFORMATION_SCHEMA is
-                // at least 64 characters, then it may actually have been
-                // chopped because that column is a varchar(64), so we will
-                // parse the output of SHOW CREATE query to get accurate
-                // information about the return variable.
-                $dtd = '';
-                $fetching = false;
-                for ($i=0; $i<$parsed_query['len']; $i++) {
-                    if ($parsed_query[$i]['type'] == 'alpha_reservedWord'
-                    && strtoupper($parsed_query[$i]['data']) == 'RETURNS') {
-                        $fetching = true;
-                    } else if ($fetching == true
-                    && $parsed_query[$i]['type'] == 'alpha_reservedWord') {
-                        // We will not be looking for options such as UNSIGNED
-                        // or ZEROFILL because there is no way that a numeric
-                        // field's DTD_IDENTIFIER can be longer than 64
-                        // characters. We can safely assume that the return
-                        // datatype is either ENUM or SET, so we only look
-                        // for CHARSET.
-                        $word = strtoupper($parsed_query[$i]['data']);
-                        if ($word == 'CHARSET'
-                        && ($parsed_query[$i+1]['type'] == 'alpha_charset'
-                        || $parsed_query[$i+1]['type'] == 'alpha_identifier')) {
-                            $dtd .= $word . ' ' . $parsed_query[$i+1]['data'];
-                        }
-                        break;
-                    } else if ($fetching == true) {
-                        $dtd .= $parsed_query[$i]['data'] . ' ';
-                    }
-                }
-                $routine['DTD_IDENTIFIER'] = $dtd;
-            }
-            $returnparam = PMA_RTN_parseOneParameter($routine['DTD_IDENTIFIER']);
-            $retval['returntype']      = $returnparam[2];
-            $retval['returnlength']    = $returnparam[3];
-            $retval['returnopts_num']  = $returnparam[4];
-            $retval['returnopts_text'] = $returnparam[4];
-        }
-        $retval['definer']         = PMA_RTN_parseRoutineDefiner($parsed_query);
-        $retval['definition']      = $routine['ROUTINE_DEFINITION'];
-        $retval['isdeterministic'] = '';
-        if ($routine['IS_DETERMINISTIC'] == 'YES') {
-            $retval['isdeterministic'] = " checked='checked'";
-        }
-        $retval['securitytype_definer'] = '';
-        $retval['securitytype_invoker'] = '';
-        if ($routine['SECURITY_TYPE'] == 'DEFINER') {
-            $retval['securitytype_definer'] = " selected='selected'";
-        } else if ($routine['SECURITY_TYPE'] == 'INVOKER') {
-            $retval['securitytype_invoker'] = " selected='selected'";
-        }
-        $retval['sqldataaccess'] = $routine['SQL_DATA_ACCESS'];
-        $retval['comment']       = $routine['ROUTINE_COMMENT'];
-    }
-
-    return $retval;
-} // PMA_RTN_getRoutineDataFromName()
-
-/**
- * This function will generate the values that are required to complete the "Add new routine" form
- * It is especially necessary to handle the 'Add another parameter', 'Remove last parameter'
- * and 'Change routine type' functionalities when JS is disabled.
- *
- * @return  array    Data necessary to create the routine editor.
- *
- */
-function PMA_RTN_getRoutineDataFromRequest()
-{
-    global $_REQUEST, $param_directions, $param_sqldataaccess;
-
-    $retval = array();
-    $retval['name'] = '';
-    if (isset($_REQUEST['routine_name'])) {
-        $retval['name'] = $_REQUEST['routine_name'];
-    }
-    $retval['original_name'] = '';
-    if (isset($_REQUEST['routine_original_name'])) {
-         $retval['original_name'] = $_REQUEST['routine_original_name'];
-    }
-    $retval['type']         = 'PROCEDURE';
-    $retval['type_toggle']  = 'FUNCTION';
-    if (isset($_REQUEST['routine_type']) && $_REQUEST['routine_type'] == 'FUNCTION') {
-        $retval['type']         = 'FUNCTION';
-        $retval['type_toggle']  = 'PROCEDURE';
-    }
-    $retval['original_type'] = 'PROCEDURE';
-    if (isset($_REQUEST['routine_original_type']) && $_REQUEST['routine_original_type'] == 'FUNCTION') {
-        $retval['original_type'] = 'FUNCTION';
-    }
-    $retval['num_params']      = 0;
-    $retval['param_dir']       = array();
-    $retval['param_name']      = array();
-    $retval['param_type']      = array();
-    $retval['param_length']    = array();
-    $retval['param_opts_num']  = array();
-    $retval['param_opts_text'] = array();
-    if (isset($_REQUEST['routine_param_name'])
-        && isset($_REQUEST['routine_param_type'])
-        && isset($_REQUEST['routine_param_length'])
-        && isset($_REQUEST['routine_param_opts_num'])
-        && isset($_REQUEST['routine_param_opts_text'])
-        && is_array($_REQUEST['routine_param_name'])
-        && is_array($_REQUEST['routine_param_type'])
-        && is_array($_REQUEST['routine_param_length'])
-        && is_array($_REQUEST['routine_param_opts_num'])
-        && is_array($_REQUEST['routine_param_opts_text'])) {
-
-        if ($_REQUEST['routine_type'] == 'PROCEDURE') {
-            $temp_num_params = 0;
-            $retval['param_dir'] = $_REQUEST['routine_param_dir'];
-            foreach ($retval['param_dir'] as $key => $value) {
-                if (! in_array($value, $param_directions, true)) {
-                    $retval['param_dir'][$key] = '';
-                }
-                $retval['num_params']++;
-            }
-            if ($temp_num_params > $retval['num_params']) {
-                $retval['num_params'] = $temp_num_params;
-            }
-        }
-        $temp_num_params = 0;
-        $retval['param_name'] = $_REQUEST['routine_param_name'];
-        foreach ($retval['param_name'] as $key => $value) {
-            $retval['param_name'][$key] = $value;
-            $temp_num_params++;
-        }
-        if ($temp_num_params > $retval['num_params']) {
-            $retval['num_params'] = $temp_num_params;
-        }
-        $temp_num_params = 0;
-        $retval['param_type'] = $_REQUEST['routine_param_type'];
-        foreach ($retval['param_type'] as $key => $value) {
-            if (! in_array($value, PMA_getSupportedDatatypes(), true)) {
-                $retval['param_type'][$key] = '';
-            }
-            $temp_num_params++;
-        }
-        if ($temp_num_params > $retval['num_params']) {
-            $retval['num_params'] = $temp_num_params;
-        }
-        $temp_num_params = 0;
-        $retval['param_length'] = $_REQUEST['routine_param_length'];
-        foreach ($retval['param_length'] as $key => $value) {
-            $retval['param_length'][$key] = $value;
-            $temp_num_params++;
-        }
-        if ($temp_num_params > $retval['num_params']) {
-            $retval['num_params'] = $temp_num_params;
-        }
-        $temp_num_params = 0;
-        $retval['param_opts_num'] = $_REQUEST['routine_param_opts_num'];
-        foreach ($retval['param_opts_num'] as $key => $value) {
-            $retval['param_opts_num'][$key] = $value;
-            $temp_num_params++;
-        }
-        if ($temp_num_params > $retval['num_params']) {
-            $retval['num_params'] = $temp_num_params;
-        }
-        $temp_num_params = 0;
-        $retval['param_opts_text'] = $_REQUEST['routine_param_opts_text'];
-        foreach ($retval['param_opts_text'] as $key => $value) {
-            $retval['param_opts_text'][$key] = $value;
-            $temp_num_params++;
-        }
-        if ($temp_num_params > $retval['num_params']) {
-            $retval['num_params'] = $temp_num_params;
-        }
-    }
-    $retval['returntype'] = '';
-    if (isset($_REQUEST['routine_returntype']) && in_array($_REQUEST['routine_returntype'], PMA_getSupportedDatatypes(), true)) {
-        $retval['returntype'] = $_REQUEST['routine_returntype'];
-    }
-    $retval['returnlength'] = '';
-    if (isset($_REQUEST['routine_returnlength'])) {
-        $retval['returnlength'] = $_REQUEST['routine_returnlength'];
-    }
-    $retval['returnopts_num'] = '';
-    if (isset($_REQUEST['routine_returnopts_num'])) {
-        $retval['returnopts_num'] = $_REQUEST['routine_returnopts_num'];
-    }
-    $retval['returnopts_text'] = '';
-    if (isset($_REQUEST['routine_returnopts_text'])) {
-        $retval['returnopts_text'] = $_REQUEST['routine_returnopts_text'];
-    }
-    $retval['definition'] = '';
-    if (isset($_REQUEST['routine_definition'])) {
-        $retval['definition'] = $_REQUEST['routine_definition'];
-    }
-    $retval['isdeterministic'] = '';
-    if (isset($_REQUEST['routine_isdeterministic']) && strtolower($_REQUEST['routine_isdeterministic']) == 'on') {
-        $retval['isdeterministic'] = " checked='checked'";
-    }
-    $retval['definer'] = '';
-    if (isset($_REQUEST['routine_definer'])) {
-        $retval['definer'] = $_REQUEST['routine_definer'];
-    }
-    $retval['securitytype_definer'] = '';
-    $retval['securitytype_invoker'] = '';
-    if (isset($_REQUEST['routine_securitytype'])) {
-        if ($_REQUEST['routine_securitytype'] === 'DEFINER') {
-            $retval['securitytype_definer'] = " selected='selected'";
-        } else if ($_REQUEST['routine_securitytype'] === 'INVOKER') {
-            $retval['securitytype_invoker'] = " selected='selected'";
-        }
-    }
-    $retval['sqldataaccess'] = '';
-    if (isset($_REQUEST['routine_sqldataaccess']) && in_array($_REQUEST['routine_sqldataaccess'], $param_sqldataaccess, true)) {
-        $retval['sqldataaccess'] = $_REQUEST['routine_sqldataaccess'];
-    }
-    $retval['comment'] = '';
-    if (isset($_REQUEST['routine_comment'])) {
-        $retval['comment'] = $_REQUEST['routine_comment'];
-    }
-
-    return $retval;
-} // end function PMA_RTN_getRoutineDataFromRequest()
-
-/**
- * Creates one row for the parameter table used in the routine editor.
- *
- * @param   array    $routine    Data for the routine returned by
- *                               PMA_RTN_getRoutineDataFromRequest() or
- *                               PMA_RTN_getRoutineDataFromName()
- * @param   mixed    $index      Either a numeric index of the row being processed
- *                               or NULL to create a template row for AJAX request
- * @param   string   $class      Class used to hide the direction column, if the
- *                               row is for a stored function.
- *
- * @return    string    HTML code of one row of parameter table for the routine editor.
- *
- */
-function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '')
-{
-    global $param_directions, $param_opts_num, $titles;
-
-    if ($index === null) {
-        // template row for AJAX request
-        $i = 0;
-        $index = '%s';
-        $drop_class = '';
-        $routine = array(
-                       'param_dir'       => array(0 => ''),
-                       'param_name'      => array(0 => ''),
-                       'param_type'      => array(0 => ''),
-                       'param_length'    => array(0 => ''),
-                       'param_opts_num'  => array(0 => ''),
-                       'param_opts_text' => array(0 => '')
-                   );
-    } else if (! empty($routine)) {
-        // regular row for routine editor
-        $drop_class = ' hide';
-        $i = $index;
-    } else {
-        // No input data. This shouldn't happen,
-        // but better be safe than sorry.
-        return '';
-    }
-
-    // Create the output
-    $retval  = "";
-    $retval .= "        <tr>\n";
-    $retval .= "            <td class='routine_direction_cell$class'><select name='routine_param_dir[$index]'>\n";
-    foreach ($param_directions as $key => $value) {
-        $selected = "";
-        if (! empty($routine['param_dir'][$i]) && $routine['param_dir'][$i] == $value) {
-            $selected = " selected='selected'";
-        }
-        $retval .= "                <option$selected>$value</option>\n";
-    }
-    $retval .= "            </select></td>\n";
-    $retval .= "            <td><input name='routine_param_name[$index]' type='text'\n";
-    $retval .= "                       value='{$routine['param_name'][$i]}' /></td>\n";
-    $retval .= "            <td><select name='routine_param_type[$index]'>";
-    $retval .= PMA_getSupportedDatatypes(true, $routine['param_type'][$i]) . "\n";
-    $retval .= "            </select></td>\n";
-    $retval .= "            <td><input name='routine_param_length[$index]' type='text'\n";
-    $retval .= "                       value='{$routine['param_length'][$i]}' /></td>\n";
-    $retval .= "            <td class='routine_param_opts_text'>\n";
-    $retval .= PMA_generateCharsetDropdownBox(PMA_CSDROPDOWN_CHARSET,
-                                              "routine_param_opts_text[$index]",
-                                              null,
-                                              $routine['param_opts_text'][$i]);
-    $retval .= "            </td>\n";
-    $retval .= "            <td class='routine_param_opts_num'><select name='routine_param_opts_num[$index]'>\n";
-    $retval .= "                <option value=''></option>";
-    foreach ($param_opts_num as $key => $value) {
-        $selected = "";
-        if (! empty($routine['param_opts_num'][$i]) && $routine['param_opts_num'][$i] == $value) {
-            $selected = " selected='selected'";
-        }
-        $retval .= "<option$selected>$value</option>";
-    }
-    $retval .= "\n            </select></td>\n";
-    $retval .= "            <td class='routine_param_remove$drop_class' style='vertical-align: middle;'>\n";
-    $retval .= "                <a href='#' class='routine_param_remove_anchor'>\n";
-    $retval .= "                    {$titles['Drop']}\n";
-    $retval .= "                </a>\n";
-    $retval .= "            </td>\n";
-    $retval .= "        </tr>\n";
-
-    return $retval;
-} // end PMA_RTN_getParameterRow()
-
-/**
- * Displays a form used to add/edit a routine
- *
- * @param   string   $mode         If the editor will be used edit a routine
- *                                 or add a new one: 'edit' or 'add'.
- * @param   string   $operation    If the editor was previously invoked with
- *                                 JS turned off, this will hold the name of
- *                                 the current operation: 'add', remove', 'change'
- * @param   array    $routine      Data for the routine returned by
- *                                 PMA_RTN_getRoutineDataFromRequest() or
- *                                 PMA_RTN_getRoutineDataFromName()
- * @param   array    $errors       If the editor was already invoked and there
- *                                 has been an error while processing the request
- *                                 this array will hold the errors.
- * @param   bool     $is_ajax      True, if called from an ajax request
- *
- * @return  string   HTML code for the routine editor.
- *
- */
-function PMA_RTN_getEditorForm($mode, $operation, $routine, $errors, $is_ajax) {
-    global $db, $titles, $param_directions, $param_sqldataaccess, $param_opts_num;
-
-    // Escape special characters
-    $need_escape = array(
-                       'original_name',
-                       'name',
-                       'returnlength',
-                       'definition',
-                       'definer',
-                       'comment'
-                   );
-    foreach($need_escape as $key => $index) {
-        $routine[$index] = htmlentities($routine[$index], ENT_QUOTES);
-    }
-    for ($i=0; $i<$routine['num_params']; $i++) {
-        $routine['param_name'][$i]   = htmlentities($routine['param_name'][$i], ENT_QUOTES);
-        $routine['param_length'][$i] = htmlentities($routine['param_length'][$i], ENT_QUOTES);
-    }
-
-    // Handle some logic first
-    if ($operation == 'change') {
-        if ($routine['type'] == 'PROCEDURE') {
-            $routine['type']        = 'FUNCTION';
-            $routine['type_toggle'] = 'PROCEDURE';
-        } else {
-            $routine['type']        = 'PROCEDURE';
-            $routine['type_toggle'] = 'FUNCTION';
-        }
-    } else if ($operation == 'add' || ($routine['num_params'] == 0 && $mode == 'add' && ! $errors)) {
-        $routine['param_dir'][]       = '';
-        $routine['param_name'][]      = '';
-        $routine['param_type'][]      = '';
-        $routine['param_length'][]    = '';
-        $routine['param_opts_num'][]  = '';
-        $routine['param_opts_text'][] = '';
-        $routine['num_params']++;
-    } else if ($operation == 'remove') {
-        unset($routine['param_dir'][$routine['num_params']-1]);
-        unset($routine['param_name'][$routine['num_params']-1]);
-        unset($routine['param_type'][$routine['num_params']-1]);
-        unset($routine['param_length'][$routine['num_params']-1]);
-        unset($routine['param_opts_num'][$routine['num_params']-1]);
-        unset($routine['param_opts_text'][$routine['num_params']-1]);
-        $routine['num_params']--;
-    }
-    $disable_remove_parameter = '';
-    if (! $routine['num_params']) {
-        $disable_remove_parameter = " color: gray;' disabled='disabled";
-    }
-    $original_routine = '';
-    if ($mode == 'edit') {
-        $original_routine = "<input name='routine_original_name' "
-                          . "type='hidden' value='{$routine['original_name']}'/>\n"
-                          . "<input name='routine_original_type' "
-                          . "type='hidden' value='{$routine['original_type']}'/>\n";
-    }
-    $isfunction_class   = '';
-    $isprocedure_class  = '';
-    $isfunction_select  = '';
-    $isprocedure_select = '';
-    if ($routine['type'] == 'PROCEDURE') {
-        $isfunction_class   = ' hide';
-        $isprocedure_select = " selected='selected'";
-    } else {
-        $isprocedure_class = ' hide';
-        $isfunction_select = " selected='selected'";
-    }
-
-    // Create the output
-    $retval  = "";
-    $retval .= "<!-- START " . strtoupper($mode) . " ROUTINE FORM -->\n\n";
-    $retval .= "<form class='rte_form' action='db_routines.php' method='post'>\n";
-    $retval .= "<input name='{$mode}routine' type='hidden' value='1' />\n";
-    $retval .= $original_routine;
-    $retval .= PMA_generate_common_hidden_inputs($db) . "\n";
-    $retval .= "<fieldset>\n";
-    $retval .= "<legend>" . __('Details') . "</legend>\n";
-    $retval .= "<table class='rte_table' style='width: 100%'>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Routine name') . "</td>\n";
-    $retval .= "    <td><input type='text' name='routine_name' value='{$routine['name']}' /></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Type') . "</td>\n";
-    $retval .= "    <td>\n";
-    if ($is_ajax) {
-        $retval .= "        <select name='routine_type'>\n";
-        $retval .= "            <option value='PROCEDURE'$isprocedure_select>PROCEDURE</option>\n";
-        $retval .= "            <option value='FUNCTION'$isfunction_select>FUNCTION</option>\n";
-        $retval .= "        </select>\n";
-    } else {
-        $retval .= "        <input name='routine_type' type='hidden' value='{$routine['type']}' />\n";
-        $retval .= "        <div style='width: 49%; float: left; text-align: center; font-weight: bold;'>\n";
-        $retval .= "            {$routine['type']}\n";
-        $retval .= "        </div>\n";
-        $retval .= "        <input style='width: 49%;' type='submit' name='routine_changetype'\n";
-        $retval .= "               value='".sprintf(__('Change to %s'), $routine['type_toggle'])."' />\n";
-    }
-    $retval .= "    </td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Parameters') . "</td>\n";
-    $retval .= "    <td>\n";
-    // parameter handling start
-    $retval .= "        <table class='routine_params_table' style='width: 100%;'>\n";
-    $retval .= "        <tr>\n";
-    $retval .= "            <th class='routine_direction_cell$isprocedure_class'>" . __('Direction') . "</th>\n";
-    $retval .= "            <th>" . __('Name') . "</th>\n";
-    $retval .= "            <th>" . __('Type') . "</th>\n";
-    $retval .= "            <th>" . __('Length/Values') . "</th>\n";
-    $retval .= "            <th colspan='2'>" . __('Options') . "</th>\n";
-    $retval .= "            <th class='routine_param_remove hide'> </th>\n";
-    $retval .= "        </tr>";
-    for ($i=0; $i<$routine['num_params']; $i++) { // each parameter
-        $retval .= PMA_RTN_getParameterRow($routine, $i, $isprocedure_class);
-    }
-    $retval .= "        </table>\n";
-    $retval .= "    </td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td> </td>\n";
-    $retval .= "    <td>\n";
-    $retval .= "        <input style='width: 49%;' type='submit' \n";
-    $retval .= "               name='routine_addparameter'\n";
-    $retval .= "               value='" . __('Add parameter') . "' />\n";
-    $retval .= "        <input style='width: 49%;$disable_remove_parameter' type='submit' \n";
-    $retval .= "               name='routine_removeparameter'\n";
-    $retval .= "               value='" . __('Remove last parameter') . "' />\n";
-    $retval .= "    </td>\n";
-    $retval .= "</tr>\n";
-    // parameter handling end
-    $retval .= "<tr class='routine_return_row$isfunction_class'>\n";
-    $retval .= "    <td>" . __('Return type') . "</td>\n";
-    $retval .= "    <td><select name='routine_returntype'>\n";
-    $retval .= PMA_getSupportedDatatypes(true, $routine['returntype']) . "\n";
-    $retval .= "    </select></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr class='routine_return_row$isfunction_class'>\n";
-    $retval .= "    <td>" . __('Return length/values') . "</td>\n";
-    $retval .= "    <td><input type='text' name='routine_returnlength'\n";
-    $retval .= "               value='{$routine['returnlength']}' /></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr class='routine_return_row$isfunction_class'>\n";
-    $retval .= "    <td>" . __('Return options') . "</td>\n";
-    $retval .= "    <td><div>\n";
-    $retval .= PMA_generateCharsetDropdownBox(PMA_CSDROPDOWN_CHARSET,
-                                              "routine_returnopts_text",
-                                              null,
-                                              $routine['returnopts_text']) . "\n";
-    $retval .= "    </div>\n";
-    $retval .= "    <div><select name='routine_returnopts_num'>\n";
-    $retval .= "        <option value=''></option>";
-    foreach ($param_opts_num as $key => $value) {
-        $selected = "";
-        if (! empty($routine['returnopts_num']) && $routine['returnopts_num'] == $value) {
-            $selected = " selected='selected'";
-        }
-        $retval .= "<option$selected>$value</option>";
-    }
-    $retval .= "\n    </select></div></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Definition') . "</td>\n";
-    $retval .= "    <td><textarea name='routine_definition' rows='15' cols='40'>{$routine['definition']}</textarea></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Is deterministic') . "</td>\n";
-    $retval .= "    <td><input type='checkbox' name='routine_isdeterministic'{$routine['isdeterministic']} /></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Definer') . "</td>\n";
-    $retval .= "    <td><input type='text' name='routine_definer'\n";
-    $retval .= "               value='{$routine['definer']}' /></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Security type') . "</td>\n";
-    $retval .= "    <td><select name='routine_securitytype'>\n";
-    $retval .= "        <option value='DEFINER'{$routine['securitytype_definer']}>DEFINER</option>\n";
-    $retval .= "        <option value='INVOKER'{$routine['securitytype_invoker']}>INVOKER</option>\n";
-    $retval .= "    </select></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('SQL data access') . "</td>\n";
-    $retval .= "    <td><select name='routine_sqldataaccess'>\n";
-    foreach ($param_sqldataaccess as $key => $value) {
-        $selected = "";
-        if ($routine['sqldataaccess'] == $value) {
-            $selected = " selected='selected'";
-        }
-        $retval .= "        <option$selected>$value</option>\n";
-    }
-    $retval .= "    </select></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "<tr>\n";
-    $retval .= "    <td>" . __('Comment') . "</td>\n";
-    $retval .= "    <td><input type='text' name='routine_comment'\n";
-    $retval .= "               value='{$routine['comment']}' /></td>\n";
-    $retval .= "</tr>\n";
-    $retval .= "</table>\n";
-    $retval .= "</fieldset>\n";
-    if ($is_ajax) {
-        $retval .= "<input type='hidden' name='routine_process_{$mode}routine' value='true' />\n";
-        $retval .= "<input type='hidden' name='ajax_request' value='true' />\n";
-    } else {
-        $retval .= "<fieldset class='tblFooters routineEditorSubmit'>\n";
-        $retval .= "    <input type='submit' name='routine_process_{$mode}routine'\n";
-        $retval .= "           value='" . __('Go') . "' />\n";
-        $retval .= "</fieldset>\n";
-    }
-    $retval .= "</form>\n\n";
-    $retval .= "<!-- END " . strtoupper($mode) . " ROUTINE FORM -->\n\n";
-
-    return $retval;
-} // end PMA_RTN_getEditorForm()
-
-/**
- * Creates the HTML code that shows the routine execution dialog.
- *
- * @param   array    $routine      Data for the routine returned by
- *                                 PMA_RTN_getRoutineDataFromName()
- * @param   bool     $is_ajax      True, if called from an ajax request
- *
- * @return  string   HTML code for the routine execution dialog.
- *
- */
-function PMA_RTN_getExecuteForm($routine, $is_ajax)
-{
-    global $db, $cfg;
-
-    // Escape special characters
-    $routine['name'] = htmlentities($routine['name'], ENT_QUOTES);
-    for ($i=0; $i<$routine['num_params']; $i++) {
-        $routine['param_name'][$i] = htmlentities($routine['param_name'][$i], ENT_QUOTES);
-    }
-
-    // Create the output
-    $retval  = "";
-    $retval .= "<!-- START ROUTINE EXECUTE FORM -->\n\n";
-    $retval .= "<form action='db_routines.php' method='post' class='rte_form'>\n";
-    $retval .= "<input type='hidden' name='routine_name' value='{$routine['name']}' />\n";
-    $retval .= PMA_generate_common_hidden_inputs($db) . "\n";
-    $retval .= "<fieldset>\n";
-    if ($is_ajax != true) {
-        $retval .= "<legend>{$routine['name']}</legend>\n";
-        $retval .= "<table class='rte_table'>\n";
-        $retval .= "<caption class='tblHeaders'>\n";
-        $retval .= __('Routine parameters');
-        $retval .= "</caption>\n";
-    } else {
-        $retval .= "<legend>" . __('Routine parameters') . "</legend>\n";
-        $retval .= "<table class='rte_table' style='width: 100%;'>\n";
-    }
-    $retval .= "<tr>\n";
-    $retval .= "<th>" . __('Name') . "</th>\n";
-    $retval .= "<th>" . __('Type') . "</th>\n";
-    if ($cfg['ShowFunctionFields']) {
-        $retval .= "<th>" . __('Function') . "</th>\n";
-    }
-    $retval .= "<th>" . __('Value')    . "</th>\n";
-    $retval .= "</tr>\n";
-    for ($i=0; $i<$routine['num_params']; $i++) { // Each parameter
-        if ($routine['type'] == 'PROCEDURE' && $routine['param_dir'][$i] == 'OUT') {
-            continue;
-        }
-        $rowclass = ($i % 2 == 0) ? 'even' : 'odd';
-        $retval .= "\n<tr class='$rowclass'>\n";
-        $retval .= "<td><strong>{$routine['param_name'][$i]}</strong></td>\n";
-        $retval .= "<td>{$routine['param_type'][$i]}</td>\n";
-        if ($cfg['ShowFunctionFields']) {
-            $retval .= "<td>\n";
-            // Get a list of data types that are not yet supported.
-            $no_support_types = PMA_unsupportedDatatypes();
-            if (stristr($routine['param_type'][$i], 'enum')
-                || stristr($routine['param_type'][$i], 'set')
-                || in_array(strtolower($routine['param_type'][$i]), $no_support_types)) {
-                $retval .= "--\n";
-            } else {
-                $field = array(
-                             'True_Type'       => strtolower($routine['param_type'][$i]),
-                             'Type'            => '',
-                             'Key'             => '',
-                             'Field'           => '',
-                             'Default'         => '',
-                             'first_timestamp' => false
-                         );
-                $retval .= "<select name='funcs[{$routine['param_name'][$i]}]'>";
-                $retval .= PMA_getFunctionsForField($field, false);
-                $retval .= "</select>";
-            }
-            $retval .= "</td>\n";
-        }
-        // Append a class to date/time fields so that
-        // jQuery can attach a datepicker to them
-        $class = '';
-        if (in_array($routine['param_type'][$i], array('DATETIME', 'TIMESTAMP'))) {
-            $class = 'datetimefield';
-        } else if ($routine['param_type'][$i] == 'DATE') {
-            $class = 'datefield';
-        }
-        $retval .= "<td style='white-space: nowrap;'>\n";
-        if (in_array($routine['param_type'][$i], array('ENUM', 'SET'))) {
-            $tokens = PMA_SQP_parse($routine['param_length'][$i]);
-            if ($routine['param_type'][$i] == 'ENUM') {
-                $input_type = 'radio';
-            } else {
-                $input_type = 'checkbox';
-            }
-            for ($j=0; $j<$tokens['len']; $j++) {
-                if ($tokens[$j]['type'] != 'punct_listsep') {
-                    $tokens[$j]['data'] = htmlentities(PMA_unquote($tokens[$j]['data']), ENT_QUOTES);
-                    $retval .= "<input name='params[{$routine['param_name'][$i]}][]' "
-                             . "value='{$tokens[$j]['data']}' type='$input_type' />"
-                             . "{$tokens[$j]['data']}<br />\n";
-                }
-            }
-        } else if (in_array(strtolower($routine['param_type'][$i]), $no_support_types)) {
-            $retval .= "\n";
-        } else {
-            $retval .= "<input class='$class' type='text' name='params[{$routine['param_name'][$i]}]' />\n";
-        }
-        $retval .= "</td>\n";
-        $retval .= "</tr>\n";
-    }
-    $retval .= "\n</table>\n";
-    if ($is_ajax != true) {
-        $retval .= "</fieldset>\n\n";
-        $retval .= "<fieldset class='tblFooters'>\n";
-        $retval .= "    <input type='submit' name='execute_routine'\n";
-        $retval .= "           value='" . __('Go') . "' />\n";
-        $retval .= "</fieldset>\n";
-    } else {
-        $retval .= "<input type='hidden' name='execute_routine' value='true' />";
-        $retval .= "<input type='hidden' name='ajax_request' value='true' />";
-    }
-    $retval .= "</form>\n\n";
-    $retval .= "<!-- END ROUTINE EXECUTE FORM -->\n\n";
-
-    return $retval;
-} // end PMA_RTN_getExecuteForm()
-
-/**
- * Composes the query necessary to create a routine from an HTTP request.
- *
- * @return  string    The CREATE [ROUTINE | PROCEDURE] query.
- *
- */
-function PMA_RTN_getQueryFromRequest() {
-    global $_REQUEST, $cfg, $routine_errors, $param_sqldataaccess;
-
-    $query = 'CREATE ';
-    if (! empty($_REQUEST['routine_definer']) && strpos($_REQUEST['routine_definer'], '@') !== false) {
-        $arr = explode('@', $_REQUEST['routine_definer']);
-        $query .= 'DEFINER=' . PMA_backquote($arr[0]) . '@' . PMA_backquote($arr[1]) . ' ';
-    }
-    if ($_REQUEST['routine_type'] == 'FUNCTION' || $_REQUEST['routine_type'] == 'PROCEDURE') {
-        $query .= $_REQUEST['routine_type'] . ' ';
-    } else {
-        $routine_errors[] = sprintf(__('Invalid routine type: "%s"'), htmlspecialchars($_REQUEST['routine_type']));
-    }
-    if (! empty($_REQUEST['routine_name'])) {
-        $query .= PMA_backquote($_REQUEST['routine_name']) . ' ';
-    } else {
-        $routine_errors[] = __('You must provide a routine name');
-    }
-    $params = '';
-    $warned_about_dir    = false;
-    $warned_about_name   = false;
-    $warned_about_length = false;
-    if ( ! empty($_REQUEST['routine_param_name']) && ! empty($_REQUEST['routine_param_type'])
-        && ! empty($_REQUEST['routine_param_length']) && is_array($_REQUEST['routine_param_name'])
-        && is_array($_REQUEST['routine_param_type']) && is_array($_REQUEST['routine_param_length'])) {
-
-        for ($i=0; $i<count($_REQUEST['routine_param_name']); $i++) {
-            if (! empty($_REQUEST['routine_param_name'][$i]) && ! empty($_REQUEST['routine_param_type'][$i])) {
-                if ($_REQUEST['routine_type'] == 'PROCEDURE' && ! empty($_REQUEST['routine_param_dir'][$i])) {
-                    $params .= $_REQUEST['routine_param_dir'][$i] . " " . PMA_backquote($_REQUEST['routine_param_name'][$i]) . " "
-                            . $_REQUEST['routine_param_type'][$i];
-                } else if ($_REQUEST['routine_type'] == 'FUNCTION') {
-                    $params .= PMA_backquote($_REQUEST['routine_param_name'][$i]) . " " . $_REQUEST['routine_param_type'][$i];
-                } else if (! $warned_about_dir) {
-                    $warned_about_dir = true;
-                    $routine_errors[] = sprintf(__('Invalid direction "%s" given for parameter.'),
-                                                htmlspecialchars($_REQUEST['routine_param_dir'][$i]));
-                }
-                if ($_REQUEST['routine_param_length'][$i] != ''
-                    && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT)$@i',
-                                   $_REQUEST['routine_param_type'][$i])) {
-                    $params .= "(" . $_REQUEST['routine_param_length'][$i] . ")";
-                } else if ($_REQUEST['routine_param_length'][$i] == ''
-                           && preg_match('@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $_REQUEST['routine_param_type'][$i])) {
-                    if (! $warned_about_length) {
-                        $warned_about_length = true;
-                        $routine_errors[] = __('You must provide length/values for routine '
-                                             . 'parameters of type ENUM, SET, VARCHAR and VARBINARY.');
-                    }
-                }
-                if (! empty($_REQUEST['routine_param_opts_text'][$i])) {
-                    if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_param_type'][$i])])) {
-                        $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_param_type'][$i])];
-                        if ($group == 'FUNC_CHAR') {
-                            $params .= ' CHARSET ' . strtolower($_REQUEST['routine_param_opts_text'][$i]);
-                        }
-                    }
-                }
-                if (! empty($_REQUEST['routine_param_opts_num'][$i])) {
-                    if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_param_type'][$i])])) {
-                        $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_param_type'][$i])];
-                        if ($group == 'FUNC_NUMBER') {
-                            $params .= ' ' . strtoupper($_REQUEST['routine_param_opts_num'][$i]);
-                        }
-                    }
-                }
-                if ($i != count($_REQUEST['routine_param_name'])-1) {
-                    $params .= ", ";
-                }
-            } else if (! $warned_about_name) {
-                $warned_about_name = true;
-                $routine_errors[] = __('You must provide a name and a type for each routine parameter.');
-                break;
-            }
-        }
-    }
-    $query .= " (" . $params . ") ";
-    if ($_REQUEST['routine_type'] == 'FUNCTION') {
-        $query .= "RETURNS {$_REQUEST['routine_returntype']}";
-        if (! empty($_REQUEST['routine_returnlength'])
-            && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT)$@i',
-                            $_REQUEST['routine_returntype'])) {
-            $query .= "(" . $_REQUEST['routine_returnlength'] . ")";
-        } else if (empty($_REQUEST['routine_returnlength'])
-            && preg_match('@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $_REQUEST['routine_returntype'])) {
-            if (! $warned_about_length) {
-                $warned_about_length = true;
-                $routine_errors[] = __('You must provide length/values for routine '
-                                     . 'parameters of type ENUM, SET, VARCHAR and VARBINARY.');
-            }
-        }
-        if (! empty($_REQUEST['routine_returnopts_text'])) {
-            if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_returntype'])])) {
-                $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_returntype'])];
-                if ($group == 'FUNC_CHAR') {
-                    $query .= ' CHARSET ' . strtolower($_REQUEST['routine_returnopts_text']);
-                }
-            }
-        }
-        if (! empty($_REQUEST['routine_returnopts_num'])) {
-            if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_returntype'])])) {
-                $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['routine_returntype'])];
-                if ($group == 'FUNC_NUMBER') {
-                    $query .= ' ' . strtoupper($_REQUEST['routine_returnopts_num']);
-                }
-            }
-        }
-        $query .= ' ';
-    }
-    if (! empty($_REQUEST['routine_comment'])) {
-        $query .= "COMMENT '{$_REQUEST['routine_comment']}' ";
-    }
-    if (isset($_REQUEST['routine_isdeterministic'])) {
-        $query .= 'DETERMINISTIC ';
-    } else {
-        $query .= 'NOT DETERMINISTIC ';
-    }
-    if (! empty($_REQUEST['routine_sqldataaccess']) && in_array($_REQUEST['routine_sqldataaccess'], $param_sqldataaccess, true)) {
-        $query .= $_REQUEST['routine_sqldataaccess'] . ' ';
-    }
-    if (! empty($_REQUEST['routine_securitytype'])) {
-        if ($_REQUEST['routine_securitytype'] == 'DEFINER' || $_REQUEST['routine_securitytype'] == 'INVOKER') {
-            $query .= 'SQL SECURITY ' . $_REQUEST['routine_securitytype'] . ' ';
-        }
-    }
-    if (! empty($_REQUEST['routine_definition'])) {
-        $query .= $_REQUEST['routine_definition'];
-    } else {
-        $routine_errors[] = __('You must provide a routine definition.');
-    }
-    return $query;
-} // end PMA_RTN_getQueryFromRequest()
-
-/**
- * Creates the HTML for a row of the routines list.
- *
- * @param    array    $routine    Data about the routine returned by a query
- *                                from the INFORMATION_SCHEMA db.
- * @param    int      $ct         Row count
- * @param    bool     $is_ajax    Whether this function was called
- *                                from within an AJAX request
- *
- * @return  string    An HTML snippet containing a row for the routines list.
- *
- */
-function PMA_RTN_getRowForRoutinesList($routine, $ct = 0, $is_ajax = false) {
-    global $titles, $db, $url_query, $ajax_class;
-
-    // Do the logic first
-    $rowclass = ($ct % 2 == 0) ? 'even' : 'odd';
-    if ($is_ajax) {
-        $rowclass .= ' ajaxInsert hide';
-    }
-    $editlink = $titles['NoEdit'];
-    $execlink = $titles['NoExecute'];
-    $exprlink = $titles['NoExport'];
-    $droplink = $titles['NoDrop'];
-    $sql_drop = sprintf('DROP %s IF EXISTS %s',
-                           $routine['ROUTINE_TYPE'],
-                           PMA_backquote($routine['SPECIFIC_NAME']));
-    if ($routine['ROUTINE_DEFINITION'] !== NULL
-        && PMA_currentUserHasPrivilege('ALTER ROUTINE', $db)
-        && PMA_currentUserHasPrivilege('CREATE ROUTINE', $db)) {
-        $editlink = '<a ' . $ajax_class['edit'] . ' href="db_routines.php?' . $url_query
-                          . '&editroutine=1'
-                          . '&routine_name=' . urlencode($routine['SPECIFIC_NAME'])
-                          . '">' . $titles['Edit'] . '</a>';
-    }
-    if ($routine['ROUTINE_DEFINITION'] !== NULL && PMA_currentUserHasPrivilege('EXECUTE', $db)) {
-        // Check if he routine has any input parameters. If it does,
-        // we will show a dialog to get values for these parameters,
-        // otherwise we can execute it directly.
-        $routine_details = PMA_RTN_getRoutineDataFromName($db, $routine['SPECIFIC_NAME'], false);
-        if ($routine !== false) {
-            $execute_action = 'execute_routine';
-            for ($i=0; $i<$routine_details['num_params']; $i++) {
-                if ($routine_details['type'] == 'PROCEDURE' && $routine_details['param_dir'][$i] == 'OUT') {
-                    continue;
-                }
-                $execute_action = 'execute_dialog';
-                break;
-            }
-            $execlink = '<a ' . $ajax_class['exec']. ' href="db_routines.php?' . $url_query
-                              . '&' . $execute_action . '=1'
-                              . '&routine_name=' . urlencode($routine['SPECIFIC_NAME'])
-                              . '">' . $titles['Execute'] . '</a>';
-        }
-    }
-    if ($routine['ROUTINE_DEFINITION'] !== NULL) {
-        $exprlink = '<a ' . $ajax_class['export'] . ' href="db_routines.php?' . $url_query
-                          . '&exportroutine=1'
-                          . '&routine_name=' . urlencode($routine['SPECIFIC_NAME'])
-                          . '">' . $titles['Export'] . '</a>';
-    }
-    if (PMA_currentUserHasPrivilege('ALTER ROUTINE', $db)) {
-        $droplink = '<a ' . $ajax_class['drop']. ' href="sql.php?' . $url_query
-                          . '&sql_query=' . urlencode($sql_drop)
-                          . '&goto=db_routines.php' . urlencode("?db=$db")
-                          . '" >' . $titles['Drop'] . '</a>';
-    }
-    // Display a row of data
-    $retval  = "        <tr class='$rowclass'>\n";
-    $retval .= "            <td>\n";
-    $retval .= "                <span class='drop_sql hide'>$sql_drop</span>\n";
-    $retval .= "                <strong>" . htmlspecialchars($routine['ROUTINE_NAME']) . "</strong>\n";
-    $retval .= "            </td>\n";
-    $retval .= "            <td>$editlink</td>\n";
-    $retval .= "            <td>$execlink</td>\n";
-    $retval .= "            <td>$exprlink</td>\n";
-    $retval .= "            <td>$droplink</td>\n";
-    $retval .= "            <td>{$routine['ROUTINE_TYPE']}</td>\n";
-    $retval .= "            <td>" . htmlspecialchars($routine['DTD_IDENTIFIER']) . "</td>\n";
-    $retval .= "        </tr>\n";
-    return $retval;
-} // end PMA_RTN_getRowForRoutinesList()
-
-/**
- * Creates a list of available routines for the specified database
- *
- * @return   string    An HTML snippet with the list of routines.
- *
- */
-function PMA_RTN_getRoutinesList()
-{
-    global $db;
-
-    /**
-     * Get the routines
-     */
-    $columns  = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`, `DTD_IDENTIFIER`, `ROUTINE_DEFINITION`";
-    $where    = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "'";
-    $routines = PMA_DBI_fetch_result("SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE $where;");
-    /**
-     * Conditional classes switch the list on or off
-     */
-    $class1 = 'hide';
-    $class2 = '';
-    if (! $routines) {
-        $class1 = '';
-        $class2 = ' hide';
-    }
-
-    /**
-     * Generate output
-     */
-    $retval  = "";
-    $retval .= "\n\n<span id='js_query_display'></span>\n\n";
-    $retval .= "<!-- LIST OF ROUTINES START -->\n";
-    $retval .= "<fieldset>\n";
-    $retval .= "    <legend>" . __('Routines') . "</legend>\n";
-    $retval .= "    <div class='$class1' id='nothing2display'>\n";
-    $retval .= "      " . __('There are no routines to display.') . "\n";
-    $retval .= "    </div>\n";
-    $retval .= "    <table class='data$class2'>\n";
-    $retval .= "        <!-- TABLE HEADERS -->\n";
-    $retval .= "        <tr>\n";
-    $retval .= "            <th>" . __('Name') . "</th>\n";
-    $retval .= "            <th colspan='4'>" . __('Action') . "</th>\n";
-    $retval .= "            <th>" . __('Type') . "</th>\n";
-    $retval .= "            <th>" . __('Return type') . "</th>\n";
-    $retval .= "        </tr>\n";
-    $retval .= "        <!-- TABLE DATA -->\n";
-    $ct = 0;
-    // Display each routine
-    foreach ($routines as $routine) {
-        $retval .= PMA_RTN_getRowForRoutinesList($routine, $ct);
-        $ct++;
-    }
-    $retval .= "    </table>\n";
-    $retval .= "</fieldset>\n";
-    $retval .= "<!-- LIST OF ROUTINES END -->\n\n";
-
-    return $retval;
-} // end PMA_RTN_getRoutinesList()
-
-/**
- * Creates a fieldset for adding a new routine, if the user has the privileges.
- *
- * @return   string    An HTML snippet with the link to add a new routine.
- *
- */
-function PMA_RTN_getAddRoutineLink()
-{
-    global $db, $url_query, $ajax_class;
-
-    $retval  = "";
-    $retval .= "<!-- ADD ROUTINE FORM START -->\n";
-    $retval .= "<fieldset>\n";
-    if (PMA_currentUserHasPrivilege('CREATE ROUTINE', $db)) {
-        $retval .= "<a {$ajax_class['add']} href='db_routines.php";
-        $retval .= "?$url_query&addroutine=1'>\n";
-        $retval .= PMA_getIcon('b_routine_add.png') . "\n";
-        $retval .= __('Add routine') . "</a>\n";
-    } else {
-        $retval .= PMA_getIcon('b_routine_add.png') . "\n";
-        $retval .= __('You do not have the necessary privileges to create a new routine') . "\n";
-    }
-    $retval .= PMA_showMySQLDocu('SQL-Syntax', 'CREATE_PROCEDURE') . "\n";
-    $retval .= "</fieldset>\n";
-    $retval .= "<!-- ADD ROUTINE FORM END -->\n\n";
-
-    return $retval;
-} // end PMA_RTN_getAddRoutineLink()
-
-?>
diff --git a/libraries/display_triggers.inc.php b/libraries/display_triggers.inc.php
deleted file mode 100644
index fcadfba..0000000
--- a/libraries/display_triggers.inc.php
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-/**
- *
- * @package phpMyAdmin
- */
-if (! defined('PHPMYADMIN')) {
-    exit;
-}
-
-$url_query .= '&goto=tbl_triggers.php';
-
-$triggers = PMA_DBI_get_triggers($db, $table);
-
-$conditional_class_add    = '';
-$conditional_class_drop   = '';
-$conditional_class_export = '';
-if ($GLOBALS['cfg']['AjaxEnable']) {
-    $conditional_class_add    = 'class="add_trigger_anchor"';
-    $conditional_class_drop   = 'class="drop_trigger_anchor"';
-    $conditional_class_export = 'class="export_trigger_anchor"';
-}
-
-/**
- * Display the export for a trigger. This is for when JS is disabled.
- */
-if (! empty($_GET['exporttrigger']) && ! empty($_GET['triggername'])) {
-    $success = false;
-    foreach ($triggers as $trigger) {
-        if ($trigger['name'] === $_GET['triggername']) {
-            $success = true;
-            $trigger_name = htmlspecialchars(PMA_backquote($_GET['triggername']));
-            $create_trig = '<textarea cols="40" rows="15" style="width: 100%;">' . $trigger['create'] . '</textarea>';
-            if (! empty($_REQUEST['ajax_request'])) {
-                $extra_data = array('title' => sprintf(__('Export of trigger %s'), $trigger_name));
-                PMA_ajaxResponse($create_trig, true, $extra_data);
-            } else {
-                echo '<fieldset>' . "\n"
-                   . ' <legend>' . sprintf(__('Export of trigger "%s"'), $trigger_name) . '</legend>' . "\n"
-                   . $create_trig
-                   . '</fieldset>';
-            }
-        }
-    }
-    if (! $success) {
-        $response = __('Error in Processing Request') . ' : '
-                  . sprintf(__('No trigger with name %s found'), $event_name);
-        $response = PMA_message::error($response);
-        if (! empty($_REQUEST['ajax_request'])) {
-            PMA_ajaxResponse($response, false);
-        } else {
-            $response->display();
-        }
-    }
-}
-
-/**
- * Display a list of available triggers
- */
-echo "\n\n<span id='js_query_display'></span>\n\n";
-echo '<fieldset>' . "\n";
-echo ' <legend>' . __('Triggers') . '</legend>' . "\n";
-if (! $triggers) {
-    echo __('There are no triggers to display.');
-} else {
-    echo '<div class="hide" id="nothing2display">' . __('There are no triggers to display.') . '</div>';
-    echo '<table class="data">' . "\n";
-
-    // Print table header
-    echo "<tr>\n<th>" . __('Name') . "</th>\n";
-    if (empty($table)) {
-        // if we don't have a table name, we will be showing the per-database list.
-        // so we must specify which table each trigger belongs to
-        echo "<th>" . __('Table') . "</th>\n";
-    }
-    echo "<th colspan='3'>" . __('Action') . "</th>\n";
-    echo "<th>" . __('Time') . "</th>\n";
-    echo "<th>" . __('Event') . "</th>\n";
-    echo "</tr>";
-
-    $ct=0;
-    $delimiter = '//';
-    // Print table contents
-    foreach ($triggers as $trigger) {
-        $drop_and_create = $trigger['drop'] . $delimiter . "\n" . $trigger['create'] . "\n";
-        $row = ($ct%2 == 0) ? 'even' : 'odd';
-        $editlink = PMA_linkOrButton('tbl_sql.php?' . $url_query . '&sql_query='
-                  . urlencode($drop_and_create) . '&show_query=1&delimiter=' . urlencode($delimiter), $titles['Edit']);
-        $exprlink = '<a ' . $conditional_class_export . ' href="db_triggers.php?' . $url_query
-                  . '&exporttrigger=1'
-                  . '&triggername=' . urlencode($trigger['name'])
-                  . '">' . $titles['Export'] . '</a>';
-        $droplink = '<a ' . $conditional_class_drop . ' href="sql.php?' . $url_query . '&sql_query='
-                  . urlencode($trigger['drop']) . '" >' . $titles['Drop'] . '</a>';
-
-        echo "<tr class='noclick $row'>\n";
-        echo "<td><span class='drop_sql' style='display:none;'>{$trigger['drop']}</span>";
-        echo "<strong>{$trigger['name']}</strong></td>\n";
-        if (empty($table)) {
-            echo "<td><a href='tbl_triggers.php?db=$db&table={$trigger['table']}'>";
-            echo $trigger['table'] . "</a></td>\n";
-        }
-        echo "<td>$editlink</td>\n";
-        echo "<td><div class='create_sql' style='display: none;'>{$trigger['create']}</div>$exprlink</td>\n";
-        echo "<td>$droplink</td>\n";
-        echo "<td>{$trigger['action_timing']}</td>\n";
-        echo "<td>{$trigger['event_manipulation']}</td>\n";
-        echo "</tr>\n";
-        $ct++;
-    }
-    echo '</table>';
-}
-echo '</fieldset>';
-
-/**
- * Display the form for adding a new trigger
- */
-echo '<fieldset>' . "\n"
-   . '    <a href="tbl_triggers.php?' . $url_query . '&addtrigger=1" class="' . $conditional_class_add . '">' . "\n"
-   . PMA_getIcon('b_trigger_add.png') . __('Add a trigger') . '</a>' . "\n"
-   . '</fieldset>' . "\n";
-
-?>
diff --git a/libraries/rte/rte_events.lib.php b/libraries/rte/rte_events.lib.php
new file mode 100644
index 0000000..070dc20
--- /dev/null
+++ b/libraries/rte/rte_events.lib.php
@@ -0,0 +1,567 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Functions for event management.
+ *
+ * @package phpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+    exit;
+}
+
+/**
+ * This function is defined in: rte_routines.lib.php, rte_triggers.lib.php and
+ * rte_events.lib.php. It is used to retreive some language strings that are
+ * used in functionalities that are common to routines, triggers and events.
+ *
+ * @param   string  $index   The index of the string to get
+ *
+ * @return  string  The requested string or an empty string, if not available
+ */
+function PMA_RTE_getWord($index)
+{
+    $words = array(
+        'add'       => __('Add event'),
+        'docu'      => 'EVENTS',
+        'export'    => __('Export of event %s'),
+        'human'     => __('event'),
+        'no_create' => __('You do not have the necessary privileges to create a new event'),
+        'not_found' => __('No event with name %1$s found in database %2$s'),
+        'nothing'   => __('There are no events to display.'),
+        'title'     => __('Events'),
+    );
+    return isset($words[$index]) ? $words[$index] : '';
+} // end PMA_RTE_getWord()
+
+/**
+ * Main function for the events functionality
+ */
+function PMA_RTE_main()
+{
+    global $db;
+
+    /**
+     * Process all requests
+     */
+    PMA_EVN_handleEditor();
+    PMA_EVN_handleExport();
+    /**
+     * Display a list of available events
+     */
+    $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`";
+    $where   = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "'";
+    $query   = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` "
+             . "WHERE $where ORDER BY `EVENT_NAME` ASC;";
+    $items   = PMA_DBI_fetch_result($query);
+    echo PMA_RTE_getList('event', $items);
+    /**
+     * Display a link for adding a new event, if
+     * the user has the privileges and a link to
+     * toggle the state of the event scheduler.
+     */
+    echo PMA_EVN_getFooterLinks();
+} // end PMA_RTE_main()
+
+/**
+ * Handles editor requests for adding or editing an item
+ */
+function PMA_EVN_handleEditor()
+{
+    global $_REQUEST, $_POST, $errors, $db, $table;
+
+    if (! empty($_REQUEST['editor_process_add'])
+        || ! empty($_REQUEST['editor_process_edit'])
+    ) {
+        $sql_query = '';
+
+        $item_query = PMA_EVN_getQueryFromRequest();
+
+        if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest()
+            // Execute the created query
+            if (! empty($_REQUEST['editor_process_edit'])) {
+                // Backup the old trigger, in case something goes wrong
+                $create_item = PMA_DBI_get_definition(
+                    $db,
+                    'EVENT',
+                    $_REQUEST['item_original_name']
+                );
+                $drop_item = "DROP EVENT " . PMA_backquote($_REQUEST['item_original_name']) . ";\n";
+                $result = PMA_DBI_try_query($drop_item);
+                if (! $result) {
+                    $errors[] = sprintf(__('The following query has failed: "%s"'), $drop_item) . '<br />'
+                                      . __('MySQL said: ') . PMA_DBI_getError(null);
+                } else {
+                    $result = PMA_DBI_try_query($item_query);
+                    if (! $result) {
+                        $errors[] = sprintf(__('The following query has failed: "%s"'), $item_query) . '<br />'
+                                          . __('MySQL said: ') . PMA_DBI_getError(null);
+                        // We dropped the old item, but were unable to create the new one
+                        // Try to restore the backup query
+                        $result = PMA_DBI_try_query($create_item);
+                        if (! $result) {
+                            // OMG, this is really bad! We dropped the query, failed to create a new one
+                            // and now even the backup query does not execute!
+                            // This should not happen, but we better handle this just in case.
+                            $errors[] = __('Sorry, we failed to restore the dropped event.') . '<br />'
+                                              . __('The backed up query was:') . "\"$create_item\"" . '<br />'
+                                              . __('MySQL said: ') . PMA_DBI_getError(null);
+                        }
+                    } else {
+                        $message = PMA_Message::success(__('Event %1$s has been modified.'));
+                        $message->addParam(PMA_backquote($_REQUEST['item_name']));
+                        $sql_query = $drop_item . $item_query;
+                    }
+                }
+            } else {
+                // 'Add a new item' mode
+                $result = PMA_DBI_try_query($item_query);
+                if (! $result) {
+                    $errors[] = sprintf(__('The following query has failed: "%s"'), $item_query) . '<br /><br />'
+                                      . __('MySQL said: ') . PMA_DBI_getError(null);
+                } else {
+                    $message = PMA_Message::success(__('Event %1$s has been created.'));
+                    $message->addParam(PMA_backquote($_REQUEST['item_name']));
+                    $sql_query = $item_query;
+                }
+            }
+        }
+
+        if (count($errors)) {
+            $message = PMA_Message::error(__('<b>One or more errors have occured while processing your request:</b>'));
+            $message->addString('<ul>');
+            foreach ($errors as $num => $string) {
+                $message->addString('<li>' . $string . '</li>');
+            }
+            $message->addString('</ul>');
+        }
+
+        $output = PMA_showMessage($message, $sql_query);
+        if ($GLOBALS['is_ajax_request']) {
+            $extra_data = array();
+            if ($message->isSuccess()) {
+                $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`";
+                $where   = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "' "
+                         . "AND EVENT_NAME='" . PMA_sqlAddSlashes($_REQUEST['item_name']) . "'";
+                $query   = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;";
+                $event   = PMA_DBI_fetch_single_row($query);
+                $extra_data['name'] = htmlspecialchars(strtoupper($_REQUEST['item_name']));
+                $extra_data['new_row'] = PMA_EVN_getRowForList($event);
+                $extra_data['insert'] = ! empty($event);
+                $response = $output;
+            } else {
+                $response = $message;
+            }
+            PMA_ajaxResponse($response, $message->isSuccess(), $extra_data);
+        }
+    }
+    /**
+     * Display a form used to add/edit a trigger, if necessary
+     */
+    if (count($errors) || ( empty($_REQUEST['editor_process_add']) && empty($_REQUEST['editor_process_edit'])
+        && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item'])
+        || ! empty($_REQUEST['item_changetype'])))
+    ) { // FIXME: this must be simpler than that
+        $operation = '';
+        if (! empty($_REQUEST['item_changetype'])) {
+            $operation = 'change';
+        }
+        // Get the data for the form (if any)
+        if (! empty($_REQUEST['add_item'])) {
+            $title = __("Create event");
+            $item = PMA_EVN_getDataFromRequest();
+            $mode = 'add';
+        } else if (! empty($_REQUEST['edit_item'])) {
+            $title = __("Edit event");
+            if (! empty($_REQUEST['item_name'])
+                && empty($_REQUEST['editor_process_edit'])
+                && empty($_REQUEST['item_changetype'])
+            ) {
+                $item = PMA_EVN_getDataFromName($_REQUEST['item_name']);
+                if ($item !== false) {
+                    $item['item_original_name'] = $item['item_name'];
+                }
+            } else {
+                $item = PMA_EVN_getDataFromRequest();
+            }
+            $mode = 'edit';
+        }
+        if ($item !== false) {
+            // Show form
+            $editor = PMA_EVN_getEditorForm($mode, $operation, $item);
+            if ($GLOBALS['is_ajax_request']) {
+                $extra_data = array('title' => $title);
+                PMA_ajaxResponse($editor, true, $extra_data);
+            } else {
+                echo "\n\n<h2>$title</h2>\n\n$editor";
+                unset($_POST);
+                require './libraries/footer.inc.php';
+            }
+            // exit;
+        } else {
+            $message  = __('Error in processing request') . ' : ';
+            $message .= sprintf(
+                PMA_RTE_getWord('not_found'),
+                htmlspecialchars(PMA_backquote($_REQUEST['item_name'])),
+                htmlspecialchars(PMA_backquote($db))
+            );
+            $message = PMA_message::error($message);
+            if ($GLOBALS['is_ajax_request']) {
+                PMA_ajaxResponse($message, false);
+            } else {
+                $message->display();
+            }
+        }
+    }
+} // end PMA_EVN_handleEditor()
+
+/**
+ * This function will generate the values that are required to for the editor
+ *
+ * @return  array    Data necessary to create the editor.
+ */
+function PMA_EVN_getDataFromRequest()
+{
+    $retval = array();
+    $indices = array('item_name',
+                     'item_original_name',
+                     'item_status',
+                     'item_execute_at',
+                     'item_interval_value',
+                     'item_interval_field',
+                     'item_starts',
+                     'item_ends',
+                     'item_definition',
+                     'item_preserve',
+                     'item_comment',
+                     'item_definer');
+    foreach ($indices as $key => $index) {
+        $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : '';
+    }
+    $retval['item_type']        = 'ONE TIME';
+    $retval['item_type_toggle'] = 'RECURRING';
+    if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'RECURRING') {
+        $retval['item_type']        = 'RECURRING';
+        $retval['item_type_toggle'] = 'ONE TIME';
+    }
+    return $retval;
+} // end PMA_EVN_getDataFromRequest()
+
+/**
+ * This function will generate the values that are required to complete
+ * the "Edit event" form given the name of a event.
+ *
+ * @param   string   $name   The name of the event.
+ *
+ * @return  array    Data necessary to create the editor.
+ */
+function PMA_EVN_getDataFromName($name)
+{
+    global $db;
+
+    $retval = array();
+    $columns = "`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, "
+             . "`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, "
+             . "`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`";
+    $where   = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "' "
+             . "AND EVENT_NAME='" . PMA_sqlAddSlashes($name) . "'";
+    $query   = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;";
+    $item    = PMA_DBI_fetch_single_row($query);
+    if (! $item) {
+        return false;
+    }
+    $retval['item_name']   = $item['EVENT_NAME'];
+    $retval['item_status'] = $item['STATUS'];
+    $retval['item_type']   = $item['EVENT_TYPE'];
+    if ($retval['item_type'] == 'RECURRING') {
+        $retval['item_type_toggle'] = 'ONE TIME';
+    } else {
+        $retval['item_type_toggle'] = 'RECURRING';
+    }
+    $retval['item_execute_at']     = $item['EXECUTE_AT'];
+    $retval['item_interval_value'] = $item['INTERVAL_VALUE'];
+    $retval['item_interval_field'] = $item['INTERVAL_FIELD'];
+    $retval['item_starts']         = $item['STARTS'];
+    $retval['item_ends']           = $item['ENDS'];
+    $retval['item_preserve']       = '';
+    if ($item['ON_COMPLETION'] == 'PRESERVE') {
+        $retval['item_preserve']   = " checked='checked'";
+    }
+    $retval['item_definition'] = $item['EVENT_DEFINITION'];
+    $retval['item_definer']    = $item['DEFINER'];
+    $retval['item_comment']    = $item['EVENT_COMMENT'];
+
+    return $retval;
+} // end PMA_EVN_getDataFromName()
+
+/**
+ * Displays a form used to add/edit an event
+ *
+ * @param   string   $mode      If the editor will be used edit an event
+ *                              or add a new one: 'edit' or 'add'.
+ * @param   string   $operation If the editor was previously invoked with
+ *                              JS turned off, this will hold the name of
+ *                              the current operation
+ * @param   array    $item      Data for the event returned by
+ *                              PMA_EVN_getDataFromRequest() or
+ *                              PMA_EVN_getDataFromName()
+ *
+ * @return  string   HTML code for the editor.
+ */
+function PMA_EVN_getEditorForm($mode, $operation, $item)
+{
+    global $db, $table, $titles, $event_status, $event_type, $event_interval;
+
+    // Escape special characters
+    $need_escape = array(
+                       'item_original_name',
+                       'item_name',
+                       'item_type',
+                       'item_execute_at',
+                       'item_interval_value',
+                       'item_starts',
+                       'item_ends',
+                       'item_definition',
+                       'item_definer',
+                       'item_comment'
+                   );
+    foreach ($need_escape as $key => $index) {
+        $item[$index] = htmlentities($item[$index], ENT_QUOTES);
+    }
+    $original_data = '';
+    if ($mode == 'edit') {
+        $original_data = "<input name='item_original_name' "
+                       . "type='hidden' value='{$item['item_original_name']}'/>\n";
+    }
+    // Handle some logic first
+    if ($operation == 'change') {
+        if ($item['item_type'] == 'RECURRING') {
+            $item['item_type']         = 'ONE TIME';
+            $item['item_type_toggle']  = 'RECURRING';
+        } else {
+            $item['item_type']         = 'RECURRING';
+            $item['item_type_toggle']  = 'ONE TIME';
+        }
+    }
+    if ($item['item_type'] == 'ONE TIME') {
+        $isrecurring_class = ' hide';
+        $isonetime_class   = '';
+    } else {
+        $isrecurring_class = '';
+        $isonetime_class   = ' hide';
+    }
+    // Create the output
+    $retval  = "";
+    $retval .= "<!-- START " . strtoupper($mode) . " EVENT FORM -->\n\n";
+    $retval .= "<form class='rte_form' action='db_events.php' method='post'>\n";
+    $retval .= "<input name='{$mode}_item' type='hidden' value='1' />\n";
+    $retval .= $original_data;
+    $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n";
+    $retval .= "<fieldset>\n";
+    $retval .= "<legend>" . __('Details') . "</legend>\n";
+    $retval .= "<table class='rte_table' style='width: 100%'>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td style='width: 20%;'>" . __('Event name') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_name' \n";
+    $retval .= "               value='{$item['item_name']}'\n";
+    $retval .= "               maxlength='64' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Status') . "</td>\n";
+    $retval .= "    <td>\n";
+    $retval .= "        <select name='item_status'>\n";
+    foreach ($event_status['display'] as $key => $value) {
+        $selected = "";
+        if (! empty($item['item_status']) && $item['item_status'] == $value) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "<option$selected>$value</option>";
+    }
+    $retval .= "        </select>\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Event type') . "</td>\n";
+    $retval .= "    <td>\n";
+    if ($GLOBALS['is_ajax_request']) {
+        $retval .= "        <select name='item_type'>";
+        foreach ($event_type as $key => $value) {
+            $selected = "";
+            if (! empty($item['item_type']) && $item['item_type'] == $value) {
+                $selected = " selected='selected'";
+            }
+            $retval .= "<option$selected>$value</option>";
+        }
+        $retval .= "        </select>\n";
+    } else {
+        $retval .= "        <input name='item_type' type='hidden' \n";
+        $retval .= "               value='{$item['item_type']}' />\n";
+        $retval .= "        <div style='width: 49%; float: left; text-align: center; font-weight: bold;'>\n";
+        $retval .= "            {$item['item_type']}\n";
+        $retval .= "        </div>\n";
+        $retval .= "        <input style='width: 49%;' type='submit'\n";
+        $retval .= "               name='item_changetype'\n";
+        $retval .= "               value='";
+        $retval .= sprintf(__('Change to %s'), $item['item_type_toggle']);
+        $retval .= "' />\n";
+    }
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr class='onetime_event_row $isonetime_class'>\n";
+    $retval .= "    <td>" . __('Execute at') . "</td>\n";
+    $retval .= "    <td class='nowrap'>\n";
+    $retval .= "        <input type='text' name='item_execute_at'\n";
+    $retval .= "               value='{$item['item_execute_at']}'\n";
+    $retval .= "               class='datetimefield' />\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr class='recurring_event_row $isrecurring_class'>\n";
+    $retval .= "    <td>" . __('Execute every') . "</td>\n";
+    $retval .= "    <td>\n";
+    $retval .= "        <input style='width: 49%;' type='text'\n";
+    $retval .= "               name='item_interval_value'\n";
+    $retval .= "               value='{$item['item_interval_value']}' />\n";
+    $retval .= "        <select style='width: 49%;' name='item_interval_field'>";
+    foreach ($event_interval as $key => $value) {
+        $selected = "";
+        if (! empty($item['item_interval_field'])
+            && $item['item_interval_field'] == $value
+        ) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "<option$selected>$value</option>";
+    }
+    $retval .= "        </select>\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr class='recurring_event_row$isrecurring_class'>\n";
+    $retval .= "    <td>" . __('Start') . "</td>\n";
+    $retval .= "    <td class='nowrap'>\n";
+    $retval .= "        <input type='text'\n name='item_starts'\n";
+    $retval .= "               value='{$item['item_starts']}'\n";
+    $retval .= "               class='datetimefield' />\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr class='recurring_event_row$isrecurring_class'>\n";
+    $retval .= "    <td>" . __('End') . "</td>\n";
+    $retval .= "    <td class='nowrap'>\n";
+    $retval .= "        <input type='text' name='item_ends'\n";
+    $retval .= "               value='{$item['item_ends']}'\n";
+    $retval .= "               class='datetimefield' />\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Definition') . "</td>\n";
+    $retval .= "    <td><textarea name='item_definition' rows='15' cols='40'>";
+    $retval .= $item['item_definition'];
+    $retval .= "</textarea></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('On completion preserve') . "</td>\n";
+    $retval .= "    <td><input type='checkbox' name='item_preserve'{$item['item_preserve']} /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Definer') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_definer'\n";
+    $retval .= "               value='{$item['item_definer']}' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Comment') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_comment' maxlength='64'\n";
+    $retval .= "               value='{$item['item_comment']}' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "</table>\n";
+    $retval .= "</fieldset>\n";
+    if ($GLOBALS['is_ajax_request']) {
+        $retval .= "<input type='hidden' name='editor_process_{$mode}'\n";
+        $retval .= "       value='true' />\n";
+        $retval .= "<input type='hidden' name='ajax_request' value='true' />\n";
+    } else {
+        $retval .= "<fieldset class='tblFooters'>\n";
+        $retval .= "    <input type='submit' name='editor_process_{$mode}'\n";
+        $retval .= "           value='" . __('Go') . "' />\n";
+        $retval .= "</fieldset>\n";
+    }
+    $retval .= "</form>\n\n";
+    $retval .= "<!-- END " . strtoupper($mode) . " EVENT FORM -->\n\n";
+
+    return $retval;
+} // end PMA_EVN_getEditorForm()
+
+/**
+ * Composes the query necessary to create an event from an HTTP request.
+ *
+ * @return  string  The CREATE EVENT query.
+ */
+function PMA_EVN_getQueryFromRequest()
+{
+    global $_REQUEST, $db, $errors, $event_status, $event_type, $event_interval;
+
+    $query = 'CREATE ';
+    if (! empty($_REQUEST['item_definer'])) {
+        if (strpos($_REQUEST['item_definer'], '@') !== false) {
+            $arr = explode('@', $_REQUEST['item_definer']);
+            $query .= 'DEFINER=' . PMA_backquote($arr[0]);
+            $query .= '@' . PMA_backquote($arr[1]) . ' ';
+        } else {
+            $errors[] = __('The definer must be in the "username at hostname" format');
+        }
+    }
+    $query .= 'EVENT ';
+    if (! empty($_REQUEST['item_name'])) {
+        $query .= PMA_backquote($_REQUEST['item_name']) . ' ';
+    } else {
+        $errors[] = __('You must provide an event name');
+    }
+    $query .= 'ON SCHEDULE ';
+    if (! empty($_REQUEST['item_type']) && in_array($_REQUEST['item_type'], $event_type)) {
+        if ($_REQUEST['item_type'] == 'RECURRING') {
+            if (! empty($_REQUEST['item_interval_value'])
+                && !empty($_REQUEST['item_interval_field'])
+                && in_array($_REQUEST['item_interval_field'], $event_interval)
+            ) {
+                $query .= 'EVERY ' . intval($_REQUEST['item_interval_value']) . ' ';
+                $query .= $_REQUEST['item_interval_field'] . ' ';
+            } else {
+                $errors[] = __('You must provide a valid interval value for the event.');
+            }
+            if (! empty($_REQUEST['item_starts'])) {
+                $query .= "STARTS '" . PMA_sqlAddSlashes($_REQUEST['item_starts']) . "' ";
+            }
+            if (! empty($_REQUEST['item_ends'])) {
+                $query .= "ENDS '" . PMA_sqlAddSlashes($_REQUEST['item_ends']) . "' ";
+            }
+        } else {
+            if (! empty($_REQUEST['item_execute_at'])) {
+                $query .= "AT '" . PMA_sqlAddSlashes($_REQUEST['item_execute_at']) . "' ";
+            } else {
+                $errors[] = __('You must provide a valid execution time for the event.');
+            }
+        }
+    } else {
+        $errors[] = __('You must provide a valid type for the event.');
+    }
+    $query .= 'ON COMPLETION ';
+    if (empty($_REQUEST['item_preserve'])) {
+        $query .= 'NOT ';
+    }
+    $query .= 'PRESERVE ';
+    if (! empty($_REQUEST['item_status'])) {
+        foreach ($event_status['display'] as $key => $value) {
+            if ($value == $_REQUEST['item_status']) {
+                $query .= $event_status['query'][$key] . ' ';
+                break;
+            }
+        }
+    }
+    $query .= 'DO ';
+    if (! empty($_REQUEST['item_definition'])) {
+        $query .= $_REQUEST['item_definition'];
+    } else {
+        $errors[] = __('You must provide an event definition.');
+    }
+
+    return $query;
+} // end PMA_EVN_getQueryFromRequest()
+
+?>
diff --git a/libraries/rte/rte_export.lib.php b/libraries/rte/rte_export.lib.php
new file mode 100644
index 0000000..d4d8f99
--- /dev/null
+++ b/libraries/rte/rte_export.lib.php
@@ -0,0 +1,107 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Common functions for the export functionality for Routines, Triggers and Events.
+ *
+ * @package phpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+    exit;
+}
+
+/**
+ * This function is called from one of the other functions in this file
+ * and it completes the handling of the export functionality.
+ *
+ * @param  string  $item_name    The name of the item that we are exporting
+ * @param  string  $export_data  The SQL query to create the requested item
+ */
+function PMA_RTE_handleExport($item_name, $export_data)
+{
+    global $db, $table;
+
+    $item_name = htmlspecialchars(PMA_backquote($_GET['item_name']));
+    if ($export_data !== false) {
+        $export_data = '<textarea cols="40" rows="15" style="width: 100%;">'
+                     . htmlspecialchars(trim($export_data)) . '</textarea>';
+        $title = sprintf(PMA_RTE_getWord('export'), $item_name);
+        if ($GLOBALS['is_ajax_request'] == true) {
+            $extra_data = array('title' => $title);
+            PMA_ajaxResponse($export_data, true, $extra_data);
+        } else {
+            echo "<fieldset>\n"
+               . "<legend>$title</legend>\n"
+               . $export_data
+               . "</fieldset>\n";
+        }
+    } else {
+        $_db = htmlspecialchars(PMA_backquote($db));
+        $response = __('Error in Processing Request') . ' : '
+                  . sprintf(PMA_RTE_getWord('not_found'), $item_name, $_db);
+        $response = PMA_message::error($response);
+        if ($GLOBALS['is_ajax_request'] == true) {
+            PMA_ajaxResponse($response, false);
+        } else {
+            $response->display();
+        }
+    }
+} // end PMA_RTE_handleExport()
+
+/**
+ * If necessary, prepares event information and passes
+ * it to PMA_RTE_handleExport() for the actual export.
+ */
+function PMA_EVN_handleExport()
+{
+    global $_GET, $db;
+
+    if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) {
+        $item_name = $_GET['item_name'];
+        $export_data = PMA_DBI_get_definition($db, 'EVENT', $item_name);
+        PMA_RTE_handleExport($item_name, $export_data);
+    }
+} // end PMA_EVN_handleExport()
+
+/**
+ * If necessary, prepares routine information and passes
+ * it to PMA_RTE_handleExport() for the actual export.
+ */
+function PMA_RTN_handleExport()
+{
+    global $_GET, $db;
+
+    if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) {
+        $item_name = $_GET['item_name'];
+        $type = PMA_DBI_fetch_value(
+            "SELECT ROUTINE_TYPE " .
+            "FROM INFORMATION_SCHEMA.ROUTINES " .
+            "WHERE ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' " .
+            "AND SPECIFIC_NAME='" . PMA_sqlAddSlashes($item_name) . "';"
+        );
+        $export_data = PMA_DBI_get_definition($db, $type, $item_name);
+        PMA_RTE_handleExport($item_name, $export_data);
+    }
+} // end PMA_RTN_handleExport()
+
+/**
+ * If necessary, prepares trigger information and passes
+ * it to PMA_RTE_handleExport() for the actual export.
+ */
+function PMA_TRI_handleExport()
+{
+    global $_GET, $db, $table;
+
+    if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) {
+        $item_name = $_GET['item_name'];
+        $triggers = PMA_DBI_get_triggers($db, $table, '');
+        $export_data = false;
+        foreach ($triggers as $trigger) {
+            if ($trigger['name'] === $item_name) {
+                $export_data = $trigger['create'];
+                break;
+            }
+        }
+        PMA_RTE_handleExport($item_name, $export_data);
+    }
+} // end PMA_TRI_handleExport()
+?>
diff --git a/libraries/rte/rte_footer.lib.php b/libraries/rte/rte_footer.lib.php
new file mode 100644
index 0000000..22e414b
--- /dev/null
+++ b/libraries/rte/rte_footer.lib.php
@@ -0,0 +1,127 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Common functions for generating the footer for Routines, Triggers and Events.
+ *
+ * @package phpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+    exit;
+}
+
+/**
+ * Creates a fieldset for adding a new item, if the user has the privileges.
+ *
+ * @param    string   $docu   String used to create a link to the MySQL docs
+ * @param    string   $priv   Privilege to check for adding a new item
+ * @param    string   $name   MySQL name of the item
+ *
+ * @return   string   An HTML snippet with the link to add a new item
+ */
+function PMA_RTE_getFooterLinks($docu, $priv, $name)
+{
+    global $db, $url_query, $ajax_class;
+
+    $icon = 'b_' . strtolower($name) . '_add.png';
+    $retval  = "";
+    $retval .= "<!-- ADD " . $name . " FORM START -->\n";
+    $retval .= "<fieldset class='left'>\n";
+    $retval .= "    <legend>" . __('New'). "</legend>\n";
+    $retval .= "        <div class='wrap'>\n";
+    if (PMA_currentUserHasPrivilege($priv, $db)) {
+        $retval .= "            <a {$ajax_class['add']} ";
+        $retval .= "href='db_" . strtolower($name) . "s.php";
+        $retval .= "?$url_query&add_item=1'>";
+        $retval .= PMA_getIcon($icon);
+        $retval .= PMA_RTE_getWord('add') . "</a>\n";
+    } else {
+        $retval .= "            " . PMA_getIcon($icon);
+        $retval .= PMA_RTE_getWord('no_create') . "\n";
+    }
+    $retval .= "            " . PMA_showMySQLDocu('SQL-Syntax', $docu) . "\n";
+    $retval .= "        </div>\n";
+    $retval .= "</fieldset>\n";
+    $retval .= "<!-- ADD " . $name . " FORM END -->\n\n";
+
+    return $retval;
+} // end PMA_RTE_getFooterLinks()
+
+/**
+ * Creates a fieldset for adding a new routine, if the user has the privileges.
+ *
+ * @return   string    HTML code with containing the fotter fieldset
+ */
+function PMA_RTN_getFooterLinks()
+{
+    return PMA_RTE_getFooterLinks('CREATE_PROCEDURE', 'CREATE ROUTINE', 'ROUTINE');
+}// end PMA_RTN_getFooterLinks()
+
+/**
+ * Creates a fieldset for adding a new trigger, if the user has the privileges.
+ *
+ * @return   string    HTML code with containing the fotter fieldset
+ */
+function PMA_TRI_getFooterLinks()
+{
+    return PMA_RTE_getFooterLinks('CREATE_TRIGGER', 'TRIGGER', 'TRIGGER');
+} // end PMA_TRI_getFooterLinks()
+
+/**
+ * Creates a fieldset for adding a new event, if the user has the privileges.
+ *
+ * @return   string    HTML code with containing the fotter fieldset
+ */
+function PMA_EVN_getFooterLinks()
+{
+    global $db, $url_query, $ajax_class;
+
+    /**
+     * For events, we show the usual 'Add event' form and also
+     * a form for toggling the state of the event scheduler
+     */
+    // Init options for the event scheduler toggle functionality
+    $es_state = PMA_DBI_fetch_value(
+        "SHOW GLOBAL VARIABLES LIKE 'event_scheduler'",
+        0,
+        1
+    );
+    $es_state = strtolower($es_state);
+    $options = array(
+                    0 => array(
+                        'label' => __('OFF'),
+                        'value' => "SET GLOBAL event_scheduler=\"OFF\"",
+                        'selected' => ($es_state != 'on')
+                    ),
+                    1 => array(
+                        'label' => __('ON'),
+                        'value' => "SET GLOBAL event_scheduler=\"ON\"",
+                        'selected' => ($es_state == 'on')
+                    )
+               );
+    // Generate output
+    $retval  = "<!-- FOOTER LINKS START -->\n";
+    $retval .= "<div class='doubleFieldset'>\n";
+    // show the usual footer
+    $retval .= PMA_RTE_getFooterLinks('CREATE_EVENT', 'EVENT', 'EVENT');
+    $retval .= "    <fieldset class='right'>\n";
+    $retval .= "        <legend>\n";
+    $retval .= "            " . __('Event scheduler status') . "\n";
+    $retval .= "        </legend>\n";
+    $retval .= "        <div class='wrap'>\n";
+    // show the toggle button
+    $retval .= PMA_toggleButton(
+        "sql.php?$url_query&goto=db_events.php" . urlencode("?db=$db"),
+        'sql_query',
+        $options,
+        'PMA_slidingMessage(data.sql_query);'
+    );
+    $retval .= "        </div>\n";
+    $retval .= "    </fieldset>\n";
+    $retval .= "    <div style='clear: both;'></div>\n";
+    $retval .= "</div>";
+    $retval .= "<!-- FOOTER LINKS END -->\n";
+
+    return $retval;
+} // end PMA_EVN_getFooterLinks()
+
+?>
diff --git a/libraries/rte/rte_list.lib.php b/libraries/rte/rte_list.lib.php
new file mode 100644
index 0000000..91cbbbc
--- /dev/null
+++ b/libraries/rte/rte_list.lib.php
@@ -0,0 +1,338 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Common functions for generating lists of Routines, Triggers and Events.
+ *
+ * @package phpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+    exit;
+}
+
+/**
+ * Creates a list of items containing the relevant
+ * information and some action links.
+ *
+ * @param    string   $type    One of ['routine'|'trigger'|'event']
+ * @param    array    $items   An array of items
+ *
+ * @return   string   HTML code of the list of items
+ */
+function PMA_RTE_getList($type, $items)
+{
+    /**
+     * Conditional classes switch the list on or off
+     */
+    $class1 = 'hide';
+    $class2 = '';
+    if (! $items) {
+        $class1 = '';
+        $class2 = ' hide';
+    }
+    /**
+     * Generate output
+     */
+    $retval  = "<!-- LIST OF " . PMA_RTE_getWord('docu') . " START -->\n";
+    $retval .= "<fieldset>\n";
+    $retval .= "    <legend>\n";
+    $retval .= "        " . PMA_RTE_getWord('title') . "\n";
+    $retval .= "        " . PMA_showMySQLDocu('SQL-Syntax', PMA_RTE_getWord('docu')) . "\n";
+    $retval .= "    </legend>\n";
+    $retval .= "    <div class='$class1' id='nothing2display'>\n";
+    $retval .= "      " . PMA_RTE_getWord('nothing') . "\n";
+    $retval .= "    </div>\n";
+    $retval .= "    <table class='data$class2'>\n";
+    $retval .= "        <!-- TABLE HEADERS -->\n";
+    $retval .= "        <tr>\n";
+    switch ($type) {
+    case 'routine':
+        $retval .= "            <th>" . __('Name') . "</th>\n";
+        $retval .= "            <th colspan='4'>" . __('Action') . "</th>\n";
+        $retval .= "            <th>" . __('Type') . "</th>\n";
+        $retval .= "            <th>" . __('Returns') . "</th>\n";
+        break;
+    case 'trigger':
+        $retval .= "            <th>" . __('Name') . "</th>\n";
+        $retval .= "            <th>" . __('Table') . "</th>\n";
+        $retval .= "            <th colspan='3'>" . __('Action') . "</th>\n";
+        $retval .= "            <th>" . __('Time') . "</th>\n";
+        $retval .= "            <th>" . __('Event') . "</th>\n";
+        break;
+    case 'event':
+        $retval .= "            <th>" . __('Name') . "</th>\n";
+        $retval .= "            <th>" . __('Status') . "</th>\n";
+        $retval .= "            <th colspan='3'>" . __('Action') . "</th>\n";
+        $retval .= "            <th>" . __('Type') . "</th>\n";
+        break;
+    default:
+        break;
+    }
+    $retval .= "        </tr>\n";
+    $retval .= "        <!-- TABLE DATA -->\n";
+    $ct = 0;
+    foreach ($items as $item) {
+        $rowclass = ($ct % 2 == 0) ? 'even' : 'odd';
+        if ($GLOBALS['is_ajax_request']) {
+            $rowclass .= ' ajaxInsert hide';
+        }
+        // Get each row from the correct function
+        switch ($type) {
+        case 'routine':
+            $retval .= PMA_RTN_getRowForList($item, $rowclass);
+            break;
+        case 'trigger':
+            $retval .= PMA_TRI_getRowForList($item, $rowclass);
+            break;
+        case 'event':
+            $retval .= PMA_EVN_getRowForList($item, $rowclass);
+            break;
+        default:
+            break;
+        }
+        $ct++;
+    }
+    $retval .= "    </table>\n";
+    $retval .= "</fieldset>\n";
+    $retval .= "<!-- LIST OF " . PMA_RTE_getWord('docu') . " END -->\n";
+
+    return $retval;
+} // end PMA_RTE_getList()
+
+/**
+ * Creates the contents for a row in the list of routines
+ *
+ * @param    array    $routine    An array of routine data
+ * @param    string   $rowclass   Empty or one of ['even'|'odd']
+ *
+ * @return   string   HTML code of a row for the list of routines
+ */
+function PMA_RTN_getRowForList($routine, $rowclass = '')
+{
+    global $ajax_class, $url_query, $db, $titles;
+
+    $sql_drop = sprintf('DROP %s IF EXISTS %s',
+                         $routine['ROUTINE_TYPE'],
+                         PMA_backquote($routine['SPECIFIC_NAME']));
+
+
+    $retval  = "        <tr class='noclick $rowclass'>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                <span class='drop_sql hide'>$sql_drop</span>\n";
+    $retval .= "                <strong>\n";
+    $retval .= "                    " . htmlspecialchars($routine['SPECIFIC_NAME']) . "\n";
+    $retval .= "                </strong>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    if ($routine['ROUTINE_DEFINITION'] !== null
+        && PMA_currentUserHasPrivilege('ALTER ROUTINE', $db)
+        && PMA_currentUserHasPrivilege('CREATE ROUTINE', $db)
+    ) {
+        $retval .= '                <a ' . $ajax_class['edit']
+                                         . ' href="db_routines.php?'
+                                         . $url_query
+                                         . '&edit_item=1'
+                                         . '&item_name=' . urlencode($routine['SPECIFIC_NAME'])
+                                         . '">' . $titles['Edit'] . "</a>\n";
+    } else {
+        $retval .= "                {$titles['NoEdit']}\n";
+    }
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    if ($routine['ROUTINE_DEFINITION'] !== null
+        && PMA_currentUserHasPrivilege('EXECUTE', $db)
+    ) {
+        // Check if he routine has any input parameters. If it does,
+        // we will show a dialog to get values for these parameters,
+        // otherwise we can execute it directly.
+        $routine_details = PMA_RTN_getDataFromName(
+            $routine['SPECIFIC_NAME'],
+            false
+        );
+        if ($routine !== false) {
+            $execute_action = 'execute_routine';
+            for ($i=0; $i<$routine_details['item_num_params']; $i++) {
+                if ($routine_details['item_type'] == 'PROCEDURE'
+                    && $routine_details['item_param_dir'][$i] == 'OUT'
+                ) {
+                    continue;
+                }
+                $execute_action = 'execute_dialog';
+                break;
+            }
+            $retval .= '                <a ' . $ajax_class['exec']
+                                             . ' href="db_routines.php?'
+                                             . $url_query
+                                             . '&' . $execute_action . '=1'
+                                             . '&item_name=' . urlencode($routine['SPECIFIC_NAME'])
+                                             . '">' . $titles['Execute'] . "</a>\n";
+        }
+    } else {
+        $retval .= "                {$titles['NoExecute']}\n";
+    }
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= '                <a ' . $ajax_class['export']
+                                     . ' href="db_routines.php?'
+                                     . $url_query
+                                     . '&export_item=1'
+                                     . '&item_name=' . urlencode($routine['SPECIFIC_NAME'])
+                                     . '">' . $titles['Export'] . "</a>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    if (PMA_currentUserHasPrivilege('EVENT', $db)) {
+        $retval .= '                <a ' . $ajax_class['drop']
+                                         . ' href="sql.php?'
+                                         . $url_query
+                                         . '&sql_query=' . urlencode($sql_drop)
+                                         . '&goto=db_events.php' . urlencode("?db={$db}")
+                                         . '" >' . $titles['Drop'] . "</a>\n";
+    } else {
+        $retval .= "                {$titles['NoDrop']}\n";
+    }
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                 {$routine['ROUTINE_TYPE']}\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                " . htmlspecialchars($routine['DTD_IDENTIFIER']) . "\n";
+    $retval .= "            </td>\n";
+    $retval .= "        </tr>\n";
+
+    return $retval;
+} // end PMA_RTN_getRowForList()
+
+/**
+ * Creates the contents for a row in the list of triggers
+ *
+ * @param    array    $trigger    An array of routine data
+ * @param    string   $rowclass   Empty or one of ['even'|'odd']
+ *
+ * @return   string   HTML code of a cell for the list of triggers
+ */
+function PMA_TRI_getRowForList($trigger, $rowclass = '')
+{
+    global $ajax_class, $url_query, $db, $table, $titles;
+
+    $retval  = "        <tr class='noclick $rowclass'>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                <span class='drop_sql hide'>{$trigger['drop']}</span>\n";
+    $retval .= "                <strong>\n";
+    $retval .= "                    " . htmlspecialchars($trigger['name']) . "\n";
+    $retval .= "                </strong>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                <a href='db_triggers.php?db={$db}"
+                                 . "&table={$trigger['table']}'>"
+                                 . $trigger['table'] . "</a>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    if (PMA_currentUserHasPrivilege('TRIGGER', $db, $table)) {
+        $retval .= '                <a ' . $ajax_class['edit']
+                                         . ' href="db_triggers.php?'
+                                         . $url_query
+                                         . '&edit_item=1'
+                                         . '&item_name=' . urlencode($trigger['name'])
+                                         . '">' . $titles['Edit'] . "</a>\n";
+    } else {
+        $retval .= "                {$titles['NoEdit']}\n";
+    }
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= '                    <a ' . $ajax_class['export']
+                                         . ' href="db_triggers.php?'
+                                         . $url_query
+                                         . '&export_item=1'
+                                         . '&item_name=' . urlencode($trigger['name'])
+                                         . '">' . $titles['Export'] . "</a>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    if (PMA_currentUserHasPrivilege('TRIGGER', $db)) {
+        $retval .= '                <a ' . $ajax_class['drop']
+                                         . ' href="sql.php?'
+                                         . $url_query
+                                         . '&sql_query=' . urlencode($trigger['drop'])
+                                         . '&goto=db_triggers.php' . urlencode("?db={$db}")
+                                         . '" >' . $titles['Drop'] . "</a>\n";
+    } else {
+        $retval .= "                {$titles['NoDrop']}\n";
+    }
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                 {$trigger['action_timing']}\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                 {$trigger['event_manipulation']}\n";
+    $retval .= "            </td>\n";
+    $retval .= "        </tr>\n";
+
+    return $retval;
+} // end PMA_TRI_getRowForList()
+
+/**
+ * Creates the contents for a row in the list of events
+ *
+ * @param    array    $event      An array of routine data
+ * @param    string   $rowclass   Empty or one of ['even'|'odd']
+ *
+ * @return   string   HTML code of a cell for the list of events
+ */
+function PMA_EVN_getRowForList($event, $rowclass = '')
+{
+    global $ajax_class, $url_query, $db, $titles;
+
+    $sql_drop = sprintf(
+        'DROP EVENT IF EXISTS %s',
+        PMA_backquote($event['EVENT_NAME'])
+    );
+
+    $retval  = "        <tr class='noclick $rowclass'>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                <span class='drop_sql hide'>$sql_drop</span>\n";
+    $retval .= "                <strong>\n";
+    $retval .= "                    " . htmlspecialchars($event['EVENT_NAME']) . "\n";
+    $retval .= "                </strong>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                 {$event['STATUS']}\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    if (PMA_currentUserHasPrivilege('EVENT', $db)) {
+        $retval .= '                <a ' . $ajax_class['edit']
+                                         . ' href="db_events.php?'
+                                         . $url_query
+                                         . '&edit_item=1'
+                                         . '&item_name=' . urlencode($event['EVENT_NAME'])
+                                         . '">' . $titles['Edit'] . "</a>\n";
+    } else {
+        $retval .= "                {$titles['NoEdit']}\n";
+    }
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= '                <a ' . $ajax_class['export']
+                                     . ' href="db_events.php?'
+                                     . $url_query
+                                     . '&export_item=1'
+                                     . '&item_name=' . urlencode($event['EVENT_NAME'])
+                                     . '">' . $titles['Export'] . "</a>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    if (PMA_currentUserHasPrivilege('EVENT', $db)) {
+        $retval .= '                <a ' . $ajax_class['drop']
+                                         . ' href="sql.php?'
+                                         . $url_query
+                                         . '&sql_query=' . urlencode($sql_drop)
+                                         . '&goto=db_events.php' . urlencode("?db={$db}")
+                                         . '" >' . $titles['Drop'] . "</a>\n";
+    } else {
+        $retval .= "                {$titles['NoDrop']}\n";
+    }
+    $retval .= "            </td>\n";
+    $retval .= "            <td>\n";
+    $retval .= "                 {$event['EVENT_TYPE']}\n";
+    $retval .= "            </td>\n";
+    $retval .= "        </tr>\n";
+
+    return $retval;
+} // end PMA_EVN_getRowForList()
+
+?>
diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php
new file mode 100644
index 0000000..deae1d2
--- /dev/null
+++ b/libraries/rte/rte_main.inc.php
@@ -0,0 +1,135 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Common code for Routines, Triggers and Events.
+ *
+ * @package phpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+    exit;
+}
+
+/**
+ * Include all other files that are common
+ * to routines, triggers and events.
+ */
+require_once './libraries/rte/rte_export.lib.php';
+require_once './libraries/rte/rte_list.lib.php';
+require_once './libraries/rte/rte_footer.lib.php';
+
+if ($GLOBALS['is_ajax_request'] != true) {
+    /**
+     * Displays the header and tabs
+     */
+    if (! empty($table) && in_array($table, PMA_DBI_get_tables($db))) {
+        require_once './libraries/tbl_common.php';
+        require_once './libraries/tbl_links.inc.php';
+    } else {
+        $table = '';
+        require_once './libraries/db_common.inc.php';
+        require_once './libraries/db_info.inc.php';
+    }
+} else {
+    /**
+     * Since we did not include some libraries, we need
+     * to manually select the required database and
+     * create the missing $url_query variable
+     */
+    if (strlen($db)) {
+        PMA_DBI_select_db($db);
+        if (! isset($url_query)) {
+            $url_query = PMA_generate_common_url($db, $table);
+        }
+    }
+}
+
+/**
+ * Generate the conditional classes that will
+ * be used to attach jQuery events to links
+ */
+$ajax_class = array('add'    => '',
+                    'edit'   => '',
+                    'exec'   => '',
+                    'drop'   => '',
+                    'export' => '');
+if ($GLOBALS['cfg']['AjaxEnable']) {
+    $ajax_class = array('add'    => 'class="ajax_add_anchor"',
+                        'edit'   => 'class="ajax_edit_anchor"',
+                        'exec'   => 'class="ajax_exec_anchor"',
+                        'drop'   => 'class="ajax_drop_anchor"',
+                        'export' => 'class="ajax_export_anchor"');
+}
+
+/**
+ * Create labels for the list
+ */
+$titles = PMA_buildActionTitles();
+
+/**
+ * Keep a list of errors that occured while
+ * processing an 'Add' or 'Edit' operation.
+ */
+$errors = array();
+
+// Some definitions for triggers
+$action_timings      = array('BEFORE',
+                             'AFTER');
+$event_manipulations = array('INSERT',
+                             'UPDATE',
+                             'DELETE');
+
+// Some definitions for routines
+$param_directions    = array('IN',
+                             'OUT',
+                             'INOUT');
+$param_opts_num      = array('UNSIGNED',
+                             'ZEROFILL',
+                             'UNSIGNED ZEROFILL');
+$param_sqldataaccess = array('NO SQL',
+                             'CONTAINS SQL',
+                             'READS SQL DATA',
+                             'MODIFIES SQL DATA');
+
+// Some definitions for events
+$event_status        = array(
+                           'query'   => array('ENABLE',
+                                              'DISABLE',
+                                              'DISABLE ON SLAVE'),
+                           'display' => array('ENABLED',
+                                              'DISABLED',
+                                              'SLAVESIDE_DISABLED')
+                       );
+$event_type          = array('RECURRING',
+                             'ONE TIME');
+$event_interval      = array('YEAR',
+                             'QUARTER',
+                             'MONTH',
+                             'DAY',
+                             'HOUR',
+                             'MINUTE',
+                             'WEEK',
+                             'SECOND',
+                             'YEAR_MONTH',
+                             'DAY_HOUR',
+                             'DAY_MINUTE',
+                             'DAY_SECOND',
+                             'HOUR_MINUTE',
+                             'HOUR_SECOND',
+                             'MINUTE_SECOND');
+/**
+ * The below function is defined in rte_routines.lib.php,
+ * rte_triggers.lib.php and rte_events.lib.php
+ *
+ * The appropriate function will now be called based on which one
+ * of these files was included earlier in the top-level folder
+ */
+PMA_RTE_main();
+
+/**
+ * Display the footer, if necessary
+ */
+if ($GLOBALS['is_ajax_request'] != true) {
+    require './libraries/footer.inc.php';
+}
+
+?>
diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php
new file mode 100644
index 0000000..eb6ee4e
--- /dev/null
+++ b/libraries/rte/rte_routines.lib.php
@@ -0,0 +1,1494 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Functions for routine management.
+ *
+ * @package phpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+    exit;
+}
+
+/**
+ * This function is defined in: rte_routines.lib.php, rte_triggers.lib.php and
+ * rte_events.lib.php. It is used to retreive some language strings that are
+ * used in functionalities that are common to routines, triggers and events.
+ *
+ * @param   string  $index   The index of the string to get
+ *
+ * @return  string  The requested string or an empty string, if not available
+ */
+function PMA_RTE_getWord($index)
+{
+    $words = array(
+        'add'       => __('Add routine'),
+        'docu'      => 'STORED_ROUTINES',
+        'export'    => __('Export of routine %s'),
+        'human'     => __('routine'),
+        'no_create' => __('You do not have the necessary privileges to create a new routine'),
+        'not_found' => __('No routine with name %1$s found in database %2$s'),
+        'nothing'   => __('There are no routines to display.'),
+        'title'     => __('Routines'),
+    );
+    return isset($words[$index]) ? $words[$index] : '';
+} // end PMA_RTE_getWord()
+
+/**
+ * Main function for the routines functionality
+ */
+function PMA_RTE_main()
+{
+    global $db;
+
+    /**
+     * Process all requests
+     */
+    PMA_RTN_handleEditor();
+    PMA_RTN_handleExecute();
+    PMA_RTN_handleExport();
+    /**
+     * Display a list of available routines
+     */
+    $columns  = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`, ";
+    $columns .= "`DTD_IDENTIFIER`, `ROUTINE_DEFINITION`";
+    $where    = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "'";
+    $items    = PMA_DBI_fetch_result(
+        "SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE $where;"
+    );
+    echo PMA_RTE_getList('routine', $items);
+    /**
+     * Display the form for adding a new routine, if the user has the privileges.
+     */
+    echo PMA_RTN_getFooterLinks();
+    /**
+     * Display a warning for users with PHP's old "mysql" extension.
+     */
+    if ($GLOBALS['cfg']['Server']['extension'] === 'mysql') {
+        trigger_error(
+            __('You are using PHP\'s deprecated \'mysql\' extension, '
+            . 'which is not capable of handling multi queries. '
+            . '<b>The execution of some stored routines may fail!</b> '
+            . 'Please use the improved \'mysqli\' extension to '
+            . 'avoid any problems.'),
+            E_USER_WARNING
+        );
+    }
+} // end PMA_RTE_main()
+
+/**
+ * This function parses a string containing one parameter of a routine,
+ * as returned by PMA_RTN_parseAllParameters() and returns an array containing
+ * the information about this parameter.
+ *
+ * @param   string  $value    A string containing one parameter of a routine
+ *
+ * @return  array             Parsed information about the input parameter
+ */
+function PMA_RTN_parseOneParameter($value)
+{
+    global $param_directions;
+
+    $retval = array(0 => '',
+                    1 => '',
+                    2 => '',
+                    3 => '',
+                    4 => '');
+    $parsed_param = PMA_SQP_parse($value);
+    $pos = 0;
+    if (in_array(strtoupper($parsed_param[$pos]['data']), $param_directions)) {
+        $retval[0] = strtoupper($parsed_param[0]['data']);
+        $pos++;
+    }
+    if ($parsed_param[$pos]['type'] == 'alpha_identifier'
+        || $parsed_param[$pos]['type'] == 'quote_backtick'
+    ) {
+        $retval[1] = PMA_unQuote($parsed_param[$pos]['data']);
+        $pos++;
+    }
+    $depth = 0;
+    $param_length = '';
+    $param_opts = array();
+    for ($i=$pos; $i<$parsed_param['len']; $i++) {
+        if (($parsed_param[$i]['type'] == 'alpha_columnType'
+            || $parsed_param[$i]['type'] == 'alpha_functionName') // "CHAR" seems to be mistaken for a function by the parser
+            && $depth == 0
+        ) {
+            $retval[2] = strtoupper($parsed_param[$i]['data']);
+        } else if ($parsed_param[$i]['type'] == 'punct_bracket_open_round' && $depth == 0) {
+            $depth = 1;
+        } else if ($parsed_param[$i]['type'] == 'punct_bracket_close_round' && $depth == 1) {
+            $depth = 0;
+        } else if ($depth == 1) {
+            $param_length .= $parsed_param[$i]['data'];
+        } else if ($parsed_param[$i]['type'] == 'alpha_reservedWord' && strtoupper($parsed_param[$i]['data']) == 'CHARSET' && $depth == 0) {
+            if ($parsed_param[$i+1]['type'] == 'alpha_charset' || $parsed_param[$i+1]['type'] == 'alpha_identifier') {
+                $param_opts[] = strtolower($parsed_param[$i+1]['data']);
+            }
+        } else if ($parsed_param[$i]['type'] == 'alpha_columnAttrib' && $depth == 0) {
+            $param_opts[] = strtoupper($parsed_param[$i]['data']);
+        }
+    }
+    $retval[3] = $param_length;
+    sort($param_opts);
+    $retval[4] = implode(' ', $param_opts);
+
+    return $retval;
+} // end PMA_RTN_parseOneParameter()
+
+/**
+ * This function looks through the contents of a parsed
+ * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts
+ * information about the routine's parameters.
+ *
+ * @param   array   $parsed_query  Parsed query, returned by by PMA_SQP_parse()
+ * @param   string  $routine_type  Routine type: 'PROCEDURE' or 'FUNCTION'
+ *
+ * @return  array   Information about the parameteres of a routine.
+ */
+function PMA_RTN_parseAllParameters($parsed_query, $routine_type)
+{
+    global $param_directions;
+
+    $retval = array();
+    $retval['num'] = 0;
+
+    // First get the list of parameters from the query
+    $buffer = '';
+    $params = array();
+    $fetching = false;
+    $depth = 0;
+    for ($i=0; $i<$parsed_query['len']; $i++) {
+        if ($parsed_query[$i]['type'] == 'alpha_reservedWord' && $parsed_query[$i]['data'] == $routine_type) {
+            $fetching = true;
+        } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_bracket_open_round') {
+            $depth++;
+            if ($depth > 1) {
+                $buffer .= $parsed_query[$i]['data'] . ' ';
+            }
+        } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_bracket_close_round') {
+            $depth--;
+            if ($depth > 0) {
+                $buffer .= $parsed_query[$i]['data'] . ' ';
+            } else {
+                break;
+            }
+        } else if ($parsed_query[$i]['type'] == 'punct_listsep' && $depth == 1) {
+            $params[] = $buffer;
+            $retval['num']++;
+            $buffer = '';
+        } else if ($fetching == true && $depth > 0) {
+            $buffer .= $parsed_query[$i]['data'] . ' ';
+        }
+    }
+    if (! empty($buffer)) {
+        $params[] = $buffer;
+        $retval['num']++;
+    }
+    // Now parse each parameter individually
+    foreach ($params as $key => $value) {
+        list($retval['dir'][],
+             $retval['name'][],
+             $retval['type'][],
+             $retval['length'][],
+             $retval['opts'][]) = PMA_RTN_parseOneParameter($value);
+    }
+    // Since some indices of $retval may be still undefined, we fill
+    // them each with an empty array to avoid E_ALL errors in PHP.
+    foreach (array('dir', 'name', 'type', 'length', 'opts') as $key => $index) {
+        if (! isset($retval[$index])) {
+            $retval[$index] = array();
+        }
+    }
+
+    return $retval;
+} // end PMA_RTN_parseAllParameters()
+
+/**
+ * This function looks through the contents of a parsed
+ * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts
+ * information about the routine's definer.
+ *
+ * @param   array   $parsed_query   Parsed query, returned by PMA_SQP_parse()
+ *
+ * @return  string  The definer of a routine.
+ */
+function PMA_RTN_parseRoutineDefiner($parsed_query)
+{
+    $retval = '';
+    $fetching = false;
+    for ($i=0; $i<$parsed_query['len']; $i++) {
+        if ($parsed_query[$i]['type'] == 'alpha_reservedWord' && $parsed_query[$i]['data'] == 'DEFINER') {
+            $fetching = true;
+        } else if ($fetching == true && ($parsed_query[$i]['type'] != 'quote_backtick' && substr($parsed_query[$i]['type'], 0, 5) != 'punct')) {
+            break;
+        } else if ($fetching == true && $parsed_query[$i]['type'] == 'quote_backtick') {
+            $retval .= PMA_unQuote($parsed_query[$i]['data']);
+        } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_user') {
+            $retval .= $parsed_query[$i]['data'];
+        }
+    }
+    return $retval;
+} // end PMA_RTN_parseRoutineDefiner()
+
+/**
+ * Handles editor requests for adding or editing an item
+ */
+function PMA_RTN_handleEditor()
+{
+    global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $cfg, $errors;
+
+    if (! empty($_REQUEST['editor_process_add'])
+        || ! empty($_REQUEST['editor_process_edit'])
+    ) {
+        /**
+         * Handle a request to create/edit a routine
+         */
+        $sql_query = '';
+        $routine_query = PMA_RTN_getQueryFromRequest();
+        if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest()
+            // Execute the created query
+            if (! empty($_REQUEST['editor_process_edit'])) {
+                if (! in_array($_REQUEST['item_original_type'], array('PROCEDURE', 'FUNCTION'))) {
+                    $errors[] = sprintf(__('Invalid routine type: "%s"'), htmlspecialchars($_REQUEST['item_original_type']));
+                } else {
+                    // Backup the old routine, in case something goes wrong
+                    $create_routine = PMA_DBI_get_definition($db, $_REQUEST['item_original_type'], $_REQUEST['item_original_name']);
+                    $drop_routine = "DROP {$_REQUEST['item_original_type']} " . PMA_backquote($_REQUEST['item_original_name']) . ";\n";
+                    $result = PMA_DBI_try_query($drop_routine);
+                    if (! $result) {
+                        $errors[] = sprintf(__('The following query has failed: "%s"'), $drop_routine) . '<br />'
+                                          . __('MySQL said: ') . PMA_DBI_getError(null);
+                    } else {
+                        $result = PMA_DBI_try_query($routine_query);
+                        if (! $result) {
+                            $errors[] = sprintf(__('The following query has failed: "%s"'), $routine_query) . '<br />'
+                                              . __('MySQL said: ') . PMA_DBI_getError(null);
+                            // We dropped the old routine, but were unable to create the new one
+                            // Try to restore the backup query
+                            $result = PMA_DBI_try_query($create_routine);
+                            if (! $result) {
+                                // OMG, this is really bad! We dropped the query, failed to create a new one
+                                // and now even the backup query does not execute!
+                                // This should not happen, but we better handle this just in case.
+                                $errors[] = __('Sorry, we failed to restore the dropped routine.') . '<br />'
+                                                  . __('The backed up query was:') . "\"$create_routine\"" . '<br />'
+                                                  . __('MySQL said: ') . PMA_DBI_getError(null);
+                            }
+                        } else {
+                            $message = PMA_Message::success(__('Routine %1$s has been modified.'));
+                            $message->addParam(PMA_backquote($_REQUEST['item_name']));
+                            $sql_query = $drop_routine . $routine_query;
+                        }
+                    }
+                }
+            } else {
+                // 'Add a new routine' mode
+                $result = PMA_DBI_try_query($routine_query);
+                if (! $result) {
+                    $errors[] = sprintf(__('The following query has failed: "%s"'), $routine_query) . '<br /><br />'
+                                      . __('MySQL said: ') . PMA_DBI_getError(null);
+                } else {
+                    $message = PMA_Message::success(__('Routine %1$s has been created.'));
+                    $message->addParam(PMA_backquote($_REQUEST['item_name']));
+                    $sql_query = $routine_query;
+                }
+            }
+        }
+
+        if (count($errors)) {
+            $message = PMA_Message::error(__('<b>One or more errors have occured while processing your request:</b>'));
+            $message->addString('<ul>');
+            foreach ($errors as $num => $string) {
+                $message->addString('<li>' . $string . '</li>');
+            }
+            $message->addString('</ul>');
+        }
+
+        $output = PMA_showMessage($message, $sql_query);
+        if ($GLOBALS['is_ajax_request']) {
+            $extra_data = array();
+            if ($message->isSuccess()) {
+                $columns  = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`, `DTD_IDENTIFIER`, `ROUTINE_DEFINITION`";
+                $where    = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' AND ROUTINE_NAME='" . PMA_sqlAddSlashes($_REQUEST['item_name']) . "'";
+                $routine  = PMA_DBI_fetch_single_row("SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE $where;");
+                $extra_data['name']    = htmlspecialchars(strtoupper($_REQUEST['item_name']));
+                $extra_data['new_row'] = PMA_RTN_getRowForList($routine);
+                $extra_data['insert']  = ! empty($routine);
+                $response = $output;
+            } else {
+                $response = $message;
+            }
+            PMA_ajaxResponse($response, $message->isSuccess(), $extra_data);
+        }
+    }
+
+    /**
+     * Display a form used to add/edit a routine, if necessary
+     */
+    if (count($errors) || ( empty($_REQUEST['editor_process_add']) && empty($_REQUEST['editor_process_edit'])
+        && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item'])
+        || ! empty($_REQUEST['routine_addparameter']) || ! empty($_REQUEST['routine_removeparameter'])
+        || ! empty($_REQUEST['routine_changetype']))) // FIXME: this must be simpler than that
+    ) {
+        // Handle requests to add/remove parameters and changing routine type
+        // This is necessary when JS is disabled
+        $operation = '';
+        if (! empty($_REQUEST['routine_addparameter'])) {
+            $operation = 'add';
+        } else if (! empty($_REQUEST['routine_removeparameter'])) {
+            $operation = 'remove';
+        } else if (! empty($_REQUEST['routine_changetype'])) {
+            $operation = 'change';
+        }
+        // Get the data for the form (if any)
+        if (! empty($_REQUEST['add_item'])) {
+            $title = __("Create routine");
+            $routine = PMA_RTN_getDataFromRequest();
+            $mode = 'add';
+        } else if (! empty($_REQUEST['edit_item'])) {
+            $title = __("Edit routine");
+            if (! $operation && ! empty($_REQUEST['item_name']) && empty($_REQUEST['editor_process_edit'])) {
+                $routine = PMA_RTN_getDataFromName($_REQUEST['item_name']);
+                if ($routine !== false) {
+                    $routine['item_original_name'] = $routine['item_name'];
+                    $routine['item_original_type'] = $routine['item_type'];
+                }
+            } else {
+                $routine = PMA_RTN_getDataFromRequest();
+            }
+            $mode = 'edit';
+        }
+        if ($routine !== false) {
+            // Show form
+            $editor = PMA_RTN_getEditorForm($mode, $operation, $routine);
+            if ($GLOBALS['is_ajax_request']) {
+                $template   = PMA_RTN_getParameterRow();
+                $extra_data = array('title' => $title,
+                                    'param_template' => $template,
+                                    'type' => $routine['item_type']);
+                PMA_ajaxResponse($editor, true, $extra_data);
+            }
+            echo "\n\n<h2>$title</h2>\n\n$editor";
+            require './libraries/footer.inc.php';
+            // exit;
+        } else {
+            $message  = __('Error in processing request') . ' : ';
+            $message .= sprintf(
+                PMA_RTE_getWord('not_found'),
+                htmlspecialchars(PMA_backquote($_REQUEST['item_name'])),
+                htmlspecialchars(PMA_backquote($db))
+            );
+            $message = PMA_message::error($message);
+            if ($GLOBALS['is_ajax_request']) {
+                PMA_ajaxResponse($message, false);
+            } else {
+                $message->display();
+            }
+        }
+    }
+} // end PMA_RTN_handleEditor()
+
+/**
+ * This function will generate the values that are required to
+ * complete the editor form. It is especially necessary to handle
+ * the 'Add another parameter', 'Remove last parameter' and
+ * 'Change routine type' functionalities when JS is disabled.
+ *
+ * @return  array    Data necessary to create the routine editor.
+ */
+function PMA_RTN_getDataFromRequest()
+{
+    global $_REQUEST, $param_directions, $param_sqldataaccess;
+
+    $retval = array();
+    $indices = array('item_name',
+                     'item_original_name',
+                     'item_returnlength',
+                     'item_returnopts_num',
+                     'item_returnopts_text',
+                     'item_definition',
+                     'item_comment',
+                     'item_definer');
+    foreach ($indices as $key => $index) {
+        $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : '';
+    }
+
+    $retval['item_type']         = 'PROCEDURE';
+    $retval['item_type_toggle']  = 'FUNCTION';
+    if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'FUNCTION') {
+        $retval['item_type']         = 'FUNCTION';
+        $retval['item_type_toggle']  = 'PROCEDURE';
+    }
+    $retval['item_original_type'] = 'PROCEDURE';
+    if (isset($_REQUEST['item_original_type'])
+        && $_REQUEST['item_original_type'] == 'FUNCTION'
+    ) {
+        $retval['item_original_type'] = 'FUNCTION';
+    }
+    $retval['item_num_params']      = 0;
+    $retval['item_param_dir']       = array();
+    $retval['item_param_name']      = array();
+    $retval['item_param_type']      = array();
+    $retval['item_param_length']    = array();
+    $retval['item_param_opts_num']  = array();
+    $retval['item_param_opts_text'] = array();
+    if (isset($_REQUEST['item_param_name'])
+        && isset($_REQUEST['item_param_type'])
+        && isset($_REQUEST['item_param_length'])
+        && isset($_REQUEST['item_param_opts_num'])
+        && isset($_REQUEST['item_param_opts_text'])
+        && is_array($_REQUEST['item_param_name'])
+        && is_array($_REQUEST['item_param_type'])
+        && is_array($_REQUEST['item_param_length'])
+        && is_array($_REQUEST['item_param_opts_num'])
+        && is_array($_REQUEST['item_param_opts_text'])
+    ) {
+        if ($_REQUEST['item_type'] == 'PROCEDURE') {
+            $temp_num_params = 0;
+            $retval['item_param_dir'] = $_REQUEST['item_param_dir'];
+            foreach ($retval['item_param_dir'] as $key => $value) {
+                if (! in_array($value, $param_directions, true)) {
+                    $retval['item_param_dir'][$key] = '';
+                }
+                $retval['item_num_params']++;
+            }
+            if ($temp_num_params > $retval['item_num_params']) {
+                $retval['item_num_params'] = $temp_num_params;
+            }
+        }
+        $temp_num_params = 0;
+        $retval['item_param_name'] = $_REQUEST['item_param_name'];
+        foreach ($retval['item_param_name'] as $key => $value) {
+            $retval['item_param_name'][$key] = $value;
+            $temp_num_params++;
+        }
+        if ($temp_num_params > $retval['item_num_params']) {
+            $retval['item_num_params'] = $temp_num_params;
+        }
+        $temp_num_params = 0;
+        $retval['item_param_type'] = $_REQUEST['item_param_type'];
+        foreach ($retval['item_param_type'] as $key => $value) {
+            if (! in_array($value, PMA_getSupportedDatatypes(), true)) {
+                $retval['item_param_type'][$key] = '';
+            }
+            $temp_num_params++;
+        }
+        if ($temp_num_params > $retval['item_num_params']) {
+            $retval['item_num_params'] = $temp_num_params;
+        }
+        $temp_num_params = 0;
+        $retval['item_param_length'] = $_REQUEST['item_param_length'];
+        foreach ($retval['item_param_length'] as $key => $value) {
+            $retval['item_param_length'][$key] = $value;
+            $temp_num_params++;
+        }
+        if ($temp_num_params > $retval['item_num_params']) {
+            $retval['item_num_params'] = $temp_num_params;
+        }
+        $temp_num_params = 0;
+        $retval['item_param_opts_num'] = $_REQUEST['item_param_opts_num'];
+        foreach ($retval['item_param_opts_num'] as $key => $value) {
+            $retval['item_param_opts_num'][$key] = $value;
+            $temp_num_params++;
+        }
+        if ($temp_num_params > $retval['item_num_params']) {
+            $retval['item_num_params'] = $temp_num_params;
+        }
+        $temp_num_params = 0;
+        $retval['item_param_opts_text'] = $_REQUEST['item_param_opts_text'];
+        foreach ($retval['item_param_opts_text'] as $key => $value) {
+            $retval['item_param_opts_text'][$key] = $value;
+            $temp_num_params++;
+        }
+        if ($temp_num_params > $retval['item_num_params']) {
+            $retval['item_num_params'] = $temp_num_params;
+        }
+    }
+    $retval['item_returntype'] = '';
+    if (isset($_REQUEST['item_returntype'])
+        && in_array($_REQUEST['item_returntype'], PMA_getSupportedDatatypes())
+    ) {
+        $retval['item_returntype'] = $_REQUEST['item_returntype'];
+    }
+
+    $retval['item_isdeterministic'] = '';
+    if (isset($_REQUEST['item_isdeterministic'])
+        && strtolower($_REQUEST['item_isdeterministic']) == 'on'
+    ) {
+        $retval['item_isdeterministic'] = " checked='checked'";
+    }
+    $retval['item_securitytype_definer'] = '';
+    $retval['item_securitytype_invoker'] = '';
+    if (isset($_REQUEST['item_securitytype'])) {
+        if ($_REQUEST['item_securitytype'] === 'DEFINER') {
+            $retval['item_securitytype_definer'] = " selected='selected'";
+        } else if ($_REQUEST['item_securitytype'] === 'INVOKER') {
+            $retval['item_securitytype_invoker'] = " selected='selected'";
+        }
+    }
+    $retval['item_sqldataaccess'] = '';
+    if (isset($_REQUEST['item_sqldataaccess'])
+        && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess, true)
+    ) {
+        $retval['item_sqldataaccess'] = $_REQUEST['item_sqldataaccess'];
+    }
+
+    return $retval;
+} // end function PMA_RTN_getDataFromRequest()
+
+/**
+ * This function will generate the values that are required to complete
+ * the "Edit routine" form given the name of a routine.
+ *
+ * @param   string   $name   The name of the routine.
+ * @param   bool     $all    Whether to return all data or just
+ *                           the info about parameters.
+ *
+ * @return  array    Data necessary to create the routine editor.
+ */
+function PMA_RTN_getDataFromName($name, $all = true)
+{
+    global $param_directions, $param_sqldataaccess, $db;
+
+    $retval  = array();
+
+    // Build and execute the query
+    $fields  = "SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, "
+             . "ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, "
+             . "ROUTINE_COMMENT, SECURITY_TYPE";
+    $where   = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' "
+             . "AND SPECIFIC_NAME='" . PMA_sqlAddSlashes($name) . "'";
+    $query   = "SELECT $fields FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;";
+
+    $routine = PMA_DBI_fetch_single_row($query);
+
+    if (! $routine) {
+        return false;
+    }
+
+    // Get required data
+    $retval['item_name'] = $routine['SPECIFIC_NAME'];
+    $retval['item_type'] = $routine['ROUTINE_TYPE'];
+    $parsed_query = PMA_SQP_parse(
+        PMA_DBI_get_definition(
+            $db,
+            $routine['ROUTINE_TYPE'],
+            $routine['SPECIFIC_NAME']
+        )
+    );
+    $params = PMA_RTN_parseAllParameters($parsed_query, $routine['ROUTINE_TYPE']);
+    $retval['item_num_params']      = $params['num'];
+    $retval['item_param_dir']       = $params['dir'];
+    $retval['item_param_name']      = $params['name'];
+    $retval['item_param_type']      = $params['type'];
+    $retval['item_param_length']    = $params['length'];
+    $retval['item_param_opts_num']  = $params['opts'];
+    $retval['item_param_opts_text'] = $params['opts'];
+
+    // Get extra data
+    if ($all) {
+        if ($retval['item_type'] == 'FUNCTION') {
+            $retval['item_type_toggle'] = 'PROCEDURE';
+        } else {
+            $retval['item_type_toggle'] = 'FUNCTION';
+        }
+        $retval['item_returntype']   = '';
+        $retval['item_returnlength'] = '';
+        $retval['item_returnopts_num']  = '';
+        $retval['item_returnopts_text'] = '';
+        if (! empty($routine['DTD_IDENTIFIER'])) {
+            if (strlen($routine['DTD_IDENTIFIER']) > 63) {
+                // If the DTD_IDENTIFIER string from INFORMATION_SCHEMA is
+                // at least 64 characters, then it may actually have been
+                // chopped because that column is a varchar(64), so we will
+                // parse the output of SHOW CREATE query to get accurate
+                // information about the return variable.
+                $dtd = '';
+                $fetching = false;
+                for ($i=0; $i<$parsed_query['len']; $i++) {
+                    if ($parsed_query[$i]['type'] == 'alpha_reservedWord'
+                        && strtoupper($parsed_query[$i]['data']) == 'RETURNS'
+                    ) {
+                        $fetching = true;
+                    } else if ($fetching == true && $parsed_query[$i]['type'] == 'alpha_reservedWord') {
+                        // We will not be looking for options such as UNSIGNED
+                        // or ZEROFILL because there is no way that a numeric
+                        // field's DTD_IDENTIFIER can be longer than 64
+                        // characters. We can safely assume that the return
+                        // datatype is either ENUM or SET, so we only look
+                        // for CHARSET.
+                        $word = strtoupper($parsed_query[$i]['data']);
+                        if ($word == 'CHARSET'
+                            && ($parsed_query[$i+1]['type'] == 'alpha_charset'
+                            || $parsed_query[$i+1]['type'] == 'alpha_identifier')
+                        ) {
+                            $dtd .= $word . ' ' . $parsed_query[$i+1]['data'];
+                        }
+                        break;
+                    } else if ($fetching == true) {
+                        $dtd .= $parsed_query[$i]['data'] . ' ';
+                    }
+                }
+                $routine['DTD_IDENTIFIER'] = $dtd;
+            }
+            $returnparam = PMA_RTN_parseOneParameter($routine['DTD_IDENTIFIER']);
+            $retval['item_returntype']      = $returnparam[2];
+            $retval['item_returnlength']    = $returnparam[3];
+            $retval['item_returnopts_num']  = $returnparam[4];
+            $retval['item_returnopts_text'] = $returnparam[4];
+        }
+        $retval['item_definer']         = PMA_RTN_parseRoutineDefiner($parsed_query);
+        $retval['item_definition']      = $routine['ROUTINE_DEFINITION'];
+        $retval['item_isdeterministic'] = '';
+        if ($routine['IS_DETERMINISTIC'] == 'YES') {
+            $retval['item_isdeterministic'] = " checked='checked'";
+        }
+        $retval['item_securitytype_definer'] = '';
+        $retval['item_securitytype_invoker'] = '';
+        if ($routine['SECURITY_TYPE'] == 'DEFINER') {
+            $retval['item_securitytype_definer'] = " selected='selected'";
+        } else if ($routine['SECURITY_TYPE'] == 'INVOKER') {
+            $retval['item_securitytype_invoker'] = " selected='selected'";
+        }
+        $retval['item_sqldataaccess'] = $routine['SQL_DATA_ACCESS'];
+        $retval['item_comment']       = $routine['ROUTINE_COMMENT'];
+    }
+
+    return $retval;
+} // PMA_RTN_getDataFromName()
+
+/**
+ * Creates one row for the parameter table used in the routine editor.
+ *
+ * @param   array    $routine    Data for the routine returned by
+ *                               PMA_RTN_getDataFromRequest() or
+ *                               PMA_RTN_getDataFromName()
+ * @param   mixed    $index      Either a numeric index of the row being processed
+ *                               or NULL to create a template row for AJAX request
+ * @param   string   $class      Class used to hide the direction column, if the
+ *                               row is for a stored function.
+ *
+ * @return    string    HTML code of one row of parameter table for the editor.
+ */
+function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '')
+{
+    global $param_directions, $param_opts_num, $titles;
+
+    if ($index === null) {
+        // template row for AJAX request
+        $i = 0;
+        $index = '%s';
+        $drop_class = '';
+        $routine = array(
+            'item_param_dir'       => array(0 => ''),
+            'item_param_name'      => array(0 => ''),
+            'item_param_type'      => array(0 => ''),
+            'item_param_length'    => array(0 => ''),
+            'item_param_opts_num'  => array(0 => ''),
+            'item_param_opts_text' => array(0 => '')
+        );
+    } else if (! empty($routine)) {
+        // regular row for routine editor
+        $drop_class = ' hide';
+        $i = $index;
+    } else {
+        // No input data. This shouldn't happen,
+        // but better be safe than sorry.
+        return '';
+    }
+
+    // Create the output
+    $retval  = "";
+    $retval .= "        <tr>\n";
+    $retval .= "            <td class='routine_direction_cell$class'>\n";
+    $retval .= "                <select name='item_param_dir[$index]'>\n";
+    foreach ($param_directions as $key => $value) {
+        $selected = "";
+        if (! empty($routine['item_param_dir'][$i])
+            && $routine['item_param_dir'][$i] == $value
+        ) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "                    <option$selected>$value</option>\n";
+    }
+    $retval .= "                </select>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td><input name='item_param_name[$index]' type='text'\n";
+    $retval .= "                       value='{$routine['item_param_name'][$i]}' /></td>\n";
+    $retval .= "            <td><select name='item_param_type[$index]'>";
+    $retval .= PMA_getSupportedDatatypes(true, $routine['item_param_type'][$i]) . "\n";
+    $retval .= "            </select></td>\n";
+    $retval .= "            <td><input name='item_param_length[$index]' type='text'\n";
+    $retval .= "                       value='{$routine['item_param_length'][$i]}' /></td>\n";
+    $retval .= "            <td class='hide no_len'>---</td>\n";
+    $retval .= "            <td class='routine_param_opts_text'>\n";
+    $retval .= PMA_generateCharsetDropdownBox(
+        PMA_CSDROPDOWN_CHARSET,
+        "item_param_opts_text[$index]",
+        null,
+        $routine['item_param_opts_text'][$i]
+    );
+    $retval .= "            </td>\n";
+    $retval .= "            <td class='hide no_opts'>---</td>\n";
+    $retval .= "            <td class='routine_param_opts_num'>\n";
+    $retval .= "                <select name='item_param_opts_num[$index]'>\n";
+    $retval .= "                    <option value=''></option>";
+    foreach ($param_opts_num as $key => $value) {
+        $selected = "";
+        if (! empty($routine['item_param_opts_num'][$i])
+            && $routine['item_param_opts_num'][$i] == $value
+        ) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "<option$selected>$value</option>";
+    }
+    $retval .= "\n                </select>\n";
+    $retval .= "            </td>\n";
+    $retval .= "            <td class='routine_param_remove$drop_class'>\n";
+    $retval .= "                <a href='#' class='routine_param_remove_anchor'>\n";
+    $retval .= "                    {$titles['Drop']}\n";
+    $retval .= "                </a>\n";
+    $retval .= "            </td>\n";
+    $retval .= "        </tr>\n";
+
+    return $retval;
+} // end PMA_RTN_getParameterRow()
+
+/**
+ * Displays a form used to add/edit a routine
+ *
+ * @param   string   $mode         If the editor will be used edit a routine
+ *                                 or add a new one: 'edit' or 'add'.
+ * @param   string   $operation    If the editor was previously invoked with
+ *                                 JS turned off, this will hold the name of
+ *                                 the current operation
+ * @param   array    $routine      Data for the routine returned by
+ *                                 PMA_RTN_getDataFromRequest() or
+ *                                 PMA_RTN_getDataFromName()
+ *
+ * @return  string   HTML code for the editor.
+ */
+function PMA_RTN_getEditorForm($mode, $operation, $routine)
+{
+    global $db, $titles, $errors, $param_directions, $param_sqldataaccess, $param_opts_num;
+
+    // Escape special characters
+    $need_escape = array(
+        'item_original_name',
+        'item_name',
+        'item_returnlength',
+        'item_definition',
+        'item_definer',
+        'item_comment'
+    );
+    foreach ($need_escape as $key => $index) {
+        $routine[$index] = htmlentities($routine[$index], ENT_QUOTES);
+    }
+    for ($i=0; $i<$routine['item_num_params']; $i++) {
+        $routine['item_param_name'][$i]   = htmlentities(
+            $routine['item_param_name'][$i],
+            ENT_QUOTES
+        );
+        $routine['item_param_length'][$i] = htmlentities(
+            $routine['item_param_length'][$i],
+            ENT_QUOTES
+        );
+    }
+
+    // Handle some logic first
+    if ($operation == 'change') {
+        if ($routine['item_type'] == 'PROCEDURE') {
+            $routine['item_type']        = 'FUNCTION';
+            $routine['item_type_toggle'] = 'PROCEDURE';
+        } else {
+            $routine['item_type']        = 'PROCEDURE';
+            $routine['item_type_toggle'] = 'FUNCTION';
+        }
+    } else if ($operation == 'add' || ($routine['item_num_params'] == 0 && $mode == 'add' && ! $errors)) {
+        $routine['item_param_dir'][]       = '';
+        $routine['item_param_name'][]      = '';
+        $routine['item_param_type'][]      = '';
+        $routine['item_param_length'][]    = '';
+        $routine['item_param_opts_num'][]  = '';
+        $routine['item_param_opts_text'][] = '';
+        $routine['item_num_params']++;
+    } else if ($operation == 'remove') {
+        unset($routine['item_param_dir'][$routine['item_num_params']-1]);
+        unset($routine['item_param_name'][$routine['item_num_params']-1]);
+        unset($routine['item_param_type'][$routine['item_num_params']-1]);
+        unset($routine['item_param_length'][$routine['item_num_params']-1]);
+        unset($routine['item_param_opts_num'][$routine['item_num_params']-1]);
+        unset($routine['item_param_opts_text'][$routine['item_num_params']-1]);
+        $routine['item_num_params']--;
+    }
+    $disable_remove_parameter = '';
+    if (! $routine['item_num_params']) {
+        $disable_remove_parameter = " color: gray;' disabled='disabled";
+    }
+    $original_routine = '';
+    if ($mode == 'edit') {
+        $original_routine = "<input name='item_original_name' "
+                          . "type='hidden' "
+                          . "value='{$routine['item_original_name']}'/>\n"
+                          . "<input name='item_original_type' "
+                          . "type='hidden' "
+                          . "value='{$routine['item_original_type']}'/>\n";
+    }
+    $isfunction_class   = '';
+    $isprocedure_class  = '';
+    $isfunction_select  = '';
+    $isprocedure_select = '';
+    if ($routine['item_type'] == 'PROCEDURE') {
+        $isfunction_class   = ' hide';
+        $isprocedure_select = " selected='selected'";
+    } else {
+        $isprocedure_class = ' hide';
+        $isfunction_select = " selected='selected'";
+    }
+
+    // Create the output
+    $retval  = "";
+    $retval .= "<!-- START " . strtoupper($mode) . " ROUTINE FORM -->\n\n";
+    $retval .= "<form class='rte_form' action='db_routines.php' method='post'>\n";
+    $retval .= "<input name='{$mode}_item' type='hidden' value='1' />\n";
+    $retval .= $original_routine;
+    $retval .= PMA_generate_common_hidden_inputs($db) . "\n";
+    $retval .= "<fieldset>\n";
+    $retval .= "<legend>" . __('Details') . "</legend>\n";
+    $retval .= "<table class='rte_table' style='width: 100%'>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td style='width: 20%;'>" . __('Routine name') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_name' maxlength='64'\n";
+    $retval .= "               value='{$routine['item_name']}' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Type') . "</td>\n";
+    $retval .= "    <td>\n";
+    if ($GLOBALS['is_ajax_request']) {
+        $retval .= "        <select name='item_type'>\n";
+        $retval .= "            <option value='PROCEDURE'$isprocedure_select>PROCEDURE</option>\n";
+        $retval .= "            <option value='FUNCTION'$isfunction_select>FUNCTION</option>\n";
+        $retval .= "        </select>\n";
+    } else {
+        $retval .= "        <input name='item_type' type='hidden' value='{$routine['item_type']}' />\n";
+        $retval .= "        <div style='width: 49%; float: left; text-align: center; font-weight: bold;'>\n";
+        $retval .= "            {$routine['item_type']}\n";
+        $retval .= "        </div>\n";
+        $retval .= "        <input style='width: 49%;' type='submit' name='routine_changetype'\n";
+        $retval .= "               value='".sprintf(__('Change to %s'), $routine['item_type_toggle'])."' />\n";
+    }
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Parameters') . "</td>\n";
+    $retval .= "    <td>\n";
+    // parameter handling start
+    $retval .= "        <table class='routine_params_table'>\n";
+    $retval .= "        <tr>\n";
+    $retval .= "            <th class='routine_direction_cell$isprocedure_class'>" . __('Direction') . "</th>\n";
+    $retval .= "            <th>" . __('Name') . "</th>\n";
+    $retval .= "            <th>" . __('Type') . "</th>\n";
+    $retval .= "            <th>" . __('Length/Values') . "</th>\n";
+    $retval .= "            <th colspan='2'>" . __('Options') . "</th>\n";
+    $retval .= "            <th class='routine_param_remove hide'> </th>\n";
+    $retval .= "        </tr>";
+    for ($i=0; $i<$routine['item_num_params']; $i++) { // each parameter
+        $retval .= PMA_RTN_getParameterRow($routine, $i, $isprocedure_class);
+    }
+    $retval .= "        </table>\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td> </td>\n";
+    $retval .= "    <td>\n";
+    $retval .= "        <input style='width: 49%;' type='submit' \n";
+    $retval .= "               name='routine_addparameter'\n";
+    $retval .= "               value='" . __('Add parameter') . "' />\n";
+    $retval .= "        <input style='width: 49%;$disable_remove_parameter'\n";
+    $retval .= "               type='submit' \n";
+    $retval .= "               name='routine_removeparameter'\n";
+    $retval .= "               value='" . __('Remove last parameter') . "' />\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    // parameter handling end
+    $retval .= "<tr class='routine_return_row$isfunction_class'>\n";
+    $retval .= "    <td>" . __('Return type') . "</td>\n";
+    $retval .= "    <td><select name='item_returntype'>\n";
+    $retval .= PMA_getSupportedDatatypes(true, $routine['item_returntype']) . "\n";
+    $retval .= "    </select></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr class='routine_return_row$isfunction_class'>\n";
+    $retval .= "    <td>" . __('Return length/values') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_returnlength'\n";
+    $retval .= "               value='{$routine['item_returnlength']}' /></td>\n";
+    $retval .= "    <td class='hide no_len'>---</td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr class='routine_return_row$isfunction_class'>\n";
+    $retval .= "    <td>" . __('Return options') . "</td>\n";
+    $retval .= "    <td><div>\n";
+    $retval .= PMA_generateCharsetDropdownBox(
+        PMA_CSDROPDOWN_CHARSET,
+        "item_returnopts_text",
+        null,
+        $routine['item_returnopts_text']
+    );
+    $retval .= "\n    </div>\n";
+    $retval .= "    <div><select name='item_returnopts_num'>\n";
+    $retval .= "        <option value=''></option>";
+    foreach ($param_opts_num as $key => $value) {
+        $selected = "";
+        if (! empty($routine['item_returnopts_num'])
+            && $routine['item_returnopts_num'] == $value
+        ) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "<option$selected>$value</option>";
+    }
+    $retval .= "\n    </select></div>\n";
+    $retval .= "    <div class='hide no_opts'>---</div>\n";
+    $retval .= "</td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Definition') . "</td>\n";
+    $retval .= "    <td><textarea name='item_definition' rows='15' cols='40'>";
+    $retval .= $routine['item_definition'];
+    $retval .= "</textarea></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Is deterministic') . "</td>\n";
+    $retval .= "    <td><input type='checkbox' name='item_isdeterministic'{$routine['item_isdeterministic']} /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Definer') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_definer'\n";
+    $retval .= "               value='{$routine['item_definer']}' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Security type') . "</td>\n";
+    $retval .= "    <td><select name='item_securitytype'>\n";
+    $retval .= "        <option value='DEFINER'{$routine['item_securitytype_definer']}>DEFINER</option>\n";
+    $retval .= "        <option value='INVOKER'{$routine['item_securitytype_invoker']}>INVOKER</option>\n";
+    $retval .= "    </select></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('SQL data access') . "</td>\n";
+    $retval .= "    <td><select name='item_sqldataaccess'>\n";
+    foreach ($param_sqldataaccess as $key => $value) {
+        $selected = "";
+        if ($routine['item_sqldataaccess'] == $value) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "        <option$selected>$value</option>\n";
+    }
+    $retval .= "    </select></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Comment') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_comment' maxlength='64'\n";
+    $retval .= "               value='{$routine['item_comment']}' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "</table>\n";
+    $retval .= "</fieldset>\n";
+    if ($GLOBALS['is_ajax_request']) {
+        $retval .= "<input type='hidden' name='editor_process_{$mode}'\n";
+        $retval .= "       value='true' />\n";
+        $retval .= "<input type='hidden' name='ajax_request' value='true' />\n";
+    } else {
+        $retval .= "<fieldset class='tblFooters'>\n";
+        $retval .= "    <input type='submit' name='editor_process_{$mode}'\n";
+        $retval .= "           value='" . __('Go') . "' />\n";
+        $retval .= "</fieldset>\n";
+    }
+    $retval .= "</form>\n\n";
+    $retval .= "<!-- END " . strtoupper($mode) . " ROUTINE FORM -->\n\n";
+
+    return $retval;
+} // end PMA_RTN_getEditorForm()
+
+/**
+ * Composes the query necessary to create a routine from an HTTP request.
+ *
+ * @return  string  The CREATE [ROUTINE | PROCEDURE] query.
+ */
+function PMA_RTN_getQueryFromRequest()
+{
+    global $_REQUEST, $cfg, $errors, $param_sqldataaccess, $param_opts_num;
+
+    $query = 'CREATE ';
+    if (! empty($_REQUEST['item_definer'])) {
+        if (strpos($_REQUEST['item_definer'], '@') !== false) {
+            $arr = explode('@', $_REQUEST['item_definer']);
+            $query .= 'DEFINER=' . PMA_backquote($arr[0]);
+            $query .= '@' . PMA_backquote($arr[1]) . ' ';
+        } else {
+            $errors[] = __('The definer must be in the "username at hostname" format');
+        }
+    }
+    if ($_REQUEST['item_type'] == 'FUNCTION'
+        || $_REQUEST['item_type'] == 'PROCEDURE'
+    ) {
+        $query .= $_REQUEST['item_type'] . ' ';
+    } else {
+        $errors[] = sprintf(__('Invalid routine type: "%s"'), htmlspecialchars($_REQUEST['item_type']));
+    }
+    if (! empty($_REQUEST['item_name'])) {
+        $query .= PMA_backquote($_REQUEST['item_name']) . ' ';
+    } else {
+        $errors[] = __('You must provide a routine name');
+    }
+    $params = '';
+    $warned_about_dir    = false;
+    $warned_about_name   = false;
+    $warned_about_length = false;
+    if (! empty($_REQUEST['item_param_name'])
+        && ! empty($_REQUEST['item_param_type'])
+        && ! empty($_REQUEST['item_param_length'])
+        && is_array($_REQUEST['item_param_name'])
+        && is_array($_REQUEST['item_param_type'])
+        && is_array($_REQUEST['item_param_length'])
+    ) {
+        for ($i=0; $i<count($_REQUEST['item_param_name']); $i++) {
+            if (! empty($_REQUEST['item_param_name'][$i]) && ! empty($_REQUEST['item_param_type'][$i])) {
+                if ($_REQUEST['item_type'] == 'PROCEDURE' && ! empty($_REQUEST['item_param_dir'][$i])) {
+                    $params .= $_REQUEST['item_param_dir'][$i] . " " . PMA_backquote($_REQUEST['item_param_name'][$i]) . " "
+                            . $_REQUEST['item_param_type'][$i];
+                } else if ($_REQUEST['item_type'] == 'FUNCTION') {
+                    $params .= PMA_backquote($_REQUEST['item_param_name'][$i]) . " " . $_REQUEST['item_param_type'][$i];
+                } else if (! $warned_about_dir) {
+                    $warned_about_dir = true;
+                    $errors[] = sprintf(
+                        __('Invalid direction "%s" given for parameter.'),
+                        htmlspecialchars($_REQUEST['item_param_dir'][$i])
+                    );
+                }
+                if ($_REQUEST['item_param_length'][$i] != ''
+                    && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i',
+                                   $_REQUEST['item_param_type'][$i])
+                ) {
+                    $params .= "(" . $_REQUEST['item_param_length'][$i] . ")";
+                } else if ($_REQUEST['item_param_length'][$i] == '' && preg_match('@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $_REQUEST['item_param_type'][$i])) {
+                    if (! $warned_about_length) {
+                        $warned_about_length = true;
+                        $errors[] = __('You must provide length/values for routine parameters of type ENUM, SET, VARCHAR and VARBINARY.');
+                    }
+                }
+                if (! empty($_REQUEST['item_param_opts_text'][$i])) {
+                    if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_param_type'][$i])])) {
+                        $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_param_type'][$i])];
+                        if ($group == 'FUNC_CHAR') {
+                            $params .= ' CHARSET ' . strtolower($_REQUEST['item_param_opts_text'][$i]);
+                        }
+                    }
+                }
+                if (! empty($_REQUEST['item_param_opts_num'][$i])) {
+                    if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_param_type'][$i])])) {
+                        $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_param_type'][$i])];
+                        if ($group == 'FUNC_NUMBER' && in_array($_REQUEST['item_param_opts_num'][$i], $param_opts_num)) {
+                            $params .= ' ' . strtoupper($_REQUEST['item_param_opts_num'][$i]);
+                        }
+                    }
+                }
+                if ($i != count($_REQUEST['item_param_name'])-1) {
+                    $params .= ", ";
+                }
+            } else if (! $warned_about_name) {
+                $warned_about_name = true;
+                $errors[] = __('You must provide a name and a type for each routine parameter.');
+                break;
+            }
+        }
+    }
+    $query .= " (" . $params . ") ";
+    if ($_REQUEST['item_type'] == 'FUNCTION') {
+        if (! empty($_REQUEST['item_returntype']) && in_array($_REQUEST['item_returntype'], $cfg['ColumnTypes'])) {
+            $query .= "RETURNS {$_REQUEST['item_returntype']}";
+        } else {
+            $errors[] = __('You must provide a valid return type for the routine.');
+        }
+        if (! empty($_REQUEST['item_returnlength'])
+            && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i',
+                            $_REQUEST['item_returntype'])
+        ) {
+            $query .= "(" . intval($_REQUEST['item_returnlength']) . ")";
+        } else if (empty($_REQUEST['item_returnlength']) && preg_match('@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $_REQUEST['item_returntype'])) {
+            if (! $warned_about_length) {
+                $warned_about_length = true;
+                $errors[] = __('You must provide length/values for routine parameters of type ENUM, SET, VARCHAR and VARBINARY.');
+            }
+        }
+        if (! empty($_REQUEST['item_returnopts_text'])) {
+            if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_returntype'])])) {
+                $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_returntype'])];
+                if ($group == 'FUNC_CHAR') {
+                    $query .= ' CHARSET ' . strtolower($_REQUEST['item_returnopts_text']);
+                }
+            }
+        }
+        if (! empty($_REQUEST['item_returnopts_num'])) {
+            if (isset($cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_returntype'])])) {
+                $group = $cfg['RestrictColumnTypes'][strtoupper($_REQUEST['item_returntype'])];
+                if ($group == 'FUNC_NUMBER' && in_array($_REQUEST['item_returnopts_num'], $param_opts_num)) {
+                    $query .= ' ' . strtoupper($_REQUEST['item_returnopts_num']);
+                }
+            }
+        }
+        $query .= ' ';
+    }
+    if (! empty($_REQUEST['item_comment'])) {
+        $query .= "COMMENT '" . PMA_sqlAddslashes($_REQUEST['item_comment']) . "' ";
+    }
+    if (isset($_REQUEST['item_isdeterministic'])) {
+        $query .= 'DETERMINISTIC ';
+    } else {
+        $query .= 'NOT DETERMINISTIC ';
+    }
+    if (! empty($_REQUEST['item_sqldataaccess']) && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess)) {
+        $query .= $_REQUEST['item_sqldataaccess'] . ' ';
+    }
+    if (! empty($_REQUEST['item_securitytype'])) {
+        if ($_REQUEST['item_securitytype'] == 'DEFINER' || $_REQUEST['item_securitytype'] == 'INVOKER') {
+            $query .= 'SQL SECURITY ' . $_REQUEST['item_securitytype'] . ' ';
+        }
+    }
+    if (! empty($_REQUEST['item_definition'])) {
+        $query .= $_REQUEST['item_definition'];
+    } else {
+        $errors[] = __('You must provide a routine definition.');
+    }
+
+    return $query;
+} // end PMA_RTN_getQueryFromRequest()
+
+/**
+ * Handles requests for executing a routine
+ */
+function PMA_RTN_handleExecute()
+{
+    global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $cfg;
+
+    /**
+     * Handle all user requests other than the default of listing routines
+     */
+    if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['item_name'])) {
+        // Build the queries
+        $routine   = PMA_RTN_getDataFromName($_REQUEST['item_name'], false);
+        if ($routine !== false) {
+            $queries   = array();
+            $end_query = array();
+            $args      = array();
+            for ($i=0; $i<$routine['item_num_params']; $i++) {
+                if (isset($_REQUEST['params'][$routine['item_param_name'][$i]])) {
+                    $value = $_REQUEST['params'][$routine['item_param_name'][$i]];
+                    if (is_array($value)) { // is SET type
+                        $value = implode(',', $value);
+                    }
+                    $value = PMA_sqlAddSlashes($value);
+                    if (! empty($_REQUEST['funcs'][$routine['item_param_name'][$i]])
+                        && in_array($_REQUEST['funcs'][$routine['item_param_name'][$i]], $cfg['Functions'])
+                    ) {
+                        $queries[] = "SET @p$i={$_REQUEST['funcs'][$routine['item_param_name'][$i]]}('$value');\n";
+                    } else {
+                        $queries[] = "SET @p$i='$value';\n";
+                    }
+                    $args[] = "@p$i";
+                } else {
+                    $args[] = "@p$i";
+                }
+                if ($routine['item_type'] == 'PROCEDURE') {
+                    if ($routine['item_param_dir'][$i] == 'OUT'
+                        || $routine['item_param_dir'][$i] == 'INOUT'
+                    ) {
+                        $end_query[] = "@p$i AS " . PMA_backquote($routine['item_param_name'][$i]);
+                    }
+                }
+            }
+            if ($routine['item_type'] == 'PROCEDURE') {
+                $queries[] = "CALL " . PMA_backquote($routine['item_name'])
+                           . "(" . implode(', ', $args) . ");\n";
+                if (count($end_query)) {
+                    $queries[] = "SELECT " . implode(', ', $end_query) . ";\n";
+                }
+            } else {
+                $queries[] = "SELECT " . PMA_backquote($routine['item_name'])
+                           . "(" . implode(', ', $args) . ") "
+                           . "AS " . PMA_backquote($routine['item_name']) . ";\n";
+            }
+            // Execute the queries
+            $affected = 0;
+            $result = null;
+            $outcome = true;
+            foreach ($queries as $num => $query) {
+                $resource = PMA_DBI_try_query($query);
+                if ($resource === false) {
+                    $outcome = false;
+                    break;
+                }
+                while (true) {
+                    if (! PMA_DBI_more_results()) {
+                        break;
+                    }
+                    PMA_DBI_next_result();
+                }
+                if (substr($query, 0, 6) == 'SELECT') {
+                    $result = $resource;
+                } else if (substr($query, 0, 4) == 'CALL') {
+                    $affected = PMA_DBI_affected_rows() - PMA_DBI_num_rows($resource);
+                }
+            }
+            // Generate output
+            if ($outcome) {
+                $message = __('Your SQL query has been executed successfully');
+                if ($routine['item_type'] == 'PROCEDURE') {
+                    $message .= '<br />';
+                    $message .= sprintf(
+                        _ngettext(
+                            '%d row affected by the last statement inside the procedure',
+                            '%d rows affected by the last statement inside the procedure',
+                            $affected
+                        ),
+                        $affected
+                    );
+                }
+                $message = PMA_message::success($message);
+                // Pass the SQL queries through the "pretty printer"
+                $output  = '<code class="sql" style="margin-bottom: 1em;">';
+                $output .= PMA_SQP_formatHtml(PMA_SQP_parse(implode($queries)));
+                $output .= '</code>';
+                // Display results
+                if ($result) {
+                    $output .= "<fieldset><legend>";
+                    $output .= sprintf(
+                        __('Execution results of routine %s'),
+                        PMA_backquote(htmlspecialchars($routine['item_name']))
+                    );
+                    $output .= "</legend>";
+                    $output .= "<table><tr>";
+                    foreach (PMA_DBI_get_fields_meta($result) as $key => $field) {
+                        $output .= "<th>";
+                        $output .= htmlspecialchars($field->name);
+                        $output .= "</th>";
+                    }
+                    $output .= "</tr>";
+                    // Stored routines can only ever return ONE ROW.
+                    $data = PMA_DBI_fetch_single_row($result);
+                    foreach ($data as $key => $value) {
+                        if ($value === null) {
+                            $value = '<i>NULL</i>';
+                        } else {
+                            $value = htmlspecialchars($value);
+                        }
+                        $output .= "<td class='odd'>" . $value . "</td>";
+                    }
+                    $output .= "</table></fieldset>";
+                } else {
+                    $notice = __('MySQL returned an empty result set (i.e. zero rows).');
+                    $output .= PMA_message::notice($notice)->getDisplay();
+                }
+            } else {
+                $output = '';
+                $message = PMA_message::error(sprintf(__('The following query has failed: "%s"'), $query) . '<br /><br />'
+                                                    . __('MySQL said: ') . PMA_DBI_getError(null));
+            }
+            // Print/send output
+            if ($GLOBALS['is_ajax_request']) {
+                $extra_data = array('dialog' => false);
+                PMA_ajaxResponse(
+                    $message->getDisplay() . $output,
+                    $message->isSuccess(),
+                    $extra_data
+                );
+            } else {
+                echo $message->getDisplay() . $output;
+                if ($message->isError()) {
+                    // At least one query has failed, so shouldn't
+                    // execute any more queries, so we quit.
+                    exit;
+                }
+                unset($_POST);
+                // Now deliberately fall through to displaying the routines list
+            }
+        } else {
+            $message  = __('Error in processing request') . ' : ';
+            $message .= sprintf(
+                PMA_RTE_getWord('not_found'),
+                htmlspecialchars(PMA_backquote($_REQUEST['item_name'])),
+                htmlspecialchars(PMA_backquote($db))
+            );
+            $message = PMA_message::error($message);
+            if ($GLOBALS['is_ajax_request']) {
+                PMA_ajaxResponse($message, $message->isSuccess());
+            } else {
+                echo $message->getDisplay();
+                unset($_POST);
+            }
+        }
+    } else if (! empty($_GET['execute_dialog']) && ! empty($_GET['item_name'])) {
+        /**
+         * Display the execute form for a routine.
+         */
+        $routine = PMA_RTN_getDataFromName($_GET['item_name'], false);
+        if ($routine !== false) {
+            $form = PMA_RTN_getExecuteForm($routine);
+            if ($GLOBALS['is_ajax_request'] == true) {
+                $extra_data = array();
+                $extra_data['dialog'] = true;
+                $extra_data['title']  = __("Execute routine") . " ";
+                $extra_data['title'] .= PMA_backquote(
+                    htmlentities($_GET['item_name'], ENT_QUOTES)
+                );
+                PMA_ajaxResponse($form, true, $extra_data);
+            } else {
+                echo "\n\n<h2>" . __("Execute routine") . "</h2>\n\n";
+                echo $form;
+                require './libraries/footer.inc.php';
+                // exit;
+            }
+        } else if (($GLOBALS['is_ajax_request'] == true)) {
+            $message  = __('Error in processing request') . ' : ';
+            $message .= sprintf(
+                PMA_RTE_getWord('not_found'),
+                htmlspecialchars(PMA_backquote($_REQUEST['item_name'])),
+                htmlspecialchars(PMA_backquote($db))
+            );
+            $message = PMA_message::error($message);
+            PMA_ajaxResponse($message, false);
+        }
+    }
+}
+
+/**
+ * Creates the HTML code that shows the routine execution dialog.
+ *
+ * @param   array    $routine      Data for the routine returned by
+ *                                 PMA_RTN_getDataFromName()
+ *
+ * @return  string   HTML code for the routine execution dialog.
+ */
+function PMA_RTN_getExecuteForm($routine)
+{
+    global $db, $cfg;
+
+    // Escape special characters
+    $routine['item_name'] = htmlentities($routine['item_name'], ENT_QUOTES);
+    for ($i=0; $i<$routine['item_num_params']; $i++) {
+        $routine['item_param_name'][$i] = htmlentities(
+            $routine['item_param_name'][$i],
+            ENT_QUOTES
+        );
+    }
+
+    // Create the output
+    $retval  = "";
+    $retval .= "<!-- START ROUTINE EXECUTE FORM -->\n\n";
+    $retval .= "<form action='db_routines.php' method='post' class='rte_form'>\n";
+    $retval .= "<input type='hidden' name='item_name'\n";
+    $retval .= "       value='{$routine['item_name']}' />\n";
+    $retval .= PMA_generate_common_hidden_inputs($db) . "\n";
+    $retval .= "<fieldset>\n";
+    if ($GLOBALS['is_ajax_request'] != true) {
+        $retval .= "<legend>{$routine['item_name']}</legend>\n";
+        $retval .= "<table class='rte_table'>\n";
+        $retval .= "<caption class='tblHeaders'>\n";
+        $retval .= __('Routine parameters');
+        $retval .= "</caption>\n";
+    } else {
+        $retval .= "<legend>" . __('Routine parameters') . "</legend>\n";
+        $retval .= "<table class='rte_table' style='width: 100%;'>\n";
+    }
+    $retval .= "<tr>\n";
+    $retval .= "<th>" . __('Name') . "</th>\n";
+    $retval .= "<th>" . __('Type') . "</th>\n";
+    if ($cfg['ShowFunctionFields']) {
+        $retval .= "<th>" . __('Function') . "</th>\n";
+    }
+    $retval .= "<th>" . __('Value')    . "</th>\n";
+    $retval .= "</tr>\n";
+    for ($i=0; $i<$routine['item_num_params']; $i++) { // Each parameter
+        if ($routine['item_type'] == 'PROCEDURE'
+            && $routine['item_param_dir'][$i] == 'OUT'
+        ) {
+            continue;
+        }
+        $rowclass = ($i % 2 == 0) ? 'even' : 'odd';
+        $retval .= "\n<tr class='$rowclass'>\n";
+        $retval .= "<td>{$routine['item_param_name'][$i]}</td>\n";
+        $retval .= "<td>{$routine['item_param_type'][$i]}</td>\n";
+        if ($cfg['ShowFunctionFields']) {
+            $retval .= "<td>\n";
+            // Get a list of data types that are not yet supported.
+            $no_support_types = PMA_unsupportedDatatypes();
+            if (stristr($routine['item_param_type'][$i], 'enum')
+                || stristr($routine['item_param_type'][$i], 'set')
+                || in_array(strtolower($routine['item_param_type'][$i]), $no_support_types)
+            ) {
+                $retval .= "--\n";
+            } else {
+                $field = array(
+                    'True_Type'       => strtolower($routine['item_param_type'][$i]),
+                    'Type'            => '',
+                    'Key'             => '',
+                    'Field'           => '',
+                    'Default'         => '',
+                    'first_timestamp' => false
+                );
+                $retval .= "<select name='funcs[{$routine['item_param_name'][$i]}]'>";
+                $retval .= PMA_getFunctionsForField($field, false);
+                $retval .= "</select>";
+            }
+            $retval .= "</td>\n";
+        }
+        // Append a class to date/time fields so that
+        // jQuery can attach a datepicker to them
+        $class = '';
+        if ($routine['item_param_type'][$i] == 'DATETIME'
+            || $routine['item_param_type'][$i] == 'TIMESTAMP'
+        ) {
+            $class = 'datetimefield';
+        } else if ($routine['item_param_type'][$i] == 'DATE') {
+            $class = 'datefield';
+        }
+        $retval .= "<td class='nowrap'>\n";
+        if (in_array($routine['item_param_type'][$i], array('ENUM', 'SET'))) {
+            $tokens = PMA_SQP_parse($routine['item_param_length'][$i]);
+            if ($routine['item_param_type'][$i] == 'ENUM') {
+                $input_type = 'radio';
+            } else {
+                $input_type = 'checkbox';
+            }
+            for ($j=0; $j<$tokens['len']; $j++) {
+                if ($tokens[$j]['type'] != 'punct_listsep') {
+                    $tokens[$j]['data'] = htmlentities(
+                        PMA_unquote($tokens[$j]['data']),
+                        ENT_QUOTES
+                    );
+                    $retval .= "<input name='params[{$routine['item_param_name'][$i]}][]' "
+                             . "value='{$tokens[$j]['data']}' type='$input_type' />"
+                             . "{$tokens[$j]['data']}<br />\n";
+                }
+            }
+        } else if (in_array(strtolower($routine['item_param_type'][$i]), $no_support_types)) {
+            $retval .= "\n";
+        } else {
+            $retval .= "<input class='$class' type='text' name='params[{$routine['item_param_name'][$i]}]' />\n";
+        }
+        $retval .= "</td>\n";
+        $retval .= "</tr>\n";
+    }
+    $retval .= "\n</table>\n";
+    if ($GLOBALS['is_ajax_request'] != true) {
+        $retval .= "</fieldset>\n\n";
+        $retval .= "<fieldset class='tblFooters'>\n";
+        $retval .= "    <input type='submit' name='execute_routine'\n";
+        $retval .= "           value='" . __('Go') . "' />\n";
+        $retval .= "</fieldset>\n";
+    } else {
+        $retval .= "<input type='hidden' name='execute_routine' value='true' />";
+        $retval .= "<input type='hidden' name='ajax_request' value='true' />";
+    }
+    $retval .= "</form>\n\n";
+    $retval .= "<!-- END ROUTINE EXECUTE FORM -->\n\n";
+
+    return $retval;
+} // end PMA_RTN_getExecuteForm()
+
+?>
diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php
new file mode 100644
index 0000000..a80fca0
--- /dev/null
+++ b/libraries/rte/rte_triggers.lib.php
@@ -0,0 +1,435 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Functions for trigger management.
+ *
+ * @package phpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+    exit;
+}
+
+/**
+ * This function is defined in: rte_routines.lib.php, rte_triggers.lib.php and
+ * rte_events.lib.php. It is used to retreive some language strings that are
+ * used in functionalities that are common to routines, triggers and events.
+ *
+ * @param   string  $index   The index of the string to get
+ *
+ * @return  string  The requested string or an empty string, if not available
+ */
+function PMA_RTE_getWord($index)
+{
+    $words = array(
+        'add'       => __('Add trigger'),
+        'docu'      => 'TRIGGERS',
+        'export'    => __('Export of trigger %s'),
+        'human'     => __('trigger'),
+        'no_create' => __('You do not have the necessary privileges to create a new trigger'),
+        'not_found' => __('No trigger with name %1$s found in database %2$s'),
+        'nothing'   => __('There are no triggers to display.'),
+        'title'     => __('Triggers'),
+    );
+    return isset($words[$index]) ? $words[$index] : '';
+} // end PMA_RTE_getWord()
+
+/**
+ * Main function for the triggers functionality
+ */
+function PMA_RTE_main()
+{
+    global $db, $table;
+
+    /**
+     * Process all requests
+     */
+    PMA_TRI_handleEditor();
+    PMA_TRI_handleExport();
+    /**
+     * Display a list of available triggers
+     */
+    $items = PMA_DBI_get_triggers($db, $table);
+    echo PMA_RTE_getList('trigger', $items);
+    /**
+     * Display a link for adding a new trigger,
+     * if the user has the necessary privileges
+     */
+    echo PMA_TRI_getFooterLinks();
+} // end PMA_RTE_main()
+
+/**
+ * Handles editor requests for adding or editing an item
+ */
+function PMA_TRI_handleEditor()
+{
+    global $_REQUEST, $_POST, $errors, $db, $table;
+
+    if (! empty($_REQUEST['editor_process_add'])
+        || ! empty($_REQUEST['editor_process_edit'])
+    ) {
+        $sql_query = '';
+
+        $item_query = PMA_TRI_getQueryFromRequest();
+
+        if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest()
+            // Execute the created query
+            if (! empty($_REQUEST['editor_process_edit'])) {
+                // Backup the old trigger, in case something goes wrong
+                $trigger = PMA_TRI_getDataFromName($_REQUEST['item_original_name']);
+                $create_item = $trigger['create'];
+                $drop_item = $trigger['drop'] . ';';
+                $result = PMA_DBI_try_query($drop_item);
+                if (! $result) {
+                    $errors[] = sprintf(__('The following query has failed: "%s"'), $drop_item) . '<br />'
+                                      . __('MySQL said: ') . PMA_DBI_getError(null);
+                } else {
+                    $result = PMA_DBI_try_query($item_query);
+                    if (! $result) {
+                        $errors[] = sprintf(__('The following query has failed: "%s"'), $item_query) . '<br />'
+                                          . __('MySQL said: ') . PMA_DBI_getError(null);
+                        // We dropped the old item, but were unable to create the new one
+                        // Try to restore the backup query
+                        $result = PMA_DBI_try_query($create_item);
+                        if (! $result) {
+                            // OMG, this is really bad! We dropped the query, failed to create a new one
+                            // and now even the backup query does not execute!
+                            // This should not happen, but we better handle this just in case.
+                            $errors[] = __('Sorry, we failed to restore the dropped trigger.') . '<br />'
+                                              . __('The backed up query was:') . "\"$create_item\"" . '<br />'
+                                              . __('MySQL said: ') . PMA_DBI_getError(null);
+                        }
+                    } else {
+                        $message = PMA_Message::success(__('Trigger %1$s has been modified.'));
+                        $message->addParam(PMA_backquote($_REQUEST['item_name']));
+                        $sql_query = $drop_item . $item_query;
+                    }
+                }
+            } else {
+                // 'Add a new item' mode
+                $result = PMA_DBI_try_query($item_query);
+                if (! $result) {
+                    $errors[] = sprintf(__('The following query has failed: "%s"'), $item_query) . '<br /><br />'
+                                      . __('MySQL said: ') . PMA_DBI_getError(null);
+                } else {
+                    $message = PMA_Message::success(__('Trigger %1$s has been created.'));
+                    $message->addParam(PMA_backquote($_REQUEST['item_name']));
+                    $sql_query = $item_query;
+                }
+            }
+        }
+
+        if (count($errors)) {
+            $message = PMA_Message::error(__('<b>One or more errors have occured while processing your request:</b>'));
+            $message->addString('<ul>');
+            foreach ($errors as $num => $string) {
+                $message->addString('<li>' . $string . '</li>');
+            }
+            $message->addString('</ul>');
+        }
+
+        $output = PMA_showMessage($message, $sql_query);
+        if ($GLOBALS['is_ajax_request']) {
+            $extra_data = array();
+            if ($message->isSuccess()) {
+                $items = PMA_DBI_get_triggers($db, $table, '');
+                $trigger = false;
+                foreach ($items as $key => $value) {
+                    if ($value['name'] == $_REQUEST['item_name']) {
+                        $trigger = $value;
+                    }
+                }
+                $extra_data['insert'] = false;
+                if (empty($table) || ($trigger !== false && $table == $trigger['table'])) {
+                    $extra_data['insert'] = true;
+                    $extra_data['new_row'] = PMA_TRI_getRowForList($trigger);
+                    $extra_data['name'] = htmlspecialchars(
+                        strtoupper($_REQUEST['item_name'])
+                    );
+                }
+                $response = $output;
+            } else {
+                $response = $message;
+            }
+            PMA_ajaxResponse($response, $message->isSuccess(), $extra_data);
+        }
+    }
+
+    /**
+     * Display a form used to add/edit a trigger, if necessary
+     */
+    if (count($errors) || ( empty($_REQUEST['editor_process_add']) && empty($_REQUEST['editor_process_edit'])
+        && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item']))) // FIXME: this must be simpler than that
+    ) {
+        // Get the data for the form (if any)
+        if (! empty($_REQUEST['add_item'])) {
+            $title = __("Create trigger");
+            $item = PMA_TRI_getDataFromRequest();
+            $mode = 'add';
+        } else if (! empty($_REQUEST['edit_item'])) {
+            $title = __("Edit trigger");
+            if (! empty($_REQUEST['item_name'])
+                && empty($_REQUEST['editor_process_edit'])
+            ) {
+                $item = PMA_TRI_getDataFromName($_REQUEST['item_name']);
+                if ($item !== false) {
+                    $item['item_original_name'] = $item['item_name'];
+                }
+            } else {
+                $item = PMA_TRI_getDataFromRequest();
+            }
+            $mode = 'edit';
+        }
+        if ($item !== false) {
+            // Show form
+            $editor = PMA_TRI_getEditorForm($mode, $item);
+            if ($GLOBALS['is_ajax_request']) {
+                $extra_data = array('title' => $title);
+                PMA_ajaxResponse($editor, true, $extra_data);
+            } else {
+                echo "\n\n<h2>$title</h2>\n\n$editor";
+                unset($_POST);
+                require './libraries/footer.inc.php';
+            }
+            // exit;
+        } else {
+            $message  = __('Error in processing request') . ' : ';
+            $message .= sprintf(
+                PMA_RTE_getWord('not_found'),
+                htmlspecialchars(PMA_backquote($_REQUEST['item_name'])),
+                htmlspecialchars(PMA_backquote($db))
+            );
+            $message = PMA_message::error($message);
+            if ($GLOBALS['is_ajax_request']) {
+                PMA_ajaxResponse($message, false);
+            } else {
+                $message->display();
+            }
+        }
+    }
+} // end PMA_TRI_handleEditor()
+
+/**
+ * This function will generate the values that are required to for the editor
+ *
+ * @return  array    Data necessary to create the editor.
+ */
+function PMA_TRI_getDataFromRequest()
+{
+    $retval = array();
+    $indices = array('item_name',
+                     'item_table',
+                     'item_original_name',
+                     'item_action_timing',
+                     'item_event_manipulation',
+                     'item_definition',
+                     'item_definer');
+    foreach ($indices as $key => $index) {
+        $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : '';
+    }
+    return $retval;
+} // end PMA_TRI_getDataFromRequest()
+
+/**
+ * This function will generate the values that are required to complete
+ * the "Edit trigger" form given the name of a trigger.
+ *
+ * @param   string   $name   The name of the trigger.
+ *
+ * @return  array    Data necessary to create the editor.
+ */
+function PMA_TRI_getDataFromName($name)
+{
+    global $db, $table, $_REQUEST;
+
+    $temp = array();
+    $items = PMA_DBI_get_triggers($db, $table, '');
+    foreach ($items as $key => $value) {
+        if ($value['name'] == $name) {
+            $temp = $value;
+        }
+    }
+    if (empty($temp)) {
+        return false;
+    } else {
+        $retval = array();
+        $retval['create']                  = $temp['create'];
+        $retval['drop']                    = $temp['drop'];
+        $retval['item_name']               = $temp['name'];
+        $retval['item_table']              = $temp['table'];
+        $retval['item_action_timing']      = $temp['action_timing'];
+        $retval['item_event_manipulation'] = $temp['event_manipulation'];
+        $retval['item_definition']         = $temp['definition'];
+        $retval['item_definer']            = $temp['definer'];
+        return $retval;
+    }
+} // end PMA_TRI_getDataFromName()
+
+/**
+ * Displays a form used to add/edit a trigger
+ *
+ * @param   string   $mode         If the editor will be used edit a trigger
+ *                                 or add a new one: 'edit' or 'add'.
+ * @param   array    $item         Data for the trigger returned by
+ *                                 PMA_TRI_getDataFromRequest() or
+ *                                 PMA_TRI_getDataFromName()
+ *
+ * @return  string   HTML code for the editor.
+ */
+function PMA_TRI_getEditorForm($mode, $item)
+{
+    global $db, $table, $titles, $event_manipulations, $action_timings;
+
+    // Escape special characters
+    $need_escape = array(
+                       'item_original_name',
+                       'item_name',
+                       'item_definition',
+                       'item_definer'
+                   );
+    foreach ($need_escape as $key => $index) {
+        $item[$index] = htmlentities($item[$index], ENT_QUOTES);
+    }
+    $original_data = '';
+    if ($mode == 'edit') {
+        $original_data = "<input name='item_original_name' "
+                       . "type='hidden' value='{$item['item_original_name']}'/>\n";
+    }
+
+    // Create the output
+    $retval  = "";
+    $retval .= "<!-- START " . strtoupper($mode) . " TRIGGER FORM -->\n\n";
+    $retval .= "<form class='rte_form' action='db_triggers.php' method='post'>\n";
+    $retval .= "<input name='{$mode}_item' type='hidden' value='1' />\n";
+    $retval .= $original_data;
+    $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n";
+    $retval .= "<fieldset>\n";
+    $retval .= "<legend>" . __('Details') . "</legend>\n";
+    $retval .= "<table class='rte_table' style='width: 100%'>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td style='width: 20%;'>" . __('Trigger name') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_name' maxlength='64'\n";
+    $retval .= "               value='{$item['item_name']}' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Table') . "</td>\n";
+    $retval .= "    <td>\n";
+    $retval .= "        <select name='item_table'>\n";
+    foreach (PMA_DBI_get_tables($db) as $key => $value) {
+        $selected = "";
+        if ($value == $item['item_table']) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "            <option$selected>$value</option>\n";
+    }
+    $retval .= "        </select>\n";
+    $retval .= "    </td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Time') . "</td>\n";
+    $retval .= "    <td><select name='item_timing'>\n";
+    foreach ($action_timings as $key => $value) {
+        $selected = "";
+        if (! empty($item['item_action_timing'])
+            && $item['item_action_timing'] == $value
+        ) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "<option$selected>$value</option>";
+    }
+    $retval .= "    </select></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Event') . "</td>\n";
+    $retval .= "    <td><select name='item_event'>\n";
+    foreach ($event_manipulations as $key => $value) {
+        $selected = "";
+        if (! empty($item['item_event_manipulation'])
+            && $item['item_event_manipulation'] == $value
+        ) {
+            $selected = " selected='selected'";
+        }
+        $retval .= "<option$selected>$value</option>";
+    }
+    $retval .= "    </select></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Definition') . "</td>\n";
+    $retval .= "    <td><textarea name='item_definition' rows='15' cols='40'>";
+    $retval .= $item['item_definition'];
+    $retval .= "</textarea></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "<tr>\n";
+    $retval .= "    <td>" . __('Definer') . "</td>\n";
+    $retval .= "    <td><input type='text' name='item_definer'\n";
+    $retval .= "               value='{$item['item_definer']}' /></td>\n";
+    $retval .= "</tr>\n";
+    $retval .= "</table>\n";
+    $retval .= "</fieldset>\n";
+    if ($GLOBALS['is_ajax_request']) {
+        $retval .= "<input type='hidden' name='editor_process_{$mode}'\n";
+        $retval .= "       value='true' />\n";
+        $retval .= "<input type='hidden' name='ajax_request' value='true' />\n";
+    } else {
+        $retval .= "<fieldset class='tblFooters'>\n";
+        $retval .= "    <input type='submit' name='editor_process_{$mode}'\n";
+        $retval .= "           value='" . __('Go') . "' />\n";
+        $retval .= "</fieldset>\n";
+    }
+    $retval .= "</form>\n\n";
+    $retval .= "<!-- END " . strtoupper($mode) . " TRIGGER FORM -->\n\n";
+
+    return $retval;
+} // end PMA_TRI_getEditorForm()
+
+/**
+ * Composes the query necessary to create a trigger from an HTTP request.
+ *
+ * @return  string  The CREATE TRIGGER query.
+ */
+function PMA_TRI_getQueryFromRequest()
+{
+    global $_REQUEST, $db, $errors, $action_timings, $event_manipulations;
+
+    $query = 'CREATE ';
+    if (! empty($_REQUEST['item_definer'])) {
+        if (strpos($_REQUEST['item_definer'], '@') !== false) {
+            $arr = explode('@', $_REQUEST['item_definer']);
+            $query .= 'DEFINER=' . PMA_backquote($arr[0]);
+            $query .= '@' . PMA_backquote($arr[1]) . ' ';
+        } else {
+            $errors[] = __('The definer must be in the "username at hostname" format');
+        }
+    }
+    $query .= 'TRIGGER ';
+    if (! empty($_REQUEST['item_name'])) {
+        $query .= PMA_backquote($_REQUEST['item_name']) . ' ';
+    } else {
+        $errors[] = __('You must provide a trigger name');
+    }
+    if (! empty($_REQUEST['item_timing']) && in_array($_REQUEST['item_timing'], $action_timings)) {
+        $query .= $_REQUEST['item_timing'] . ' ';
+    } else {
+        $errors[] = __('You must provide a valid timing for the trigger');
+    }
+    if (! empty($_REQUEST['item_event']) && in_array($_REQUEST['item_event'], $event_manipulations)) {
+        $query .= $_REQUEST['item_event'] . ' ';
+    } else {
+        $errors[] = __('You must provide a valid event for the trigger');
+    }
+    $query .= 'ON ';
+    if (! empty($_REQUEST['item_table']) && in_array($_REQUEST['item_table'], PMA_DBI_get_tables($db))) {
+        $query .= PMA_backQuote($_REQUEST['item_table']);
+    } else {
+        $errors[] = __('You must provide a valid table name');
+    }
+    $query .= ' FOR EACH ROW ';
+    if (! empty($_REQUEST['item_definition'])) {
+        $query .= $_REQUEST['item_definition'];
+    } else {
+        $errors[] = __('You must provide a trigger definition.');
+    }
+
+    return $query;
+} // end PMA_TRI_getQueryFromRequest()
+
+?>
diff --git a/libraries/tbl_links.inc.php b/libraries/tbl_links.inc.php
index 6282097..5f24800 100644
--- a/libraries/tbl_links.inc.php
+++ b/libraries/tbl_links.inc.php
@@ -98,10 +98,11 @@ if(PMA_Tracker::isActive()) {
     $tabs['tracking']['link'] = 'tbl_tracking.php';
 }
 if (! $db_is_information_schema && PMA_MYSQL_INT_VERSION >= 50002 && ! PMA_DRIZZLE) {
-    // Temporarily hiding this unfinished feature
-    // $tabs['triggers']['link'] = 'tbl_triggers.php';
-    // $tabs['triggers']['text'] = __('Triggers');
-    // $tabs['triggers']['icon'] = 'b_triggers.png';
+    if (PMA_currentUserHasPrivilege('TRIGGER', $db, $table)) {
+        $tabs['triggers']['link'] = 'tbl_triggers.php';
+        $tabs['triggers']['text'] = __('Triggers');
+        $tabs['triggers']['icon'] = 'b_triggers.png';
+    }
 }
 
 /**
diff --git a/tbl_triggers.php b/tbl_triggers.php
index bf9cbbc..a5d8a3e 100644
--- a/tbl_triggers.php
+++ b/tbl_triggers.php
@@ -1,35 +1 @@
-<?php
-
-/**
- *
- */
-require_once './libraries/common.inc.php';
-require_once './libraries/common.lib.php';
-
-$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
-$GLOBALS['js_include'][] = 'display_triggers.js';
-
-require_once './libraries/tbl_common.php';
-
-/**
- * Create labels for the list
- */
-$titles = PMA_buildActionTitles();
-
-/**
- * Displays the header and tabs
- */
-require_once './libraries/tbl_links.inc.php';
-
-/**
- * Displays the list of triggers
- */
-require_once './libraries/display_triggers.inc.php';
-
-/**
- * Displays the footer
- */
-require './libraries/footer.inc.php';
-
-
-?>
+<?php require_once './db_triggers.php'; ?>
diff --git a/themes/original/css/theme_right.css.php b/themes/original/css/theme_right.css.php
index d8a0e81..c18e003 100644
--- a/themes/original/css/theme_right.css.php
+++ b/themes/original/css/theme_right.css.php
@@ -1860,6 +1860,10 @@ fieldset .disabled-field td {
     vertical-align:     middle;
 }
 
+.rte_table tr td:nth-child(1) {
+    font-weight:        bold;
+}
+
 .rte_table input, .rte_table select, .rte_table textarea {
     width:              100%;
     margin:             0;
@@ -1868,6 +1872,11 @@ fieldset .disabled-field td {
     -moz-box-sizing:    border-box;
     -webkit-box-sizing: border-box;
 }
+
+.rte_table .routine_params_table {
+    width:              100%;
+}
+
 #placeholder .button {
     position: absolute;
     cursor: pointer;
@@ -1880,6 +1889,56 @@ fieldset .disabled-field td {
     padding: 2px;
 }
 
+.wrapper {
+    float: <?php echo $left; ?>;
+    margin-bottom: 0.5em;
+}
+.toggleButton {
+    position: relative;
+    cursor: pointer;
+    font-size: 0.8em;
+    text-align: center;
+    line-height: 1.55em;
+    height: 1.55em;
+    overflow: hidden;
+    border-right: 0.1em solid #888;
+    border-left: 0.1em solid #888;
+}
+.toggleButton table,
+.toggleButton td,
+.toggleButton img {
+    padding: 0;
+    position: relative;
+}
+.toggleButton .container {
+    position: absolute;
+}
+.toggleButton .toggleOn {
+    color: white;
+    padding: 0 1em;
+}
+.toggleButton .toggleOff {
+    padding: 0 1em;
+}
+
+.doubleFieldset fieldset {
+    width: 48%;
+    float: <?php echo $left; ?>;
+    padding: 0;
+}
+.doubleFieldset fieldset.left {
+    margin-<?php echo $right; ?>: 1%;
+}
+.doubleFieldset fieldset.right {
+    margin-<?php echo $left; ?>: 1%;
+}
+.doubleFieldset legend {
+    margin-<?php echo $left; ?>: 0.5em;
+}
+.doubleFieldset div.wrap {
+    padding: 0.5em;
+}
+
 #table_columns input, #table_columns select {
     width:              14em;
     box-sizing:         border-box;
diff --git a/themes/original/img/toggle-ltr.png b/themes/original/img/toggle-ltr.png
new file mode 100644
index 0000000..bc312a9
Binary files /dev/null and b/themes/original/img/toggle-ltr.png differ
diff --git a/themes/original/img/toggle-rtl.png b/themes/original/img/toggle-rtl.png
new file mode 100644
index 0000000..e81640e
Binary files /dev/null and b/themes/original/img/toggle-rtl.png differ
diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php
index 109c762..f6d523c 100644
--- a/themes/pmahomme/css/theme_right.css.php
+++ b/themes/pmahomme/css/theme_right.css.php
@@ -2217,6 +2217,10 @@ fieldset .disabled-field td {
     vertical-align:     middle;
 }
 
+.rte_table tr td:nth-child(1) {
+    font-weight:        bold;
+}
+
 .rte_table input, .rte_table select, .rte_table textarea {
     width:              100%;
     margin:             0;
@@ -2226,6 +2230,10 @@ fieldset .disabled-field td {
     -webkit-box-sizing: border-box;
 }
 
+.rte_table .routine_params_table {
+    width:              100%;
+}
+
 #placeholder .button {
     position: absolute;
     cursor: pointer;
@@ -2238,6 +2246,60 @@ fieldset .disabled-field td {
     padding: 2px;
 }
 
+.wrapper {
+    float: <?php echo $left; ?>;
+    margin-bottom: 1.5em;
+}
+.toggleButton {
+    position: relative;
+    cursor: pointer;
+    font-size: 0.8em;
+    text-align: center;
+    line-height: 1.55em;
+    height: 1.55em;
+    overflow: hidden;
+    border-right: 0.1em solid #888;
+    border-left: 0.1em solid #888;
+    -webkit-border-radius: 0.3em;
+    -moz-border-radius: 0.3em;
+    border-radius: 0.3em;
+}
+.toggleButton table,
+.toggleButton td,
+.toggleButton img {
+    padding: 0;
+    position: relative;
+}
+.toggleButton .container {
+    position: absolute;
+}
+.toggleButton .toggleOn {
+    color: white;
+    padding: 0 1em;
+    text-shadow: 0px 0px 0.2em #000;
+}
+.toggleButton .toggleOff {
+    padding: 0 1em;
+}
+
+.doubleFieldset fieldset {
+    width: 48%;
+    float: <?php echo $left; ?>;
+    padding: 0;
+}
+.doubleFieldset fieldset.left {
+    margin-<?php echo $right; ?>: 1%;
+}
+.doubleFieldset fieldset.right {
+    margin-<?php echo $left; ?>: 1%;
+}
+.doubleFieldset legend {
+    margin-<?php echo $left; ?>: 1.5em;
+}
+.doubleFieldset div.wrap {
+    padding: 1.5em;
+}
+
 #table_columns input, #table_columns select {
     width:              14em;
     box-sizing:         border-box;
diff --git a/themes/pmahomme/img/toggle-ltr.png b/themes/pmahomme/img/toggle-ltr.png
new file mode 100644
index 0000000..6dce09c
Binary files /dev/null and b/themes/pmahomme/img/toggle-ltr.png differ
diff --git a/themes/pmahomme/img/toggle-rtl.png b/themes/pmahomme/img/toggle-rtl.png
new file mode 100644
index 0000000..5b14cef
Binary files /dev/null and b/themes/pmahomme/img/toggle-rtl.png differ


hooks/post-receive
-- 
phpMyAdmin




More information about the Git mailing list