[Phpmyadmin-git] [SCM] phpMyAdmin branch, master, updated. RELEASE_3_4_2-4431-g61329e5

Rouslan Placella roccivic at users.sourceforge.net
Mon Jun 20 19:32:11 CEST 2011


The branch, master has been updated
       via  61329e5c87cc7062eff02a71ee08084a8f2b9a12 (commit)
       via  0ae05939011d842c0b612a61eba97393f9a0ca61 (commit)
       via  ae55e9b8f8ca0d7d3f65b7d9945a726738826ce1 (commit)
       via  223832b68ddacceab0e29825f28eaa9d38815b1e (commit)
       via  3829f2280f48f86059c616d118112356bd8be96a (commit)
       via  db6ae660cf04df2922fbc63d22f378651946d721 (commit)
       via  a0504f47d60855bae9a329b366beb53e1cd2abd8 (commit)
       via  71abc9f8d096e19fcc0d8b64a9475c75a4d1531c (commit)
       via  6ba8170aab54035346dc4a33b15f9795805588ae (commit)
       via  a5a43128256bee452004d71ecfc60fc116a9ac7f (commit)
       via  9b77820b7d4dd8c9975143effd5e30044146220f (commit)
       via  a63b2188be23ed2077a7a61d3d7a4cdecb083e24 (commit)
       via  8410e8e520fd660a0106e0e5f40cd1af8ca74664 (commit)
       via  c2fb87aff5929f2229c60a0ecdd957ac02bdee5e (commit)
       via  8d5cc0bbbcaa39f455d02e5f7b6aaaee8bced815 (commit)
       via  c0ceb2d75cea340ccc42c12a39a8283960c73136 (commit)
       via  f8c3da7885090d516fdaabfd71d959e40314e6d2 (commit)
       via  16185ac4f504a4f55fbca3b4dd64adbdbe2d1f7d (commit)
       via  657cbc8672939eaba5f66c1b177d61821754c6cf (commit)
       via  a8f8d3e7a8ac0f083fd7c2decc1c522c8cc6824b (commit)
       via  4047020d789217d393c597f726bf76e8a01d765c (commit)
       via  2cd59139ec5960a5809b56edd17ddeed6ece8660 (commit)
       via  dda7ce9c39c97f814304f9403f8b1619b3c89ba6 (commit)
       via  58c4ab431f33585e0006b79a38edf9fd0d855071 (commit)
       via  279ef37298727ace79dc8cce58ef4df98f14bc66 (commit)
       via  48681dfd81be21eea86d1b8e6deefd530a0028c5 (commit)
       via  cde93fe9496d2573790b3cfcc19699ec104338af (commit)
       via  31b42160d89b222e8d9ba44a6cfc2848db2048ad (commit)
       via  1c019d785f90482fc7afb4e97674208eb85a4683 (commit)
       via  041d5bd9d4beb4e856b51cca7b077788d7cba5eb (commit)
       via  c220bb4e134ed1d371c864c9190d68796fd344cd (commit)
       via  e2834cd49da5df098cc34d3919c2a67c449ee695 (commit)
       via  889cce858304aca13a0a94ef6e45f5717b79da99 (commit)
       via  ebfa1dd50603f25a52fcbdca6174b8b1fec78845 (commit)
       via  8db8527337182e7ccec5a4e4c87b1eb3af0641b2 (commit)
       via  17b8f21ccd8bd9a3927c8004ffdf9146060c91b3 (commit)
       via  d8da233e0cf63883e02f69bcdc17b6a0f00bbd70 (commit)
       via  2a7848fe9c373faad6b789e2ab669330f6b7d2f5 (commit)
       via  90af8e9dc5abdb30dc18a5e709ba9f008fb16849 (commit)
       via  d44d191d516405bfbab94e20188cb5b93101a00f (commit)
       via  2bc9529d69348bc95069fb5e8b1bf01a80126bd8 (commit)
       via  d14df11efb2772592e5f4c8e21db1a3c73d7fdd0 (commit)
       via  d7767b978c86aac6e048f3dc541f29416d448de1 (commit)
       via  4a455c3e626163b95a20fbfe85494ebcacab0224 (commit)
       via  aa2692c12f1285e62cb69f2269538a5d91866565 (commit)
       via  9a380a59356a39177f3176904f838a2f21493d79 (commit)
       via  11e3b20a9e5a7fbe492fd3af9d80350d85558773 (commit)
       via  2b09c553be186df319592e6a46c74011b156ec56 (commit)
       via  91a4c157961acc0f34e42c8c37621f52532b5b32 (commit)
       via  e0f4b36c73faa9d9eae1888fbd5fc0d1d623242e (commit)
       via  a07a1d997c1ce547bf0800fee108fba0f053f4f6 (commit)
       via  463a49a3ec82d814e70542ed8b704b1fe2d35c47 (commit)
       via  4baa133671fb7c30f134ae10c49a17da5b539847 (commit)
       via  82847a80b8fec01a5d7c1de3ec62db175d0d98d2 (commit)
       via  40a7510fa74b6b09ff272ab093ff29b7c13623ce (commit)
       via  43819596c8b5a72c7be41409fc43a7d13549404b (commit)
       via  3a6a30d5ba76821975dcf441dc19c02efbe15c96 (commit)
       via  dcf6969534a47d12639852f2a29d35d5a5f89bcf (commit)
       via  a9787c89b98eb00bf328f5b12666bf03edc2430c (commit)
       via  3f8efed7f102ae885d330151dcdceed46fb737cd (commit)
       via  6500912511e4704415d031c3b28ab86071848dcb (commit)
       via  6752d54b84adcbceb86e7d4ca5a30d346f344138 (commit)
       via  5343e6ee9ee6078770707f7f4cd78b4d571d2b67 (commit)
       via  3983253371f6567bdbd5967958f897106faf9492 (commit)
       via  0189a62776fbaed70b2072eaed7d034384dd66ff (commit)
       via  48532dfad0751e7e6d8e2ed8c20a8a1c45147a6c (commit)
       via  62f1d89ff6ba0ef91d5c44cce8330225f4799221 (commit)
       via  870ab261ae9c48e965c18c786209c5989cf8fe02 (commit)
       via  c27b2e776b754b3caaf7bdb30f4c3ee2b281ad6d (commit)
       via  493e573f52c6c38dd70d40744796a589f3c54b50 (commit)
       via  6f7b52627b17b2c8ca3365fc4260cb55f8faa9fc (commit)
       via  c830bdd85704cc9097467eed832234e3896cf4e7 (commit)
       via  8f670c6ae2ac59836d454280b87712d41cbf0cba (commit)
       via  bab400e1d036ea70ec8e1d010a81526a1d7c9d63 (commit)
       via  35454870e5249cbe527d9ea059986e8b3fcd5f88 (commit)
       via  7e4c5d5ef75f0736ed3962f20eb4624aee9fffe9 (commit)
       via  2434f0628c6673e45b7579c1c10e1c9cd3d16ecc (commit)
       via  d5358316998ff5bc0ecea9c8362fe62ed24a91ce (commit)
       via  008f5db63d7ab94ed5ce4b4e6e84c2fb11ab62a5 (commit)
       via  9bf9726bf9df2952953d04697f71552aa4305892 (commit)
       via  7103156e509030d76c314f2ce17d512aa673b804 (commit)
       via  255d7dcf0019b02554306e80ac550fdca9bd3bbd (commit)
       via  30d417cfe199aac561e876df323d5b14a4ddce0f (commit)
       via  9a36c3bd952912a15bc4bee8ca23106328805544 (commit)
       via  e2e58f1446fa6f572733af4c2806c6e37c80f7ed (commit)
       via  3b150147609027cc39392cc1f2d7a6f484dfa26a (commit)
       via  0c131ac95e7b4937dd8bc6fbbb13c09c564a3fb6 (commit)
       via  92d6e2d5c78da2bdcfff8fc06c346efc5a4a1835 (commit)
       via  5f9fed0b5c3ab373d953e07eab90c6cd276ab0eb (commit)
       via  80fa502e22a68ee0bc86ae9ea6f71f01e6ff544f (commit)
       via  15bc50543193b12b1fe9fd7fa3bd5f8129dfcc23 (commit)
       via  a31c41a6699e6f3fe0afa301be89a3d1792b4f4e (commit)
       via  bfb1102da4ce23a520ad457653af8742dba61cb9 (commit)
       via  c6254910b21063e38c5bbae36db13faaca8a4a77 (commit)
       via  0bd514ee8d56e7c4088baebc007fea7cb5b7665e (commit)
       via  e2250a3f99605fe11be5d572936f2bef075f2ad0 (commit)
       via  409dcfcde535e6ce6ff25473fbca385e44883a3d (commit)
       via  9e19d03ed5c881776bd40e30529ddd1f58d9d439 (commit)
       via  97e6b7aa5686fa57e73e01ed9e92eb00c4851b39 (commit)
       via  6077cfb9a2d8f090a357c15104216ce16e40bd98 (commit)
       via  c33fc8e7660a296a193f3a88d43e41babe74bf93 (commit)
       via  42477ca0e92bd54c5b6087273617f46573659d9e (commit)
       via  a126fc22e8684c59d51a6e2a64455eeaf116d567 (commit)
       via  f3158122bbca91eacacf6a156d5c53030894eb19 (commit)
       via  98d36b41bdd1e0cf14f413422f16abf161ff6596 (commit)
       via  f964639676eb9d99fba4b339fa3d823be709047b (commit)
       via  77c8f4c624cded54ba2f2d9c4e256e1191485b63 (commit)
       via  054fd49a043d34deffba4882cb122bc713234ef2 (commit)
       via  5673db8f7a3eea42a698d7ea0647fa1b899aae31 (commit)
       via  3ae8cba7dc5ff3ab5c7433e10836428e426d8917 (commit)
       via  22c9117c061c1822e5e4bea7f68877d28fd768d7 (commit)
       via  6eb2f3e815febcb18ca4954656e3780ded858c48 (commit)
       via  36d060b862e87a132b5e1f0df297b8ee720063ff (commit)
       via  4643171415814b70d08a152072d4d6f6d8ba6063 (commit)
       via  2f24e5b6b54b89f3c8b5e20a09845858b300f23f (commit)
       via  c5e6c7542d296ff3d0789d09c4211ea8f4a8e953 (commit)
       via  0b3121e722bcccc79fed750d997e81d17cdf09e2 (commit)
       via  eb78483214184ae7446e730aedc38bfa6405a2c0 (commit)
       via  f20c48fe829467e7f7e3638bc9feeeea8c724fb3 (commit)
       via  8ee7ac5b08b41d7f9dd3ac7f6b67513eaf2d8e75 (commit)
       via  f0e651698da2eb40cb56fb9b07fb1d829c2ad9bd (commit)
       via  5cb0b867be0fe09ab3545379589499b5087bedda (commit)
       via  22da77c86cf2b92c2557d8ac67a74282e9c81e89 (commit)
       via  2ebaa77320fa143072ee0430005e2be2161f5aa7 (commit)
       via  be504638350ccac7c736da32de48e6be87858698 (commit)
       via  e7e97ee6c5e2bc8cbcac2cd9c8ad09d0a3a5f740 (commit)
       via  5c75a21a84ed36780d88eab02f7d3c9386904f61 (commit)
       via  132694ce80dc59add74ee8f6e2afaf4943884edb (commit)
       via  320c311b92ba33dee80d6e199e805e9af1e9a1c8 (commit)
       via  42aaf6c5c9cbd8a9a2c0e88446f6cec7f4cf960d (commit)
       via  b1ef4fb11b81648158f4441555a0d9be80119ba6 (commit)
       via  8469bf8280c4935f4dcd455f522b5348db3d1e67 (commit)
       via  0659c39435b8373f8ddf21c307e9c531b4054e06 (commit)
       via  1db0f7b861d1481abeac12215d0f852fea6c9e9a (commit)
       via  fc745f2dac4408800d073c64e0e3c5060846a211 (commit)
       via  6fd9e7c5aabf46d3cc7cf32b373793136383ba16 (commit)
       via  409b5ad5ff7c6f0a6a9823cd4d58613fbbbfc661 (commit)
       via  f8f61518c2ccb48b299eb39301a1c7334e5ba4c2 (commit)
       via  a73f6ad72389fbad9b82387959a72aa5216ae934 (commit)
       via  db0d4b84b812df1ee418af90cf1216cfcc35b2f1 (commit)
       via  0c6cceef136e8ec3de7e2e34f91ac91637811588 (commit)
       via  e80c65a88a6da66ace528a95f7ed7039ac856bfb (commit)
       via  ebce205059a939b04d77f3dbfa2ec59d14693ee3 (commit)
       via  63693133e2cc01adfe7a2891feadb4d2864a7468 (commit)
       via  d2728442f8807a051da28083f00a5779d1c5f00c (commit)
       via  d3210ef1b67b91a7668c7c55aad909592b558a06 (commit)
       via  058b6175c12ac3f9335f369ef2161d93d4cf0e6c (commit)
       via  44301dd2502a409be99dfa34185bcef94d0fbae7 (commit)
       via  aac4d59508b44346d9568d70a51dd3e0ee57f83b (commit)
       via  65474446738d03120dd153151f8af62bf221e060 (commit)
       via  6d156b4febec6b9a0890e95ba07a0dc359c8b496 (commit)
      from  6a5ea0a2199d2a44afad5a58d2e099fa58fdd89e (commit)


- Log -----------------------------------------------------------------
commit 61329e5c87cc7062eff02a71ee08084a8f2b9a12
Merge: 0ae05939011d842c0b612a61eba97393f9a0ca61 6a5ea0a2199d2a44afad5a58d2e099fa58fdd89e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 20 18:26:50 2011 +0100

    Merge branch 'master' into rte

commit 0ae05939011d842c0b612a61eba97393f9a0ca61
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 20 12:50:29 2011 +0100

    Fixed incorrect escaping of some query parameters

commit ae55e9b8f8ca0d7d3f65b7d9945a726738826ce1
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 20 11:40:23 2011 +0100

    Removed unnecessary AJAX messages from the routines functionalities.

commit 223832b68ddacceab0e29825f28eaa9d38815b1e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 20 11:33:06 2011 +0100

    E_ALL fix in PMA_currentUserHasPrivilege()

commit 3829f2280f48f86059c616d118112356bd8be96a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 20 11:32:07 2011 +0100

    More error handling for routine functionalities

commit db6ae660cf04df2922fbc63d22f378651946d721
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 20 10:44:37 2011 +0100

    Removed duplicate function PMA_getSupportedCharsets() that was added by mistake into the routines functionality.

commit a0504f47d60855bae9a329b366beb53e1cd2abd8
Merge: 71abc9f8d096e19fcc0d8b64a9475c75a4d1531c 5f664dc7591d018ab15bb761ef7c44555ab97ca6
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 17:12:36 2011 +0100

    Merge branch 'master' into rte

commit 71abc9f8d096e19fcc0d8b64a9475c75a4d1531c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 17:02:33 2011 +0100

    Fixed bug where the information about the return variable of a routine was not correctly loaded into the editor.

commit 6ba8170aab54035346dc4a33b15f9795805588ae
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 15:08:13 2011 +0100

    Validation for fields that can be too long in routine ditor.

commit a5a43128256bee452004d71ecfc60fc116a9ac7f
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 14:40:18 2011 +0100

    Submit Routines dialogs forms when the enter key is pressed.

commit 9b77820b7d4dd8c9975143effd5e30044146220f
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 14:03:26 2011 +0100

    Focus on a relevant input element after opening a dialog (routines functionality).

commit a63b2188be23ed2077a7a61d3d7a4cdecb083e24
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 13:57:15 2011 +0100

    When issuing warning  about routine execution check for presence of mysql, not the absence of mysqli extentions.

commit 8410e8e520fd660a0106e0e5f40cd1af8ca74664
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 13:56:10 2011 +0100

    Fixed casing of messages in routines functionality

commit c2fb87aff5929f2229c60a0ecdd957ac02bdee5e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 13:44:14 2011 +0100

    Expand the routine editor to use all available space.

commit 8d5cc0bbbcaa39f455d02e5f7b6aaaee8bced815
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 13:36:26 2011 +0100

    Added an extra sanity check for query creation in routine editor

commit c0ceb2d75cea340ccc42c12a39a8283960c73136
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 13:16:05 2011 +0100

    Added more animations to routine functionalities

commit f8c3da7885090d516fdaabfd71d959e40314e6d2
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 17 13:15:34 2011 +0100

    Introduced JavaScript function PMA_slidingMessage()

commit 16185ac4f504a4f55fbca3b4dd64adbdbe2d1f7d
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 16 13:11:26 2011 +0100

    Fixe whitespaces in db_routines.php

commit 657cbc8672939eaba5f66c1b177d61821754c6cf
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 16 13:10:06 2011 +0100

    Fixed incorrect escaping of NULL results in routine execution.

commit a8f8d3e7a8ac0f083fd7c2decc1c522c8cc6824b
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 16 11:44:06 2011 +0100

    Animate the insertion of new routines into the list

commit 4047020d789217d393c597f726bf76e8a01d765c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 15 12:45:50 2011 +0100

    Refactored code that generated the dropdown list of MySQL functions.

commit 2cd59139ec5960a5809b56edd17ddeed6ece8660
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 15 11:28:56 2011 +0100

    Marged table headers in lists of Routines, Triggers and Events.

commit dda7ce9c39c97f814304f9403f8b1619b3c89ba6
Merge: 58c4ab431f33585e0006b79a38edf9fd0d855071 6c39191b03421d41d92bafc9252b0095862e71ed
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 19:44:09 2011 +0100

    Merge branch 'master' into rte

commit 58c4ab431f33585e0006b79a38edf9fd0d855071
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 15:51:25 2011 +0100

    Fixed bug where with JS disabled sql.php did not redirect the user back to list of routines after a DROP operation.

commit 279ef37298727ace79dc8cce58ef4df98f14bc66
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 15:45:39 2011 +0100

    Warn the user if the definition of a stored function does not contain a return statement.

commit 48681dfd81be21eea86d1b8e6deefd530a0028c5
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 15:32:44 2011 +0100

    Hide the parameter "length" for datatypes that do not support this in the routine editor.

commit cde93fe9496d2573790b3cfcc19699ec104338af
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 15:11:32 2011 +0100

    Refactored code that generates parameter rows for the Routine Editor.

commit 31b42160d89b222e8d9ba44a6cfc2848db2048ad
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 14:36:06 2011 +0100

    Moved all arbitrary code from routines.inc.php and renamed this file to routines.lib.php

commit 1c019d785f90482fc7afb4e97674208eb85a4683
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 14:26:47 2011 +0100

    Renamed Routine functions to more meaningful names.

commit 041d5bd9d4beb4e856b51cca7b077788d7cba5eb
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 14:05:37 2011 +0100

    Moved PMA_getSupportedCharsets() to common.lib.php

commit c220bb4e134ed1d371c864c9190d68796fd344cd
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 13:56:00 2011 +0100

    Moved PMA_getSupportedDatatypes() to common.lib.php

commit e2834cd49da5df098cc34d3919c2a67c449ee695
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 11:54:05 2011 +0100

    Generate the type dropdown for Routine editor in PHP, not JavaScript.

commit 889cce858304aca13a0a94ef6e45f5717b79da99
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 14 11:38:35 2011 +0100

    Fixed inconsistent escaping of special characters in Routines functionalities.

commit ebfa1dd50603f25a52fcbdca6174b8b1fec78845
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 13 18:10:22 2011 +0100

    Fixed "Commands out of sync" error when calling a stored routine from sql.php

commit 8db8527337182e7ccec5a4e4c87b1eb3af0641b2
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 13 15:14:31 2011 +0100

    Show the sql_query to the user when dropping Routines, Events and triggers and fix classes in the list.

commit 17b8f21ccd8bd9a3927c8004ffdf9146060c91b3
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 13 10:26:43 2011 +0100

    Fixed bug where new routines were not added to the list of routines, if the list was empty.

commit d8da233e0cf63883e02f69bcdc17b6a0f00bbd70
Merge: 2a7848fe9c373faad6b789e2ab669330f6b7d2f5 c3cba1170c4ca1073b301f875c8ad94704e025aa
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 18:46:59 2011 +0100

    Merge branch 'master' into rte

commit 2a7848fe9c373faad6b789e2ab669330f6b7d2f5
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 18:44:57 2011 +0100

    Moved code to generate a list of routines and a link to add a new routine into functions.

commit 90af8e9dc5abdb30dc18a5e709ba9f008fb16849
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 17:56:20 2011 +0100

    Moved some code in db_routines.inc.php to logically separate arbitrary code from functions.

commit d44d191d516405bfbab94e20188cb5b93101a00f
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 17:48:36 2011 +0100

    Removed outdated comment.

commit 2bc9529d69348bc95069fb5e8b1bf01a80126bd8
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 17:48:12 2011 +0100

    Removed unnecessary global variable.

commit d14df11efb2772592e5f4c8e21db1a3c73d7fdd0
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 16:39:34 2011 +0100

    Fixed E_ALL error: undefined index 'ajax_request'.

commit d7767b978c86aac6e048f3dc541f29416d448de1
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 16:26:11 2011 +0100

    Updated comments for routines functions.

commit 4a455c3e626163b95a20fbfe85494ebcacab0224
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 16:05:38 2011 +0100

    Fixed bug where the "Execute Routine" link was shown to unprivileged users.

commit aa2692c12f1285e62cb69f2269538a5d91866565
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 15:36:44 2011 +0100

    Fixed call to undefined function.

commit 9a380a59356a39177f3176904f838a2f21493d79
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 15:31:29 2011 +0100

    Fixed bug: return variable for a function was not correctly loaded into the routine editor.

commit 11e3b20a9e5a7fbe492fd3af9d80350d85558773
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 15:26:49 2011 +0100

    Some small improvements to the AJAX integration of the Routines Editor

commit 2b09c553be186df319592e6a46c74011b156ec56
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 15:05:52 2011 +0100

    HTML fixes for the Routine Editor.

commit 91a4c157961acc0f34e42c8c37621f52532b5b32
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 15:01:46 2011 +0100

    AJAX integration for routine execution functionality.

commit e0f4b36c73faa9d9eae1888fbd5fc0d1d623242e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 10 14:19:20 2011 +0100

    Fail safely when a requested routine is not found in the db.

commit a07a1d997c1ce547bf0800fee108fba0f053f4f6
Merge: 463a49a3ec82d814e70542ed8b704b1fe2d35c47 1906a9b1bb848966eeed3053803ec5a2e74d7fdb
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 9 21:26:26 2011 +0100

    Merge branch 'master' into rte

commit 463a49a3ec82d814e70542ed8b704b1fe2d35c47
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 9 21:25:18 2011 +0100

    Some small code improvements for db_routines.js

commit 4baa133671fb7c30f134ae10c49a17da5b539847
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 9 21:23:01 2011 +0100

    Comments and coding guidelines fixes for db_routines.js

commit 82847a80b8fec01a5d7c1de3ec62db175d0d98d2
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 9 21:08:26 2011 +0100

    JS integration for parameter options in Routines Editor.

commit 40a7510fa74b6b09ff272ab093ff29b7c13623ce
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 9 21:00:12 2011 +0100

    Support for parameter options in Routines Editor.

commit 43819596c8b5a72c7be41409fc43a7d13549404b
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 8 13:01:01 2011 +0100

    Fixed bug where the "Drop parameter" option disappeared in the Routine Editor if $cfg['PropertiesIconic'] was set to FALSE.

commit 3a6a30d5ba76821975dcf441dc19c02efbe15c96
Merge: dcf6969534a47d12639852f2a29d35d5a5f89bcf 6bc5a845f49d1f1b0864f37dceaeaa4b52fefdff
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 8 12:07:43 2011 +0100

    Merge brach 'master' into 'rte'

commit dcf6969534a47d12639852f2a29d35d5a5f89bcf
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 8 11:29:39 2011 +0100

    Use PMA_showMessage() for displaying the queries for creating and altering routines.

commit a9787c89b98eb00bf328f5b12666bf03edc2430c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 7 19:20:21 2011 +0100

    Improved form validation for the Routines Editor.

commit 3f8efed7f102ae885d330151dcdceed46fb737cd
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 7 18:34:58 2011 +0100

    Improved functionality for execution of Routines

commit 6500912511e4704415d031c3b28ab86071848dcb
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 7 14:17:17 2011 +0100

    Style fixes for Routines, Triggers and Events.

commit 6752d54b84adcbceb86e7d4ca5a30d346f344138
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 7 14:15:41 2011 +0100

    Support "MySQL functions" in the Execute Routine functionality.

commit 5343e6ee9ee6078770707f7f4cd78b4d571d2b67
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 7 13:24:43 2011 +0100

    Handle input parameters of type SET in routine execution functionality.

commit 3983253371f6567bdbd5967958f897106faf9492
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue Jun 7 10:40:13 2011 +0100

    Made title of the Routine Editor dialog dynamic.

commit 0189a62776fbaed70b2072eaed7d034384dd66ff
Merge: 48532dfad0751e7e6d8e2ed8c20a8a1c45147a6c 37eb5c0955b8e953527007a2a4818195c86bcada
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 17:18:35 2011 +0100

    Merge branch 'master' into rte

commit 48532dfad0751e7e6d8e2ed8c20a8a1c45147a6c
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 16:51:27 2011 +0100

    Fixed "Commands out of sync" error when executing stored Routines.

commit 62f1d89ff6ba0ef91d5c44cce8330225f4799221
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 13:57:35 2011 +0100

    "SQL data access" on routine creation defaults incorrectly to "READS SQL DATA".

commit 870ab261ae9c48e965c18c786209c5989cf8fe02
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 13:55:56 2011 +0100

    Consistent font size for the Export feature of Routines, Triggers and Events.

commit c27b2e776b754b3caaf7bdb30f4c3ee2b281ad6d
Merge: 493e573f52c6c38dd70d40744796a589f3c54b50 37f18cc9be747235c6f7d3f48f43f0bd9a234296
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 12:44:15 2011 +0100

    Merge branch 'master' into rte

commit 493e573f52c6c38dd70d40744796a589f3c54b50
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 12:40:54 2011 +0100

    Integrated the Routine Editor with CodeMirror.

commit 6f7b52627b17b2c8ca3365fc4260cb55f8faa9fc
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 11:10:50 2011 +0100

    Attached syntax highlited editor to Routine, Trigger and Event export dialogs.

commit c830bdd85704cc9097467eed832234e3896cf4e7
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 10:52:15 2011 +0100

    Moved Routine Editor validation into a function.

commit 8f670c6ae2ac59836d454280b87712d41cbf0cba
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 10:50:40 2011 +0100

    Better placement for the submit button in the Routine Editor.

commit bab400e1d036ea70ec8e1d010a81526a1d7c9d63
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon Jun 6 10:25:55 2011 +0100

    Made Routine Editor dialog modal.

commit 35454870e5249cbe527d9ea059986e8b3fcd5f88
Merge: 7e4c5d5ef75f0736ed3962f20eb4624aee9fffe9 5d6a5a8adb55455a3bc152089fd5663eee508ce7
Author: Rouslan Placella <rouslan at placella.com>
Date:   Sat Jun 4 20:26:11 2011 +0100

    Merge branch 'master' into rte

commit 7e4c5d5ef75f0736ed3962f20eb4624aee9fffe9
Author: Rouslan Placella <rouslan at placella.com>
Date:   Sat Jun 4 20:22:57 2011 +0100

    Add CSS used by Routines, Triggers and Events to 'original' theme.

commit 2434f0628c6673e45b7579c1c10e1c9cd3d16ecc
Author: Rouslan Placella <rouslan at placella.com>
Date:   Sat Jun 4 20:20:59 2011 +0100

    AJAX integration for Routines editor.

commit d5358316998ff5bc0ecea9c8362fe62ed24a91ce
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 3 15:01:26 2011 +0100

    Prototype Execute functionality for Routines.

commit 008f5db63d7ab94ed5ce4b4e6e84c2fb11ab62a5
Merge: 9bf9726bf9df2952953d04697f71552aa4305892 7cd81057f585ec97ea0055b5c88fd0c29981c552
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri Jun 3 10:52:12 2011 +0100

    Merge branch 'master' into rte

commit 9bf9726bf9df2952953d04697f71552aa4305892
Merge: 7103156e509030d76c314f2ce17d512aa673b804 0cd84b36be4c6c11982649014606eb7a3debfdc3
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 2 20:10:21 2011 +0100

    Merge branch 'master' into rte

commit 7103156e509030d76c314f2ce17d512aa673b804
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 2 20:09:06 2011 +0100

    Moved some code around to ease merging with master.

commit 255d7dcf0019b02554306e80ac550fdca9bd3bbd
Merge: 30d417cfe199aac561e876df323d5b14a4ddce0f 2da400447c6993d46b969a1c9c863fd81817f67e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu Jun 2 11:07:24 2011 +0100

    Merge remote-tracking branch 'origin/master' into rte

commit 30d417cfe199aac561e876df323d5b14a4ddce0f
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 20:13:52 2011 +0100

    A few more PHPDOC comments.

commit 9a36c3bd952912a15bc4bee8ca23106328805544
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 18:27:48 2011 +0100

    Got rid of global $param_datatypes from db_routines.inc.php

commit e2e58f1446fa6f572733af4c2806c6e37c80f7ed
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 18:20:09 2011 +0100

    Comments, whitespaces, etc...

commit 3b150147609027cc39392cc1f2d7a6f484dfa26a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 17:32:24 2011 +0100

    Removed duplicate function introduced earlier by mistake.

commit 0c131ac95e7b4937dd8bc6fbbb13c09c564a3fb6
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 17:16:16 2011 +0100

    Allow users to change the name of a Routine in edit mode.

commit 92d6e2d5c78da2bdcfff8fc06c346efc5a4a1835
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 16:50:35 2011 +0100

    Avoid passing the routine type in the HTTP request when exporting a routine.

commit 5f9fed0b5c3ab373d953e07eab90c6cd276ab0eb
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 16:11:06 2011 +0100

    Refactored JS used to drop Routines, Triggers and Events.

commit 80fa502e22a68ee0bc86ae9ea6f71f01e6ff544f
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 15:27:50 2011 +0100

    Refactored JS used to export Routines, Triggers and Events.

commit 15bc50543193b12b1fe9fd7fa3bd5f8129dfcc23
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 14:49:27 2011 +0100

    Escape the database and table names in PMA_currentUserHasPrivilege()

commit a31c41a6699e6f3fe0afa301be89a3d1792b4f4e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 14:11:12 2011 +0100

    Cleaned up the code for displaying the list of routines.

commit bfb1102da4ce23a520ad457653af8742dba61cb9
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 12:49:09 2011 +0100

    Disabled access to Routines features if the user does not have the required privileges.

commit c6254910b21063e38c5bbae36db13faaca8a4a77
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 12:15:18 2011 +0100

    Intoduced PMA_currentUserHasPrivilege() to easily disable access to some features.

commit 0bd514ee8d56e7c4088baebc007fea7cb5b7665e
Merge: e2250a3f99605fe11be5d572936f2bef075f2ad0 0dbc9f4a3c7fa46baed1477f001e37dad14fc908 a4d680782b166565b83a8614a148ff72975185f2
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed Jun 1 12:10:50 2011 +0100

    Merge branch 'master', remote-tracking branch 'origin' into rte

commit e2250a3f99605fe11be5d572936f2bef075f2ad0
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 19:47:32 2011 +0100

    E_ALL fixes.

commit 409dcfcde535e6ce6ff25473fbca385e44883a3d
Merge: 9e19d03ed5c881776bd40e30529ddd1f58d9d439 575f265293ffe0625da6a8fc0877a84d595d5322
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 19:22:38 2011 +0100

    Merge remote-tracking branch 'origin/master' into rte

commit 9e19d03ed5c881776bd40e30529ddd1f58d9d439
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 19:21:53 2011 +0100

    Fixed jQuery animation when dropping Routines, Triggers and Events.

commit 97e6b7aa5686fa57e73e01ed9e92eb00c4851b39
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 19:14:30 2011 +0100

    Improved parser for parameters of routines.

commit 6077cfb9a2d8f090a357c15104216ce16e40bd98
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 15:21:14 2011 +0100

    Disabled the "Edit Routine" and "Export Routine" links if the user cannot perform these operations.

commit c33fc8e7660a296a193f3a88d43e41babe74bf93
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 14:29:11 2011 +0100

    Moved code for generating the sql query that creates a routine into a function.

commit 42477ca0e92bd54c5b6087273617f46573659d9e
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 14:08:15 2011 +0100

    Fixed broken handling of "SQL SECURITY" in routines.

commit a126fc22e8684c59d51a6e2a64455eeaf116d567
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 13:47:21 2011 +0100

    Improve the parsing of parameters in routines editor.

commit f3158122bbca91eacacf6a156d5c53030894eb19
Merge: 98d36b41bdd1e0cf14f413422f16abf161ff6596 a47ac24a49d5d925553f8d3c92f6a9722ee8b0ad
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 12:14:02 2011 +0100

    Merge branch 'master', remote-tracking branch 'origin' into rte

commit 98d36b41bdd1e0cf14f413422f16abf161ff6596
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 12:13:22 2011 +0100

    Show query on successful creation or edit of routines.

commit f964639676eb9d99fba4b339fa3d823be709047b
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 11:14:15 2011 +0100

    Backquote Routine parameters in the generated query.

commit 77c8f4c624cded54ba2f2d9c4e256e1191485b63
Merge: 054fd49a043d34deffba4882cb122bc713234ef2 80701c70cf5ab0d78d05a24060c5c3560a2d8e2d
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 31 10:58:55 2011 +0100

    Merge remote-tracking branch 'origin' into rte

commit 054fd49a043d34deffba4882cb122bc713234ef2
Merge: 5673db8f7a3eea42a698d7ea0647fa1b899aae31 310466c489603511a1a615db8e36f1714e249bcd
Author: Rouslan Placella <rouslan at placella.com>
Date:   Mon May 30 13:34:18 2011 +0100

    Merge branch 'master' of git://phpmyadmin.git.sourceforge.net/gitroot/phpmyadmin/phpmyadmin into rte

commit 5673db8f7a3eea42a698d7ea0647fa1b899aae31
Merge: 3ae8cba7dc5ff3ab5c7433e10836428e426d8917 0b5f4410cd653b2ce132e5f7537e03949cef59f9
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri May 27 17:51:41 2011 +0100

    Merge branch 'master' of git://phpmyadmin.git.sourceforge.net/gitroot/phpmyadmin/phpmyadmin into rte

commit 3ae8cba7dc5ff3ab5c7433e10836428e426d8917
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri May 27 17:43:23 2011 +0100

    Removed some redundant includes in Routines, Triggers and Events files.

commit 22c9117c061c1822e5e4bea7f68877d28fd768d7
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri May 27 14:59:36 2011 +0100

    Load the Export data for Routines asynchronously.

commit 6eb2f3e815febcb18ca4954656e3780ded858c48
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri May 27 12:49:59 2011 +0100

    Improved query execution handling by the Routines Editor.

commit 36d060b862e87a132b5e1f0df297b8ee720063ff
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri May 27 12:01:12 2011 +0100

    Fixed conditional class in "Add a new Routine" link.

commit 4643171415814b70d08a152072d4d6f6d8ba6063
Author: Rouslan Placella <rouslan at placella.com>
Date:   Fri May 27 11:36:59 2011 +0100

    Improved error handling in Routines editor.

commit 2f24e5b6b54b89f3c8b5e20a09845858b300f23f
Merge: c5e6c7542d296ff3d0789d09c4211ea8f4a8e953 434d233e5b710dc6d3ac82b6825cf726aac22cb3
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 20:32:35 2011 +0100

    Merge branch 'master' of git://phpmyadmin.git.sourceforge.net/gitroot/phpmyadmin/phpmyadmin into rte

commit c5e6c7542d296ff3d0789d09c4211ea8f4a8e953
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 20:32:22 2011 +0100

    Added a few comments in db_routines.inc.php

commit 0b3121e722bcccc79fed750d997e81d17cdf09e2
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 20:31:37 2011 +0100

    Fixed incorrect escaping of form fields in the Routines Editor.

commit eb78483214184ae7446e730aedc38bfa6405a2c0
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 20:28:28 2011 +0100

    Refactored the Routines editor.

commit f20c48fe829467e7f7e3638bc9feeeea8c724fb3
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 14:48:53 2011 +0100

    Fixed handling of function return type in routines dialog.

commit 8ee7ac5b08b41d7f9dd3ac7f6b67513eaf2d8e75
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 14:21:32 2011 +0100

    Disable the 'Remove last parameter' button in the routines editor, if there are no parameters to remove.

commit f0e651698da2eb40cb56fb9b07fb1d829c2ad9bd
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 14:17:42 2011 +0100

    Don't show any parameters in the dialog when editing a routine, if it doesn't have any.

commit 5cb0b867be0fe09ab3545379589499b5087bedda
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 14:04:24 2011 +0100

    Don't handle parameter direction for stored functions, they don't support this.

commit 22da77c86cf2b92c2557d8ac67a74282e9c81e89
Merge: 2ebaa77320fa143072ee0430005e2be2161f5aa7 d012edac93bdd1f2a7b519b6e9ad0534cc45b1b4
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 13:07:47 2011 +0100

    Merge branch 'master' of git://phpmyadmin.git.sourceforge.net/gitroot/phpmyadmin/phpmyadmin into rte

commit 2ebaa77320fa143072ee0430005e2be2161f5aa7
Author: Rouslan Placella <rouslan at placella.com>
Date:   Thu May 26 13:07:28 2011 +0100

    Implemented a parser for routine parameters.

commit be504638350ccac7c736da32de48e6be87858698
Merge: e7e97ee6c5e2bc8cbcac2cd9c8ad09d0a3a5f740 76194fd122690cbe3947bfa25ae5d40de82d1d35
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 21:16:46 2011 +0100

    Merge branch 'master' of git://phpmyadmin.git.sourceforge.net/gitroot/phpmyadmin/phpmyadmin into rte

commit e7e97ee6c5e2bc8cbcac2cd9c8ad09d0a3a5f740
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 21:15:04 2011 +0100

    Hide the Routines, Triggers and Events tabs from Drizzle users.

commit 5c75a21a84ed36780d88eab02f7d3c9386904f61
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 21:12:29 2011 +0100

    Prototype handling of "Edit routine" functionality

commit 132694ce80dc59add74ee8f6e2afaf4943884edb
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 20:59:18 2011 +0100

    Added code to handle the "Add a new routine" requests

commit 320c311b92ba33dee80d6e199e805e9af1e9a1c8
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 20:29:22 2011 +0100

    Added handling of 'length/values' for routine parameters in "Add new routine form"

commit 42aaf6c5c9cbd8a9a2c0e88446f6cec7f4cf960d
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 20:11:00 2011 +0100

    Better handling for choosing routine type in the "Add new routine form"

commit b1ef4fb11b81648158f4441555a0d9be80119ba6
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 11:56:06 2011 +0100

    Display actual datatypes in the "Add a new Routine" form

commit 8469bf8280c4935f4dcd455f522b5348db3d1e67
Merge: 0659c39435b8373f8ddf21c307e9c531b4054e06 13f09c03cfa37ba3f05fde015826ce4893158293
Author: Rouslan Placella <rouslan at placella.com>
Date:   Wed May 25 11:05:58 2011 +0100

    Merge branch 'master' of git://phpmyadmin.git.sourceforge.net/gitroot/phpmyadmin/phpmyadmin into rte

commit 0659c39435b8373f8ddf21c307e9c531b4054e06
Merge: 1db0f7b861d1481abeac12215d0f852fea6c9e9a 4e2cd5e998340f2f7262bc890d64e51c85970937
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 22:33:51 2011 +0100

    Merge branch 'master' of git://phpmyadmin.git.sourceforge.net/gitroot/phpmyadmin/phpmyadmin into rte

commit 1db0f7b861d1481abeac12215d0f852fea6c9e9a
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 22:32:23 2011 +0100

    Created a prototype of "Add a new Procedure" functionality.

commit fc745f2dac4408800d073c64e0e3c5060846a211
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 14:52:32 2011 +0100

    Fix the "Return type" of Stored Functions not showing up in the Routines list.

commit 6fd9e7c5aabf46d3cc7cf32b373793136383ba16
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 14:43:09 2011 +0100

    Always show the "Add new" link for triggers.
    
    This makes sense when there is nothing to show for a db-wise list of triggers.

commit 409b5ad5ff7c6f0a6a9823cd4d58613fbbbfc661
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 14:41:08 2011 +0100

    No need to use $GLOBALS to access $url_query

commit f8f61518c2ccb48b299eb39301a1c7334e5ba4c2
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 14:39:33 2011 +0100

    Add Export functionality for Roustines, Triggers and Events when JS is disabled.

commit a73f6ad72389fbad9b82387959a72aa5216ae934
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 14:06:19 2011 +0100

    Improve the display of the "Event Scheduler fieldset"

commit db0d4b84b812df1ee418af90cf1216cfcc35b2f1
Merge: 755fc28b49b3012cc80881720f54f5c3781285ea 0c6cceef136e8ec3de7e2e34f91ac91637811588
Author: Rouslan Placella <rouslan at placella.com>
Date:   Tue May 24 13:01:02 2011 +0100

    Merge branch 'master' of ssh://repo.or.cz/srv/git/phpmyadmin/roccivic into rte

commit 0c6cceef136e8ec3de7e2e34f91ac91637811588
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 19:33:42 2011 +0100

    E_ALL fixes

commit e80c65a88a6da66ace528a95f7ed7039ac856bfb
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 18:48:17 2011 +0100

    Show status of the event scheduler and offer option to toggle it

commit ebce205059a939b04d77f3dbfa2ec59d14693ee3
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 18:10:46 2011 +0100

    Updated documentation

commit 63693133e2cc01adfe7a2891feadb4d2864a7468
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:52:56 2011 +0100

    Moved JS related to Routines, Triggers and Events into their own files.

commit d2728442f8807a051da28083f00a5779d1c5f00c
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:50:14 2011 +0100

    Recycled old Events functionality and linked it to the new entry in the menu

commit d3210ef1b67b91a7668c7c55aad909592b558a06
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:49:58 2011 +0100

    Recycled old Triggers functionality and linked it to the new entry in the menu

commit 058b6175c12ac3f9335f369ef2161d93d4cf0e6c
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:49:22 2011 +0100

    Recycled old Routines functionality and linked it to the new entry in the menu

commit 44301dd2502a409be99dfa34185bcef94d0fbae7
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:43:19 2011 +0100

    Added new tabs for Routines, Triggers and Events

commit aac4d59508b44346d9568d70a51dd3e0ee57f83b
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:41:30 2011 +0100

    Support retreiving Triggers on a per-database basis.

commit 65474446738d03120dd153151f8af62bf221e060
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:39:09 2011 +0100

    Removed references to Routines, Triggers and Events from *_structute.php files

commit 6d156b4febec6b9a0890e95ba07a0dc359c8b496
Author: Rouslan <roccivic at roccivic-pc.(none)>
Date:   Sat May 21 17:36:48 2011 +0100

    Added new graphics for Procedures, Triggers and Events

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

Summary of changes:
 Documentation.html                                |    7 +
 db_events.php                                     |   38 +
 db_routines.php                                   |  443 +++++++
 db_structure.php                                  |   15 -
 db_triggers.php                                   |   38 +
 js/db_events.js                                   |    2 +
 js/db_routines.js                                 |  568 +++++++++
 js/db_structure.js                                |   74 --
 js/display_triggers.js                            |    2 +
 js/functions.js                                   |  195 +++-
 js/messages.php                                   |    6 +-
 libraries/common.inc.php                          |    1 +
 libraries/common.lib.php                          |  270 +++++-
 libraries/database_interface.lib.php              |   24 +-
 libraries/db_events.inc.php                       |  127 ++-
 libraries/db_links.inc.php                        |   20 +
 libraries/db_routines.inc.php                     |   94 --
 libraries/db_routines.lib.php                     | 1265 +++++++++++++++++++++
 libraries/dbi/mysql.dbi.lib.php                   |   26 +
 libraries/dbi/mysqli.dbi.lib.php                  |   38 +
 libraries/display_triggers.inc.php                |  123 ++
 libraries/tbl_links.inc.php                       |   18 +-
 libraries/tbl_properties.inc.php                  |   23 +-
 libraries/tbl_triggers.inc.php                    |   58 -
 sql.php                                           |    9 +
 tbl_change.php                                    |   90 +--
 tbl_structure.php                                 |    2 -
 tbl_triggers.php                                  |   35 +
 themes/original/css/theme_right.css.php           |   13 +
 themes/original/img/b_event_add.png               |  Bin 0 -> 927 bytes
 themes/original/img/b_events.png                  |  Bin 0 -> 969 bytes
 themes/{pmahomme => original}/img/b_nextpage.png  |  Bin 395 -> 395 bytes
 themes/original/img/b_routine_add.png             |  Bin 0 -> 651 bytes
 themes/original/img/b_routines.png                |  Bin 0 -> 666 bytes
 themes/original/img/b_trigger_add.png             |  Bin 0 -> 731 bytes
 themes/original/img/b_triggers.png                |  Bin 0 -> 707 bytes
 themes/original/img/bd_edit.png                   |  Bin 0 -> 253 bytes
 themes/original/img/bd_export.png                 |  Bin 0 -> 210 bytes
 themes/{pmahomme => original}/img/bd_nextpage.png |  Bin 167 -> 167 bytes
 themes/pmahomme/css/theme_right.css.php           |   13 +
 themes/pmahomme/img/b_event_add.png               |  Bin 0 -> 927 bytes
 themes/pmahomme/img/b_events.png                  |  Bin 0 -> 969 bytes
 themes/pmahomme/img/b_routine_add.png             |  Bin 0 -> 651 bytes
 themes/pmahomme/img/b_routines.png                |  Bin 0 -> 666 bytes
 themes/pmahomme/img/b_trigger_add.png             |  Bin 0 -> 731 bytes
 themes/pmahomme/img/b_triggers.png                |  Bin 0 -> 707 bytes
 themes/pmahomme/img/bd_edit.png                   |  Bin 0 -> 295 bytes
 themes/pmahomme/img/bd_export.png                 |  Bin 0 -> 353 bytes
 48 files changed, 3213 insertions(+), 424 deletions(-)
 create mode 100644 db_events.php
 create mode 100644 db_routines.php
 create mode 100644 db_triggers.php
 create mode 100644 js/db_events.js
 create mode 100644 js/db_routines.js
 create mode 100644 js/display_triggers.js
 delete mode 100644 libraries/db_routines.inc.php
 create mode 100644 libraries/db_routines.lib.php
 create mode 100644 libraries/display_triggers.inc.php
 delete mode 100644 libraries/tbl_triggers.inc.php
 create mode 100644 tbl_triggers.php
 create mode 100644 themes/original/img/b_event_add.png
 create mode 100644 themes/original/img/b_events.png
 copy themes/{pmahomme => original}/img/b_nextpage.png (100%)
 create mode 100644 themes/original/img/b_routine_add.png
 create mode 100644 themes/original/img/b_routines.png
 create mode 100644 themes/original/img/b_trigger_add.png
 create mode 100644 themes/original/img/b_triggers.png
 create mode 100644 themes/original/img/bd_edit.png
 create mode 100644 themes/original/img/bd_export.png
 copy themes/{pmahomme => original}/img/bd_nextpage.png (100%)
 create mode 100644 themes/pmahomme/img/b_event_add.png
 create mode 100644 themes/pmahomme/img/b_events.png
 create mode 100644 themes/pmahomme/img/b_routine_add.png
 create mode 100644 themes/pmahomme/img/b_routines.png
 create mode 100644 themes/pmahomme/img/b_trigger_add.png
 create mode 100644 themes/pmahomme/img/b_triggers.png
 create mode 100644 themes/pmahomme/img/bd_edit.png
 create mode 100644 themes/pmahomme/img/bd_export.png

diff --git a/Documentation.html b/Documentation.html
index d2dea87..eb840d2 100644
--- a/Documentation.html
+++ b/Documentation.html
@@ -137,6 +137,8 @@ vim: expandtab ts=4 sw=4 sts=4 tw=78
         <abbr title="Frequently Asked Questions">FAQ</abbr> 3.6)</a></li>
     <li>support mysqli, the improved MySQL extension <a href="#faq1_17">
         (see <abbr title="Frequently Asked Questions">FAQ</abbr> 1.17)</a></li>
+    <li>create, edit, call, export and drop stored procedures and functions</li>
+    <li>create, edit, export and drop events and triggers</li>
     <li>communicate in <a href="http://www.phpmyadmin.net/home_page/translations.php">62 different languages</a>
         </li>
     <li>synchronize two databases residing on the same as well as remote servers
@@ -5152,6 +5154,8 @@ Jakub Wilk, Thomas Michael Winningham, Vilius Zigmantas, "Manuzhai".
     <li><a href="http://www.wikipedia.org/wiki/Secure_Sockets_Layer">SSL (Secure
             Sockets Layer)</a>
          - a cryptographic protocol which provides secure communication on the Internet.</li>
+    <li><a href="http://en.wikipedia.org/wiki/Stored_procedure">Stored procedure</a>
+         - a subroutine available to applications accessing a relational database system</li>
     <li><a href="http://www.wikipedia.org/wiki/SQL">SQL</a>
          - Structured Query Language</li>
     <li><a href="http://www.wikipedia.org/wiki/Table_%28database%29">table</a>
@@ -5163,6 +5167,9 @@ Jakub Wilk, Thomas Michael Winningham, Vilius Zigmantas, "Manuzhai".
          - a type of archive file format: the Tape ARchive format.</li>
     <li><a href="http://www.wikipedia.org/wiki/TCP">TCP (Transmission Control Protocol)</a>
          - one of the core protocols of the Internet protocol suite.</li>
+    <li><a href="http://en.wikipedia.org/wiki/Database_trigger">trigger</a>
+         - a procedural code that is automatically executed in response to
+         certain events on a particular table or view in a database</li>
     <li><a href="http://www.acko.net/node/56">UFPDF</a>
         - Unicode/UTF-8 extension for FPDF</li>
     <li><a href="http://www.wikipedia.org/wiki/URL">URL (Uniform Resource Locator)</a>
diff --git a/db_events.php b/db_events.php
new file mode 100644
index 0000000..6b39b83
--- /dev/null
+++ b/db_events.php
@@ -0,0 +1,38 @@
+<?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'][] = 'db_events.js';
+
+/**
+ * Create labels for the list
+ */
+$titles = PMA_buildActionTitles();
+
+/**
+ * Displays the header
+ */
+require_once './libraries/db_common.inc.php';
+
+/**
+ * Displays the tabs
+ */
+require_once './libraries/db_info.inc.php';
+
+/**
+ * Displays the list of events
+ */
+require_once './libraries/db_events.inc.php';
+
+/**
+ * Displays the footer
+ */
+require './libraries/footer.inc.php';
+
+
+?>
diff --git a/db_routines.php b/db_routines.php
new file mode 100644
index 0000000..1d9523e
--- /dev/null
+++ b/db_routines.php
@@ -0,0 +1,443 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * @package phpMyAdmin
+ */
+
+/**
+ * Include required files
+ */
+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';
+
+/**
+ * Include JavaScript libraries
+ */
+$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
+$GLOBALS['js_include'][] = 'jquery/timepicker.js';
+$GLOBALS['js_include'][] = 'db_routines.js';
+
+/**
+ * Create labels for the list
+ */
+$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(__('%s row(s) affected by the last statement inside the procedure'), $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(__('Query "%s" failed'), $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 %s found in database %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)) {
+        PMA_ajaxResponse(PMA_message::error(), 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 %s found in database %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(__('Query "%s" failed'), $drop_routine) . '<br />'
+                                      . __('MySQL said: ') . PMA_DBI_getError(null);
+                } else {
+                    $result = PMA_DBI_try_query($routine_query);
+                    if (! $result) {
+                        $routine_errors[] = sprintf(__('Query "%s" failed'), $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(__('Query "%s" failed'), $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);
+    }
+}
+
+/**
+ * Display a form used to add/edit a routine, if necessary
+ */
+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 %s found in database %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';
+}
+
+?>
diff --git a/db_structure.php b/db_structure.php
index b49b417..0054585 100644
--- a/db_structure.php
+++ b/db_structure.php
@@ -59,14 +59,6 @@ $titles = PMA_buildActionTitles();
 if ($num_tables == 0) {
 	echo '<p>' . __('No tables found in database') . '</p>' . "\n";
 
-	// Routines
-	require './libraries/db_routines.inc.php';
-
-	// Events
-	if (PMA_MYSQL_INT_VERSION > 50100) {
-	    require './libraries/db_events.inc.php';
-	}
-
 	if (empty($db_is_information_schema)) {
 		require './libraries/display_create_table.lib.php';
 	} // end if (Create Table dialog)
@@ -546,13 +538,6 @@ PMA_listNavigator($total_num_tables, $pos, $_url_params, 'db_structure.php', 'fr
 <hr />
 
 <?php
-// Routines
-require './libraries/db_routines.inc.php';
-
-// Events
-if (PMA_MYSQL_INT_VERSION > 50100) {
-    require './libraries/db_events.inc.php';
-}
 
 /**
  * Work on the database
diff --git a/db_triggers.php b/db_triggers.php
new file mode 100644
index 0000000..416be77
--- /dev/null
+++ b/db_triggers.php
@@ -0,0 +1,38 @@
+<?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';
+
+/**
+ * Create labels for the list
+ */
+$titles = PMA_buildActionTitles();
+
+/**
+ * Displays the header
+ */
+require_once './libraries/db_common.inc.php';
+
+/**
+ * Displays the tabs
+ */
+require_once './libraries/db_info.inc.php';
+
+/**
+ * Displays the list of triggers
+ */
+require_once './libraries/display_triggers.inc.php';
+
+/**
+ * Displays the footer
+ */
+require './libraries/footer.inc.php';
+
+
+?>
diff --git a/js/db_events.js b/js/db_events.js
new file mode 100644
index 0000000..3a0ccd5
--- /dev/null
+++ b/js/db_events.js
@@ -0,0 +1,2 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+
diff --git a/js/db_routines.js b/js/db_routines.js
new file mode 100644
index 0000000..1c03b6b
--- /dev/null
+++ b/js/db_routines.js
@@ -0,0 +1,568 @@
+/* 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($('#js_query_display'), 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 style="font-size: 0.9em;">'+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($('#js_query_display'), 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 style="font-size: 0.9em;">'+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($('#js_query_display'), 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/db_structure.js b/js/db_structure.js
index 92dae86..ad55341 100644
--- a/js/db_structure.js
+++ b/js/db_structure.js
@@ -270,80 +270,6 @@ $(document).ready(function() {
     }); //end of Drop Table Ajax action
 
     /**
-     * Ajax Event handler for 'Drop Event'
-     *
-     * @uses    $.PMA_confirm()
-     * @uses    PMA_ajaxShowMessage()
-     * @see     $cfg['AjaxEnable']
-     */
-    $('.drop_event_anchor').live('click', function(event) {
-        event.preventDefault();
-
-        /**
-         * @var curr_event_row  Object reference to current event's row
-         */
-        var curr_event_row = $(this).parents('tr');
-        /**
-         * @var curr_event_name String containing the name of {@link curr_event_row}
-         */
-        var curr_event_name = $(curr_event_row).children('td:first').text();
-        /**
-         * @var question    String containing the question to be asked for confirmation
-         */
-        var question = 'DROP EVENT ' + curr_event_name;
-
-        $(this).PMA_confirm(question, $(this).attr('href') , function(url) {
-
-            PMA_ajaxShowMessage(PMA_messages['strDroppingEvent']);
-
-            $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
-                if(data.success == true) {
-                    PMA_ajaxShowMessage(data.message);
-                    $(curr_event_row).hide("medium").remove();
-                }
-                else {
-                    PMA_ajaxShowMessage(PMA_messages['strErrorProcessingRequest'] + " : " + data.error);
-                }
-            }) // end $.get()
-        }) // end $.PMA_confirm()
-    }) //end Drop Event
-
-    /**
-     * Ajax Event handler for 'Drop Procedure'
-     *
-     * @uses    $.PMA_confirm()
-     * @uses    PMA_ajaxShowMessage()
-     * @see     $cfg['AjaxEnable']
-     */
-    $('.drop_procedure_anchor').live('click', function(event) {
-        event.preventDefault();
-
-        /**
-         * @var curr_proc_row   Object containing reference to the current procedure's row
-         */
-        var curr_proc_row = $(this).parents('tr');
-        /**
-         * @var question    String containing the question to be asked for confirmation
-         */
-        var question = $(curr_proc_row).children('td').children('.drop_procedure_sql').val();
-
-        $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
-
-            PMA_ajaxShowMessage(PMA_messages['strDroppingProcedure']);
-
-            $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
-                if(data.success == true) {
-                    PMA_ajaxShowMessage(data.message);
-                    $(curr_event_row).hide("medium").remove();
-                }
-                else {
-                    PMA_ajaxShowMessage(PMA_messages['strErrorProcessingRequest'] + " : " + data.error);
-                }
-            }) // end $.get()
-        }) // end $.PMA_confirm()
-    }) //end Drop Procedure
-
-    /**
      * Ajax Event handler for 'Drop tracking'
      *
      * @uses    $.PMA_confirm()
diff --git a/js/display_triggers.js b/js/display_triggers.js
new file mode 100644
index 0000000..3a0ccd5
--- /dev/null
+++ b/js/display_triggers.js
@@ -0,0 +1,2 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+
diff --git a/js/functions.js b/js/functions.js
index 6657ac9..14f3b46 100644
--- a/js/functions.js
+++ b/js/functions.js
@@ -1750,46 +1750,6 @@ $(document).ready(function() {
 }, 'top.frame_content'); //end $(document).ready for 'Create Table'
 
 /**
- * Attach Ajax event handlers for Drop Trigger.  Used on tbl_structure.php
- * @see $cfg['AjaxEnable']
- */
-$(document).ready(function() {
-
-    $(".drop_trigger_anchor").live('click', function(event) {
-        event.preventDefault();
-
-        $anchor = $(this);
-        /**
-         * @var curr_row    Object reference to the current trigger's <tr>
-         */
-        var $curr_row = $anchor.parents('tr');
-        /**
-         * @var question    String containing the question to be asked for confirmation
-         */
-        var question = 'DROP TRIGGER IF EXISTS `' + $curr_row.children('td:first').text() + '`';
-
-        $anchor.PMA_confirm(question, $anchor.attr('href'), function(url) {
-
-            PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
-            $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
-                if(data.success == true) {
-                    PMA_ajaxShowMessage(data.message);
-                    $("#topmenucontainer")
-                    .next('div')
-                    .remove()
-                    .end()
-                    .after(data.sql_query);
-                    $curr_row.hide("medium").remove();
-                }
-                else {
-                    PMA_ajaxShowMessage(data.error);
-                }
-            }) // end $.get()
-        }) // end $.PMA_confirm()
-    }) // end $().live()
-}, 'top.frame_content'); //end $(document).ready() for Drop Trigger
-
-/**
  * Attach Ajax event handlers for Drop Database. Moved here from db_structure.js
  * as it was also required on db_create.php
  *
@@ -2448,6 +2408,161 @@ $(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 style="font-size: 0.9em;">'+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   $obj   a jQuery object containing the reference
+ *                 to the element where to put the message
+ * @param   msg    A string containing the text to display
+ *
+ * @return  bool   True on success, false on failure
+ */
+function PMA_slidingMessage($obj, msg) {
+    if ($obj != 'undefined' && $obj instanceof jQuery) {
+        if ($obj.has('div').length > 0) {
+            // If there already is a message inside the
+            // target object, we must get rid of it
+            $obj
+            .append('<div style="display: none;">' + msg + '</div>')
+            .find('div')
+            .first()
+            .fadeOut(function () {
+                $(this).remove();
+                $obj.animate({
+                    height: $obj.find('div').first().height()
+                });
+                $obj
+                .find('div')
+                .first()
+                .fadeIn();
+            });
+        } else {
+            // Object does not already have a message
+            // inside it, so we simply slide it down
+            $obj
+            .width('100%')
+            .html('<div style="display: none;">' + msg + '</div>')
+            .find('div')
+            .first()
+            .slideDown(function() {
+                // Set the height of the parent
+                // to the height of the child
+                $obj
+                .height(
+                    $obj
+                    .find('div')
+                    .first()
+                    .height()
+                );
+            });
+        }
+        return true;
+    } else {
+        return false;
+    }
+} // 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($('#js_query_display'), 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 6863532..18cb752 100644
--- a/js/messages.php
+++ b/js/messages.php
@@ -31,8 +31,6 @@ $js_messages['strDoYouReally'] = __('Do you really want to ');
 $js_messages['strDropDatabaseStrongWarning'] = __('You are about to DESTROY a complete database!');
 $js_messages['strDropTableStrongWarning'] = __('You are about to DESTROY a complete table!');
 $js_messages['strTruncateTableStrongWarning'] = __('You are about to TRUNCATE a complete table!');
-$js_messages['strDroppingEvent'] = __('Dropping Event');
-$js_messages['strDroppingProcedure'] = __('Dropping Procedure');
 $js_messages['strDeleteTrackingData'] = __('Delete tracking data for this table');
 $js_messages['strDeletingTrackingData'] = __('Deleting tracking data');
 $js_messages['strDroppingPrimaryKeyIndex'] = __('Dropping Primary Key/Index');
@@ -120,6 +118,10 @@ $js_messages['strShowSearchResults'] = __('Show search results');
 $js_messages['strBrowsing'] = __('Browsing');
 $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/libraries/common.inc.php b/libraries/common.inc.php
index 5be5c76..a0b8628 100644
--- a/libraries/common.inc.php
+++ b/libraries/common.inc.php
@@ -371,6 +371,7 @@ $goto_whitelist = array(
     'db_operations.php',
     'db_printview.php',
     'db_search.php',
+    'db_routines.php',
     //'Documentation.html',
     'export.php',
     'import.php',
diff --git a/libraries/common.lib.php b/libraries/common.lib.php
index d2c8249..a9b87f9 100644
--- a/libraries/common.lib.php
+++ b/libraries/common.lib.php
@@ -840,7 +840,6 @@ function PMA_backquote($a_name, $do_it = true)
     }
 } // end of the 'PMA_backquote()' function
 
-
 /**
  * Defines the <CR><LF> value depending on the user OS.
  *
@@ -2959,6 +2958,275 @@ function PMA_buildActionTitles() {
     $titles['Empty']      = PMA_getIcon('b_empty.png', __('Empty'), true);
     $titles['NoEmpty']    = PMA_getIcon('bd_empty.png', __('Empty'), true);
     $titles['Edit']       = PMA_getIcon('b_edit.png', __('Edit'), true);
+    $titles['NoEdit']     = PMA_getIcon('bd_edit.png', __('Edit'), true);
+    $titles['Export']     = PMA_getIcon('b_export.png', __('Export'), true);
+    $titles['NoExport']   = PMA_getIcon('bd_export.png', __('Export'), true);
+    $titles['Execute']    = PMA_getIcon('b_nextpage.png', __('Execute'), true);
+    $titles['NoExecute']  = PMA_getIcon('bd_nextpage.png', __('Execute'), true);
     return $titles;
 }
+
+/**
+ * This function processes the datatypes supported by the DB, as specified in
+ * $cfg['ColumnTypes'] and either returns an array (useful for quickly checking
+ * if a datatype is supported) or an HTML snippet that creates a drop-down list.
+ *
+ * @param   bool    $html       Whether to generate an html snippet or an array
+ * @param   string  $selected   The value to mark as selected in HTML mode
+ *
+ * @return  mixed   An HTML snippet or an array of datatypes.
+ *
+ * @uses    htmlspecialchars()
+ * @uses    in_array()
+ */
+function PMA_getSupportedDatatypes($html = false, $selected = '')
+{
+    global $cfg;
+
+    if ($html) {
+        // NOTE: the SELECT tag in not included in this snippet.
+        $retval = '';
+        foreach ($cfg['ColumnTypes'] as $key => $value) {
+            if (is_array($value)) {
+                $retval .= "<optgroup label='" . htmlspecialchars($key) . "'>";
+                foreach ($value as $subkey => $subvalue) {
+                    if ($subvalue == $selected) {
+                        $retval .= "<option selected='selected'>";
+                        $retval .= $subvalue;
+                        $retval .= "</option>";
+                    } else if ($subvalue === '-') {
+                        $retval .= "<option disabled='disabled'>";
+                        $retval .= $subvalue;
+                        $retval .= "</option>";
+                    } else {
+                        $retval .= "<option>$subvalue</option>";
+                    }
+                }
+                $retval .= '</optgroup>';
+            } else {
+                if ($selected == $value) {
+                    $retval .= "<option selected='selected'>$value</option>";
+                } else {
+                    $retval .= "<option>$value</option>";
+                }
+            }
+        }
+    } else {
+        $retval = array();
+        foreach ($cfg['ColumnTypes'] as $key => $value) {
+            if (is_array($value)) {
+                foreach ($value as $subkey => $subvalue) {
+                    if ($subvalue !== '-') {
+                        $retval[] = $subvalue;
+                    }
+                }
+            } else {
+                if ($value !== '-') {
+                    $retval[] = $value;
+                }
+            }
+        }
+    }
+
+    return $retval;
+} // end PMA_getSupportedDatatypes()
+
+/**
+ * Returns a list of datatypes that are not (yet) handled by PMA.
+ * Used by: tbl_change.php and libraries/db_routines.inc.php
+ *
+ * @return   array   list of datatypes
+ */
+
+function PMA_unsupportedDatatypes() {
+    // These GIS data types are not yet supported.
+    $no_support_types = array('geometry',
+                              'point',
+                              'linestring',
+                              'polygon',
+                              'multipoint',
+                              'multilinestring',
+                              'multipolygon',
+                              'geometrycollection'
+                        );
+
+    return $no_support_types;
+}
+
+/**
+ * Creates a dropdown box with MySQL functions for a particular column.
+ *
+ * @param    array    $field          Data about the column for which
+ *                                    to generate the dropdown
+ * @param    bool     $insert_mode    Whether the operation is 'insert'
+ *
+ * @global   array    $cfg            PMA configuration
+ * @global   array    $analyzed_sql   Analyzed SQL query
+ * @global   mixed    $data           (null/string) FIXME: what is this for?
+ *
+ * @return   string   An HTML snippet of a dropdown list with function
+ *                    names appropriate for the requested column.
+ */
+function PMA_getFunctionsForField($field, $insert_mode)
+{
+    global $cfg, $analyzed_sql, $data;
+
+    $selected = '';
+    // Find the current type in the RestrictColumnTypes. Will result in 'FUNC_CHAR'
+    // or something similar. Then directly look up the entry in the RestrictFunctions array,
+    // which will then reveal the available dropdown options
+    if (isset($cfg['RestrictColumnTypes'][strtoupper($field['True_Type'])])
+     && isset($cfg['RestrictFunctions'][$cfg['RestrictColumnTypes'][strtoupper($field['True_Type'])]])) {
+        $current_func_type  = $cfg['RestrictColumnTypes'][strtoupper($field['True_Type'])];
+        $dropdown           = $cfg['RestrictFunctions'][$current_func_type];
+        $default_function   = $cfg['DefaultFunctions'][$current_func_type];
+    } else {
+        $dropdown = array();
+        $default_function   = '';
+    }
+    $dropdown_built = array();
+    $op_spacing_needed = false;
+    // what function defined as default?
+    // for the first timestamp we don't set the default function
+    // if there is a default value for the timestamp
+    // (not including CURRENT_TIMESTAMP)
+    // and the column does not have the
+    // ON UPDATE DEFAULT TIMESTAMP attribute.
+    if ($field['True_Type'] == 'timestamp'
+      && empty($field['Default'])
+      && empty($data)
+      && ! isset($analyzed_sql[0]['create_table_fields'][$field['Field']]['on_update_current_timestamp'])) {
+        $default_function = $cfg['DefaultFunctions']['first_timestamp'];
+    }
+    // For primary keys of type char(36) or varchar(36) UUID if the default function
+    // Only applies to insert mode, as it would silently trash data on updates.
+    if ($insert_mode
+        && $field['Key'] == 'PRI'
+        && ($field['Type'] == 'char(36)' || $field['Type'] == 'varchar(36)')
+    ) {
+         $default_function = $cfg['DefaultFunctions']['pk_char36'];
+    }
+    // this is set only when appropriate and is always true
+    if (isset($field['display_binary_as_hex'])) {
+        $default_function = 'UNHEX';
+    }
+
+    // Create the output
+    $retval = '                <option></option>' . "\n";
+    // loop on the dropdown array and print all available options for that field.
+    foreach ($dropdown as $each_dropdown){
+        $retval .= '                ';
+        $retval .= '<option';
+        if ($default_function === $each_dropdown) {
+            $retval .= ' selected="selected"';
+        }
+        $retval .= '>' . $each_dropdown . '</option>' . "\n";
+        $dropdown_built[$each_dropdown] = 'true';
+        $op_spacing_needed = true;
+    }
+    // For compatibility's sake, do not let out all other functions. Instead
+    // print a separator (blank) and then show ALL functions which weren't shown
+    // yet.
+    $cnt_functions = count($cfg['Functions']);
+    for ($j = 0; $j < $cnt_functions; $j++) {
+        if (! isset($dropdown_built[$cfg['Functions'][$j]]) || $dropdown_built[$cfg['Functions'][$j]] != 'true') {
+            // Is current function defined as default?
+            $selected = ($field['first_timestamp'] && $cfg['Functions'][$j] == $cfg['DefaultFunctions']['first_timestamp'])
+                        || (!$field['first_timestamp'] && $cfg['Functions'][$j] == $default_function)
+                      ? ' selected="selected"'
+                      : '';
+            if ($op_spacing_needed == true) {
+                $retval .= '                ';
+                $retval .= '<option value="">--------</option>' . "\n";
+                $op_spacing_needed = false;
+            }
+
+            $retval .= '                ';
+            $retval .= '<option' . $selected . '>' . $cfg['Functions'][$j] . '</option>' . "\n";
+        }
+    } // end for
+
+    return $retval;
+} // end PMA_getFunctionsForField()
+
+/**
+ * Checks if the current user has a specific privilege and returns true if the
+ * user indeed has that privilege or false if (s)he doesn't. This function must
+ * only be used for features that are available since MySQL 5, because it
+ * relies on the INFORMATION_SCHEMA database to be present.
+ *
+ * Example:   PMA_currentUserHasPrivilege('CREATE ROUTINE', 'mydb');
+ *            // Checks if the currently logged in user has the global
+ *            // 'CREATE ROUTINE' privilege or, if not, checks if the
+ *            // user has this privilege on database 'mydb'.
+ *
+ * @uses    PMA_DBI_fetch_value()
+ * @uses    explode()
+ * @uses    str_replace()
+ * @uses    sprintf()
+ *
+ * @param   string   $priv   The privilege to check
+ * @param   mixed    $db     null, to only check global privileges
+ *                           string, db name where to also check for privileges
+ * @param   mixed    $tbl    null, to only check global privileges
+ *                           string, db name where to also check for privileges
+ */
+function PMA_currentUserHasPrivilege($priv, $db = null, $tbl = null)
+{
+    // Get the username for the current user in the format
+    // required to use in the information schema database.
+    $user = PMA_DBI_fetch_value("SELECT CURRENT_USER();");
+    if ($user === false) {
+        return false;
+    }
+    $user = explode('@', $user);
+    $username  = "''";
+    $username .= str_replace("'", "''", $user[0]);
+    $username .= "''@''";
+    $username .= str_replace("'", "''", $user[1]);
+    $username .= "''";
+    // Prepage the query
+    $query = "SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`%s` "
+           . "WHERE GRANTEE='%s' AND PRIVILEGE_TYPE='%s'";
+    // Check global privileges first.
+    if (PMA_DBI_fetch_value(sprintf($query,
+                                    'USER_PRIVILEGES',
+                                    $username,
+                                    $priv))) {
+        return true;
+    }
+    // If a database name was provided and user does not have the
+    // required global privilege, try database-wise permissions.
+    if ($db !== null) {
+        $query .= " AND TABLE_SCHEMA='%s'";
+        if (PMA_DBI_fetch_value(sprintf($query,
+                                        'SCHEMA_PRIVILEGES',
+                                        $username,
+                                        $priv,
+                                        PMA_sqlAddslashes($db)))) {
+            return true;
+        }
+    } else {
+        // There was no database name provided and the user
+        // does not have the correct global privilege.
+        return false;
+    }
+    // If a table name was also provided and we still didn't
+    // find any valid privileges, try table-wise privileges.
+    if ($tbl !== null) {
+        $query .= " AND TABLE_NAME='%s'";
+        if ($retval = PMA_DBI_fetch_value(sprintf($query,
+                                                  'TABLE_PRIVILEGES',
+                                                  $username,
+                                                  $priv,
+                                                  PMA_sqlAddslashes($db),
+                                                  PMA_sqlAddslashes($tbl)))) {
+            return true;
+        }
+    }
+    // If we reached this point, the user does not
+    // have even valid table-wise privileges.
+    return false;
+}
+
 ?>
diff --git a/libraries/database_interface.lib.php b/libraries/database_interface.lib.php
index d8d48df..5e61ef8 100644
--- a/libraries/database_interface.lib.php
+++ b/libraries/database_interface.lib.php
@@ -1424,7 +1424,7 @@ function PMA_DBI_get_definition($db, $which, $name, $link = null)
 }
 
 /**
- * returns details about the TRIGGERs of a specific table
+ * returns details about the TRIGGERs for a specific table or database
  *
  * @uses    PMA_DBI_fetch_result()
  * @param   string              $db     db name
@@ -1433,20 +1433,25 @@ function PMA_DBI_get_definition($db, $which, $name, $link = null)
  *
  * @return  array               information about triggers (may be empty)
  */
-function PMA_DBI_get_triggers($db, $table, $delimiter = '//')
+function PMA_DBI_get_triggers($db, $table = '', $delimiter = '//')
 {
     $result = array();
-
     if (! $GLOBALS['cfg']['Server']['DisableIS']) {
-    // 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'
-        $triggers = PMA_DBI_fetch_result("SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, ACTION_TIMING, ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA= '" . PMA_sqlAddslashes($db,true) . "' and EVENT_OBJECT_TABLE = '" . PMA_sqlAddslashes($table, true) . "';");
+        // 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) . "';";
+        if (! empty($table)) {
+            $query .= " AND EVENT_OBJECT_TABLE = '" . PMA_sqlAddslashes($table, true) . "';";
+        }
     } else {
-        $triggers = PMA_DBI_fetch_result("SHOW TRIGGERS FROM " . PMA_backquote(PMA_sqlAddslashes($db,true)) . " LIKE '" . PMA_sqlAddslashes($table, true) . "';");
+        $query = "SHOW TRIGGERS FROM " . PMA_backquote(PMA_sqlAddslashes($db,true));
+        if (! empty($table)) {
+            $query .= " LIKE '" . PMA_sqlAddslashes($table, true) . "';";
+        }
     }
 
-    if ($triggers) {
+    if ($triggers = PMA_DBI_fetch_result($query)) {
         foreach ($triggers as $trigger) {
             if ($GLOBALS['cfg']['Server']['DisableIS']) {
                 $trigger['TRIGGER_NAME'] = $trigger['Trigger'];
@@ -1457,6 +1462,7 @@ function PMA_DBI_get_triggers($db, $table, $delimiter = '//')
             }
             $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'];
 
diff --git a/libraries/db_events.inc.php b/libraries/db_events.inc.php
index 6e93299..f924026 100644
--- a/libraries/db_events.inc.php
+++ b/libraries/db_events.inc.php
@@ -10,52 +10,139 @@ if (! defined('PHPMYADMIN')) {
 
 $events = PMA_DBI_fetch_result('SELECT EVENT_NAME, EVENT_TYPE FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'' . PMA_sqlAddslashes($db,true) . '\';');
 
-if ($events) {
-    PMA_generate_slider_effect('events', __('Events'));
-    echo '<fieldset>' . "\n";
-    echo ' <legend>' . __('Events') . '</legend>' . "\n";
-    echo '<table border="0">';
+$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> </th>
-                      <th> </th>
+                      <th colspan="3">%s</th>
                       <th>%s</th>
                 </tr>',
           __('Name'),
+          __('Action'),
           __('Type'));
     $ct=0;
     $delimiter = '//';
-    if ($GLOBALS['cfg']['AjaxEnable']) {
-        $conditional_class = 'class="drop_event_anchor"';
-    } else {
-        $conditional_class = '';
-    }
     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
 
-        $definition = 'DROP EVENT ' . PMA_backquote($event['EVENT_NAME']) . $delimiter . "\n"
-            .  PMA_DBI_get_definition($db, 'EVENT', $event['EVENT_NAME'])
-            . "\n";
+        $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><strong>%s</strong></td>
+                          <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['Structure']) : ' ',
-                     '<a ' . $conditional_class . ' href="sql.php?' . $url_query . '&sql_query=' . urlencode($sqlDrop) . '" >' . $titles['Drop'] . '</a>',
+                     ! 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";
-    echo '</div>' . "\n";
 }
+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') . __('The event scheduler is ') . $es_state . ':'
+       . '    <a href="db_events.php?' . $url_query . '&toggle_scheduler=' . $es_change . '">'
+       . __('Turn') . " $es_change\n" .  '</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 a new 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 7eaf343..cb276d5 100644
--- a/libraries/db_links.inc.php
+++ b/libraries/db_links.inc.php
@@ -93,6 +93,17 @@ if (! $db_is_information_schema) {
         $tab_privileges['text'] = __('Privileges');
         $tab_privileges['icon'] = 's_rights.png';
     }
+    $tab_routines['link']   = 'db_routines.php';
+    $tab_routines['text']   = __('Routines');
+    $tab_routines['icon']   = 'b_routines.png';
+
+    $tab_events['link']     = 'db_events.php';
+    $tab_events['text']     = __('Events');
+    $tab_events['icon']     = 'b_events.png';
+
+    $tab_triggers['link']   = 'db_triggers.php';
+    $tab_triggers['text']   = __('Triggers');
+    $tab_triggers['icon']   = 'b_triggers.png';
 }
 
 /**
@@ -110,6 +121,15 @@ if (! $db_is_information_schema) {
     if ($is_superuser) {
         $tabs[] =& $tab_privileges;
     }
+    if (PMA_MYSQL_INT_VERSION >= 50002 && ! PMA_DRIZZLE) {
+        $tabs[] =& $tab_routines;
+    }
+    if (PMA_MYSQL_INT_VERSION >= 50106 && ! PMA_DRIZZLE) {
+        $tabs[] =& $tab_events;
+    }
+    if (PMA_MYSQL_INT_VERSION >= 50002 && ! PMA_DRIZZLE) {
+        $tabs[] =& $tab_triggers;
+    }
 }
 if (PMA_Tracker::isActive()) {
     $tabs[] =& $tab_tracking;
diff --git a/libraries/db_routines.inc.php b/libraries/db_routines.inc.php
deleted file mode 100644
index d6a5b07..0000000
--- a/libraries/db_routines.inc.php
+++ /dev/null
@@ -1,94 +0,0 @@
-<?php
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-/**
- *
- * @todo Support seeing the "results" of the called procedure or
- *       function. This needs further reseach because a procedure
- *       does not necessarily contain a SELECT statement that
- *       produces something to see. But it seems we could at least
- *       get the number of rows affected. We would have to
- *       use the CLIENT_MULTI_RESULTS flag to get the result set
- *       and also the call status. All this does not fit well with
- *       our current sql.php.
- *       Of course the interface would need a way to pass calling parameters.
- *       Also, support DEFINER (like we do in export).
- * @package phpMyAdmin
- */
-if (! defined('PHPMYADMIN')) {
-    exit;
-}
-
-$routines = PMA_DBI_fetch_result('SELECT SPECIFIC_NAME,ROUTINE_NAME,ROUTINE_TYPE,DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA= \'' . PMA_sqlAddslashes($db,true) . '\';');
-
-if ($routines) {
-    PMA_generate_slider_effect('routines', __('Routines'));
-    echo '<fieldset>' . "\n";
-    echo ' <legend>' . __('Routines') . '</legend>' . "\n";
-    echo '<table border="0">';
-    echo sprintf('<tr>
-                      <th>%s</th>
-                      <th> </th>
-                      <th> </th>
-                      <th>%s</th>
-                      <th>%s</th>
-                </tr>',
-          __('Name'),
-          __('Type'),
-          __('Return type'));
-    $ct=0;
-    $delimiter = '//';
-    if ($GLOBALS['cfg']['AjaxEnable']) {
-        $conditional_class = 'class="drop_procedure_anchor"';
-    } else {
-        $conditional_class = '';
-    }
-
-    foreach ($routines as $routine) {
-
-        // information_schema (at least in MySQL 5.0.45)
-        // does not return the routine parameters
-        // so we rely on PMA_DBI_get_definition() which
-        // uses SHOW CREATE
-
-        $definition = 'DROP ' . $routine['ROUTINE_TYPE'] . ' ' . PMA_backquote($routine['SPECIFIC_NAME']) . $delimiter . "\n"
-            .  PMA_DBI_get_definition($db, $routine['ROUTINE_TYPE'], $routine['SPECIFIC_NAME'])
-            . "\n";
-
-        //if ($routine['ROUTINE_TYPE'] == 'PROCEDURE') {
-        //    $sqlUseProc  = 'CALL ' . $routine['SPECIFIC_NAME'] . '()';
-        //} else {
-        //    $sqlUseProc = 'SELECT ' . $routine['SPECIFIC_NAME'] . '()';
-            /* this won't get us far: to really use the function
-               i'd need to know how many parameters the function needs and then create
-               something to ask for them. As i don't see this directly in
-               the table i am afraid that requires parsing the ROUTINE_DEFINITION
-               and i don't really need that now so i simply don't offer
-               a method for running the function*/
-        //}
-        if ($routine['ROUTINE_TYPE'] == 'PROCEDURE') {
-            $sqlDropProc = 'DROP PROCEDURE ' . PMA_backquote($routine['SPECIFIC_NAME']);
-        } else {
-            $sqlDropProc = 'DROP FUNCTION ' . PMA_backquote($routine['SPECIFIC_NAME']);
-        }
-
-        echo sprintf('<tr class="%s">
-                          <td><input type="hidden" class="drop_procedure_sql" value="%s" /><strong>%s</strong></td>
-                          <td>%s</td>
-                          <td>%s</td>
-                          <td>%s</td>
-                          <td>%s</td>
-                     </tr>',
-                     ($ct%2 == 0) ? 'even' : 'odd',
-                     $sqlDropProc,
-                     $routine['ROUTINE_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']) : ' ',
-                     '<a ' . $conditional_class . ' href="sql.php?' . $url_query . '&sql_query=' . urlencode($sqlDropProc) . '" >' . $titles['Drop'] . '</a>',
-                     $routine['ROUTINE_TYPE'],
-                     $routine['DTD_IDENTIFIER']);
-        $ct++;
-    }
-    echo '</table>';
-    echo '</fieldset>' . "\n";
-    echo '</div>' . "\n";
-}
-?>
diff --git a/libraries/db_routines.lib.php b/libraries/db_routines.lib.php
new file mode 100644
index 0000000..13859cf
--- /dev/null
+++ b/libraries/db_routines.lib.php
@@ -0,0 +1,1265 @@
+<?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
+ *
+ * @uses    PMA_SQP_parse()
+ * @uses    PMA_unquote()
+ * @uses    in_array()
+ * @uses    strtoupper()
+ * @uses    strtolower()
+ * @uses    sort()
+ * @uses    implode()
+ */
+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.
+ *
+ * @uses    PMA_RTN_parseOneParameter()
+ */
+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.
+ *
+ * @uses    substr()
+ * @uses    PMA_unQuote()
+ */
+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.
+ *
+ * @uses    PMA_sqlAddslashes()
+ * @uses    PMA_DBI_fetch_single_row()
+ * @uses    PMA_SQP_parse()
+ * @uses    PMA_DBI_get_definition()
+ * @uses    PMA_RTN_parseAllParameters()
+ * @uses    PMA_RTN_parseRoutineDefiner()
+ * @uses    PMA_RTN_parseOneParameter()
+ */
+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.
+ *
+ * @uses    isset()
+ * @uses    is_array()
+ * @uses    in_array()
+ * @uses    strtolower()
+ * @uses    PMA_getSupportedDatatypes()
+ */
+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.
+ *
+ * @uses    PMA_getSupportedDatatypes()
+ * @uses    PMA_getSupportedCharsets()
+ */
+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.
+ *
+ * @uses    htmlentities()
+ * @uses    PMA_generate_common_hidden_inputs()
+ * @uses    strtoupper()
+ * @uses    PMA_getSupportedDatatypes()
+ * @uses    PMA_getSupportedCharsets()
+ */
+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.
+ *
+ * @uses    PMA_generate_common_hidden_inputs()
+ * @uses    PMA_unsupportedDatatypes()
+ * @uses    stristr()
+ * @uses    in_array()
+ * @uses    strtolower()
+ * @uses    strtoupper()
+ * @uses    isset()
+ * @uses    PMA_SQP_parse()
+ * @uses    htmlentities()
+ * @uses    PMA_unquote()
+ */
+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.
+ *
+ * @uses    explode()
+ * @uses    strpos()
+ * @uses    PMA_backquote()
+ * @uses    sprintf()
+ * @uses    htmlspecialchars()
+ * @uses    is_array()
+ * @uses    preg_match()
+ * @uses    count()
+ * @uses    strtoupper()
+ * @uses    strtolower()
+ */
+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.
+ *
+ * @uses    sprintf()
+ * @uses    PMA_currentUserHasPrivilege()
+ * @uses    PMA_backquote
+ * @uses    PMA_RTN_getRoutineDataFromName()
+ * @uses    htmlspecialchars()
+ * @uses    urlencode()
+ */
+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.
+ *
+ * @uses    PMA_sqlAddslashes()
+ * @uses    PMA_DBI_fetch_result()
+ * @uses    PMA_RTN_getRowForRoutinesList()
+ */
+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.
+ *
+ * @uses    PMA_currentUserHasPrivilege()
+ * @uses    PMA_getIcon()
+ * @uses    PMA_showMySQLDocu()
+ */
+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/dbi/mysql.dbi.lib.php b/libraries/dbi/mysql.dbi.lib.php
index e84e6b0..5cbb4fa 100644
--- a/libraries/dbi/mysql.dbi.lib.php
+++ b/libraries/dbi/mysql.dbi.lib.php
@@ -208,6 +208,32 @@ function PMA_DBI_free_result()
 }
 
 /**
+ * Check if there are any more query results from a multi query
+ *
+ * @return  boolean         false
+ */
+function PMA_DBI_more_results() {
+    // N.B.: PHP's 'mysql' extension does not support
+    // multi_queries so this function will always
+    // return false. Use the 'mysqli' extension, if
+    // you need support for multi_queries.
+    return false;
+}
+
+/**
+ * Prepare next result from multi_query
+ *
+ * @return  boolean         false
+ */
+function PMA_DBI_next_result() {
+    // N.B.: PHP's 'mysql' extension does not support
+    // multi_queries so this function will always
+    // return false. Use the 'mysqli' extension, if
+    // you need support for multi_queries.
+    return false;
+}
+
+/**
  * Returns a string representing the type of connection used
  * @uses    mysql_get_host_info()
  * @uses    $GLOBALS['userlink']    as default for $link
diff --git a/libraries/dbi/mysqli.dbi.lib.php b/libraries/dbi/mysqli.dbi.lib.php
index 2418fd2..bee7430 100644
--- a/libraries/dbi/mysqli.dbi.lib.php
+++ b/libraries/dbi/mysqli.dbi.lib.php
@@ -255,6 +255,44 @@ function PMA_DBI_free_result()
 }
 
 /**
+ * Check if there are any more query results from a multi query
+ *
+ * @uses    $GLOBALS['userlink']
+ * @uses    mysqli_more_results()
+ * @param   object mysqli   $link   the mysqli object
+ * @return  boolean         true or false
+ */
+function PMA_DBI_more_results($link = null) {
+    if (empty($link)) {
+        if (isset($GLOBALS['userlink'])) {
+            $link = $GLOBALS['userlink'];
+        } else {
+            return false;
+        }
+    }
+    return mysqli_more_results($link);
+}
+
+/**
+ * Prepare next result from multi_query
+ *
+ * @uses    $GLOBALS['userlink']
+ * @uses    mysqli_next_result()
+ * @param   object mysqli   $link   the mysqli object
+ * @return  boolean         true or false
+ */
+function PMA_DBI_next_result($link = null) {
+    if (empty($link)) {
+        if (isset($GLOBALS['userlink'])) {
+            $link = $GLOBALS['userlink'];
+        } else {
+            return false;
+        }
+    }
+    return mysqli_next_result($link);
+}
+
+/**
  * Returns a string representing the type of connection used
  * @uses    mysqli_get_host_info()
  * @uses    $GLOBALS['userlink']    as default for $link
diff --git a/libraries/display_triggers.inc.php b/libraries/display_triggers.inc.php
new file mode 100644
index 0000000..aa4583e
--- /dev/null
+++ b/libraries/display_triggers.inc.php
@@ -0,0 +1,123 @@
+<?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 new Trigger') . '</a>' . "\n"
+   . '</fieldset>' . "\n";
+
+?>
diff --git a/libraries/tbl_links.inc.php b/libraries/tbl_links.inc.php
index e31dd53..66df327 100644
--- a/libraries/tbl_links.inc.php
+++ b/libraries/tbl_links.inc.php
@@ -40,6 +40,13 @@ $err_url   = $cfg['DefaultTabTable'] . PMA_generate_common_url($url_params);
 require_once './libraries/header.inc.php';
 
 /**
+ * Ensure that $db_is_information_schema is not null
+ */
+if (! isset($db_is_information_schema)) {
+    $db_is_information_schema = false;
+}
+
+/**
  * Displays links
  */
 $tabs = array();
@@ -61,7 +68,7 @@ $tabs['search']['icon'] = 'b_search.png';
 $tabs['search']['text'] = __('Search');
 $tabs['search']['link'] = 'tbl_select.php';
 
-if (! (isset($db_is_information_schema) && $db_is_information_schema)) {
+if (!$db_is_information_schema) {
     $tabs['insert']['icon'] = 'b_insrow.png';
     $tabs['insert']['link'] = 'tbl_change.php';
     $tabs['insert']['text'] = __('Insert');
@@ -76,7 +83,7 @@ $tabs['export']['text'] = __('Export');
  * Don't display "Import" and "Operations"
  * for views and information_schema
  */
-if (! $tbl_is_view && ! (isset($db_is_information_schema) && $db_is_information_schema)) {
+if (! $tbl_is_view && !$db_is_information_schema) {
     $tabs['import']['icon'] = 'b_tblimport.png';
     $tabs['import']['link'] = 'tbl_import.php';
     $tabs['import']['text'] = __('Import');
@@ -90,13 +97,16 @@ if(PMA_Tracker::isActive()) {
     $tabs['tracking']['text'] = __('Tracking');
     $tabs['tracking']['link'] = 'tbl_tracking.php';
 }
-if (! $tbl_is_view && ! (isset($db_is_information_schema) && $db_is_information_schema)) {
+if (! $db_is_information_schema && PMA_MYSQL_INT_VERSION >= 50002 && ! PMA_DRIZZLE) {
+    $tabs['triggers']['link'] = 'tbl_triggers.php';
+    $tabs['triggers']['text'] = __('Triggers');
+    $tabs['triggers']['icon'] = 'b_triggers.png';
 }
 
 /**
  * Views support a limited number of operations
  */
-if ($tbl_is_view && ! (isset($db_is_information_schema) && $db_is_information_schema)) {
+if ($tbl_is_view && !$db_is_information_schema) {
     $tabs['operation']['icon'] = 'b_tblops.png';
     $tabs['operation']['link'] = 'view_operations.php';
     $tabs['operation']['text'] = __('Operations');
diff --git a/libraries/tbl_properties.inc.php b/libraries/tbl_properties.inc.php
index 4f1b647..8edc3ea 100644
--- a/libraries/tbl_properties.inc.php
+++ b/libraries/tbl_properties.inc.php
@@ -14,6 +14,7 @@ if (! defined('PHPMYADMIN')) {
  * Check parameters
  */
 require_once './libraries/common.inc.php';
+require_once './libraries/common.lib.php';
 PMA_checkParameters(array('db', 'table', 'action', 'num_fields'));
 
 
@@ -322,27 +323,7 @@ for ($i = 0; $i < $num_fields; $i++) {
     $type = rtrim($type);
     $type_upper = strtoupper($type);
 
-    foreach ($cfg['ColumnTypes'] as $col_goup => $column_type) {
-        if (is_array($column_type)) {
-            $content_cells[$i][$ci] .= '<optgroup label="' . htmlspecialchars($col_goup) . '">';
-            foreach ($column_type as $col_group_type) {
-                $content_cells[$i][$ci] .= '<option value="'. $col_group_type . '"';
-                if ($type_upper == strtoupper($col_group_type)) {
-                    $content_cells[$i][$ci] .= ' selected="selected"';
-                }
-                $content_cells[$i][$ci] .= '>' . $col_group_type . '</option>';
-            }
-            $content_cells[$i][$ci] .= '</optgroup>';
-            continue;
-        }
-
-        $content_cells[$i][$ci] .= '<option value="'. $column_type . '"';
-        if ($type_upper == strtoupper($column_type)) {
-            $content_cells[$i][$ci] .= ' selected="selected"';
-        }
-        $content_cells[$i][$ci] .= '>' . $column_type . '</option>';
-    } // end for
-
+    $content_cells[$i][$ci] .= PMA_getSupportedDatatypes(true, $type_upper);
     $content_cells[$i][$ci] .= '    </select>';
     $ci++;
 
diff --git a/libraries/tbl_triggers.inc.php b/libraries/tbl_triggers.inc.php
deleted file mode 100644
index 0663ef4..0000000
--- a/libraries/tbl_triggers.inc.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/* vim: set expandtab sw=4 ts=4 sts=4: */
-/**
- *
- * @package phpMyAdmin
- */
-if (! defined('PHPMYADMIN')) {
-    exit;
-}
-
-$url_query .= '&goto=tbl_structure.php';
-
-$triggers = PMA_DBI_get_triggers($db, $table);
-
-if ($triggers) {
-    echo '<div id="tabletriggers">' . "\n";
-    echo '<table class="data">' . "\n";
-    echo ' <caption class="tblHeaders">' . __('Triggers') . '</caption>'  . "\n";
-    echo sprintf('<tr>
-                          <th>%s</th>
-                          <th> </th>
-                          <th> </th>
-                          <th>%s</th>
-                          <th>%s</th>
-                    </tr>',
-              __('Name'),
-              __('Time'),
-              __('Event'));
-    $ct=0;
-    $delimiter = '//';
-    if ($GLOBALS['cfg']['AjaxEnable']) {
-        $conditional_class = 'class="drop_trigger_anchor"';
-    } else {
-        $conditional_class = '';
-    }
-
-    foreach ($triggers as $trigger) {
-        $drop_and_create = $trigger['drop'] . $delimiter . "\n" . $trigger['create'] . "\n";
-
-        echo sprintf('<tr class="noclick %s">
-                              <td><strong>%s</strong></td>
-                              <td>%s</td>
-                              <td>%s</td>
-                              <td>%s</td>
-                              <td>%s</td>
-                         </tr>',
-                         ($ct%2 == 0) ? 'even' : 'odd',
-                         $trigger['name'],
-                         PMA_linkOrButton('tbl_sql.php?' . $url_query . '&sql_query=' . urlencode($drop_and_create) . '&show_query=1&delimiter=' . urlencode($delimiter), $titles['Change']),
-                         '<a ' . $conditional_class . ' href="sql.php?' . $url_query . '&sql_query=' . urlencode($trigger['drop']) . '" >' . $titles['Drop'] . '</a>',
-                         $trigger['action_timing'],
-                         $trigger['event_manipulation']);
-        $ct++;
-    }
-    echo '</table>';
-    echo '</div>' . "\n";
-}
-?>
diff --git a/sql.php b/sql.php
index f4ea949..7da775a 100644
--- a/sql.php
+++ b/sql.php
@@ -449,6 +449,15 @@ if (isset($GLOBALS['show_as_php']) || !empty($GLOBALS['validatequery'])) {
 
     $result   = @PMA_DBI_try_query($full_sql_query, null, PMA_DBI_QUERY_STORE);
 
+    // If a stored procedure was called, there may be more results that are
+    // queued up and waiting to be flushed from the buffer. So let's do that.
+    while (true) {
+        if(! PMA_DBI_more_results()) {
+            break;
+        }
+        PMA_DBI_next_result();
+    }
+
     $querytime_after = array_sum(explode(' ', microtime()));
 
     $GLOBALS['querytime'] = $querytime_after - $querytime_before;
diff --git a/tbl_change.php b/tbl_change.php
index 4adaf40..94c7da0 100644
--- a/tbl_change.php
+++ b/tbl_change.php
@@ -12,6 +12,7 @@
  * Gets the variables sent or posted to this script and displays the header
  */
 require_once './libraries/common.inc.php';
+require_once './libraries/common.lib.php';
 
 /**
  * Ensures db and table are valid, else moves to the "parent" script
@@ -537,8 +538,8 @@ foreach ($rows as $row_id => $vrow) {
         $idindex  = ($o_rows * $fields_cnt) + $i + 1;
         $tabindex = $idindex;
 
-        // These GIS data types are not yet supported.
-        $no_support_types = array('geometry', 'point', 'linestring', 'polygon', 'multipoint', 'multilinestring', 'multipolygon', 'geometrycollection');
+        // Get a list of data types that are not yet supported.
+        $no_support_types = PMA_unsupportedDatatypes();
 
         // The function column
         // -------------------
@@ -556,88 +557,9 @@ foreach ($rows as $row_id => $vrow) {
                 ?>
             <td>
                 <select name="funcs<?php echo $field_name_appendix; ?>" <?php echo $unnullify_trigger; ?> tabindex="<?php echo ($tabindex + $tabindex_for_function); ?>" id="field_<?php echo $idindex; ?>_1">
-                    <option></option>
-                <?php
-                $selected     = '';
-
-                // Find the current type in the RestrictColumnTypes. Will result in 'FUNC_CHAR'
-                // or something similar. Then directly look up the entry in the RestrictFunctions array,
-                // which will then reveal the available dropdown options
-                if (isset($cfg['RestrictColumnTypes'][strtoupper($field['True_Type'])])
-                 && isset($cfg['RestrictFunctions'][$cfg['RestrictColumnTypes'][strtoupper($field['True_Type'])]])) {
-                    $current_func_type  = $cfg['RestrictColumnTypes'][strtoupper($field['True_Type'])];
-                    $dropdown           = $cfg['RestrictFunctions'][$current_func_type];
-                    $default_function   = $cfg['DefaultFunctions'][$current_func_type];
-                } else {
-                    $dropdown = array();
-                    $default_function   = '';
-                }
-
-                $dropdown_built = array();
-                $op_spacing_needed = false;
-
-                // what function defined as default?
-                // for the first timestamp we don't set the default function
-                // if there is a default value for the timestamp
-                // (not including CURRENT_TIMESTAMP)
-                // and the column does not have the
-                // ON UPDATE DEFAULT TIMESTAMP attribute.
-
-                if ($field['True_Type'] == 'timestamp'
-                  && empty($field['Default'])
-                  && empty($data)
-                  && ! isset($analyzed_sql[0]['create_table_fields'][$field['Field']]['on_update_current_timestamp'])) {
-                    $default_function = $cfg['DefaultFunctions']['first_timestamp'];
-                }
-
-                // For primary keys of type char(36) or varchar(36) UUID if the default function
-                // Only applies to insert mode, as it would silently trash data on updates.
-                if ($insert_mode
-                    && $field['Key'] == 'PRI'
-                    && ($field['Type'] == 'char(36)' || $field['Type'] == 'varchar(36)')
-                ) {
-                     $default_function = $cfg['DefaultFunctions']['pk_char36'];
-                }
-
-                // this is set only when appropriate and is always true
-                if (isset($field['display_binary_as_hex'])) {
-                    $default_function = 'UNHEX';
-                }
-
-                // loop on the dropdown array and print all available options for that field.
-                foreach ($dropdown as $each_dropdown){
-                    echo '<option';
-                    if ($default_function === $each_dropdown) {
-                        echo ' selected="selected"';
-                    }
-                    echo '>' . $each_dropdown . '</option>' . "\n";
-                    $dropdown_built[$each_dropdown] = 'true';
-                    $op_spacing_needed = true;
-                }
-
-                // For compatibility's sake, do not let out all other functions. Instead
-                // print a separator (blank) and then show ALL functions which weren't shown
-                // yet.
-                $cnt_functions = count($cfg['Functions']);
-                for ($j = 0; $j < $cnt_functions; $j++) {
-                    if (! isset($dropdown_built[$cfg['Functions'][$j]]) || $dropdown_built[$cfg['Functions'][$j]] != 'true') {
-                        // Is current function defined as default?
-                        $selected = ($field['first_timestamp'] && $cfg['Functions'][$j] == $cfg['DefaultFunctions']['first_timestamp'])
-                                    || (!$field['first_timestamp'] && $cfg['Functions'][$j] == $default_function)
-                                  ? ' selected="selected"'
-                                  : '';
-                        if ($op_spacing_needed == true) {
-                            echo '                ';
-                            echo '<option value="">--------</option>' . "\n";
-                            $op_spacing_needed = false;
-                        }
-
-                        echo '                ';
-                        echo '<option' . $selected . '>' . $cfg['Functions'][$j] . '</option>' . "\n";
-                    }
-                } // end for
-                unset($selected);
-                ?>
+<?php
+    echo PMA_getFunctionsForField($field, $insert_mode);
+?>
                 </select>
             </td>
                 <?php
diff --git a/tbl_structure.php b/tbl_structure.php
index 21fc51e..41e5b9d 100644
--- a/tbl_structure.php
+++ b/tbl_structure.php
@@ -932,8 +932,6 @@ if ($cfg['ShowStats']) {
 }
 // END - Calc Table Space
 
-require './libraries/tbl_triggers.inc.php';
-
 echo '<div class="clearfloat"></div>' . "\n";
 
 /**
diff --git a/tbl_triggers.php b/tbl_triggers.php
new file mode 100644
index 0000000..bf9cbbc
--- /dev/null
+++ b/tbl_triggers.php
@@ -0,0 +1,35 @@
+<?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';
+
+
+?>
diff --git a/themes/original/css/theme_right.css.php b/themes/original/css/theme_right.css.php
index 960f63f..5ec7c1e 100644
--- a/themes/original/css/theme_right.css.php
+++ b/themes/original/css/theme_right.css.php
@@ -1858,6 +1858,19 @@ fieldset .disabled-field td {
     margin-bottom: 0.5em;
 }
 
+.rte_table td {
+    vertical-align:     middle;
+}
+
+.rte_table input, .rte_table select, .rte_table textarea {
+    width:              100%;
+    margin:             0;
+    box-sizing:         border-box;
+    -ms-box-sizing:     border-box;
+    -moz-box-sizing:    border-box;
+    -webkit-box-sizing: border-box;
+}
+
 #table_columns input, #table_columns select {
     width:              14em;
     box-sizing:         border-box;
diff --git a/themes/original/img/b_event_add.png b/themes/original/img/b_event_add.png
new file mode 100644
index 0000000..6940d74
Binary files /dev/null and b/themes/original/img/b_event_add.png differ
diff --git a/themes/original/img/b_events.png b/themes/original/img/b_events.png
new file mode 100644
index 0000000..4564284
Binary files /dev/null and b/themes/original/img/b_events.png differ
diff --git a/themes/original/img/b_routine_add.png b/themes/original/img/b_routine_add.png
new file mode 100644
index 0000000..95b9719
Binary files /dev/null and b/themes/original/img/b_routine_add.png differ
diff --git a/themes/original/img/b_routines.png b/themes/original/img/b_routines.png
new file mode 100644
index 0000000..428b0db
Binary files /dev/null and b/themes/original/img/b_routines.png differ
diff --git a/themes/original/img/b_trigger_add.png b/themes/original/img/b_trigger_add.png
new file mode 100644
index 0000000..5b91c50
Binary files /dev/null and b/themes/original/img/b_trigger_add.png differ
diff --git a/themes/original/img/b_triggers.png b/themes/original/img/b_triggers.png
new file mode 100644
index 0000000..e902511
Binary files /dev/null and b/themes/original/img/b_triggers.png differ
diff --git a/themes/original/img/bd_edit.png b/themes/original/img/bd_edit.png
new file mode 100644
index 0000000..8894dcf
Binary files /dev/null and b/themes/original/img/bd_edit.png differ
diff --git a/themes/original/img/bd_export.png b/themes/original/img/bd_export.png
new file mode 100644
index 0000000..07e4c67
Binary files /dev/null and b/themes/original/img/bd_export.png differ
diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php
index fcaba3d..27008b9 100644
--- a/themes/pmahomme/css/theme_right.css.php
+++ b/themes/pmahomme/css/theme_right.css.php
@@ -2209,6 +2209,19 @@ fieldset .disabled-field td {
     margin-bottom: 0.5em;
 }
 
+.rte_table td {
+    vertical-align:     middle;
+}
+
+.rte_table input, .rte_table select, .rte_table textarea {
+    width:              100%;
+    margin:             0;
+    box-sizing:         border-box;
+    -ms-box-sizing:     border-box;
+    -moz-box-sizing:    border-box;
+    -webkit-box-sizing: border-box;
+}
+
 #table_columns input, #table_columns select {
     width:              14em;
     box-sizing:         border-box;
diff --git a/themes/pmahomme/img/b_event_add.png b/themes/pmahomme/img/b_event_add.png
new file mode 100644
index 0000000..6940d74
Binary files /dev/null and b/themes/pmahomme/img/b_event_add.png differ
diff --git a/themes/pmahomme/img/b_events.png b/themes/pmahomme/img/b_events.png
new file mode 100644
index 0000000..4564284
Binary files /dev/null and b/themes/pmahomme/img/b_events.png differ
diff --git a/themes/pmahomme/img/b_routine_add.png b/themes/pmahomme/img/b_routine_add.png
new file mode 100644
index 0000000..95b9719
Binary files /dev/null and b/themes/pmahomme/img/b_routine_add.png differ
diff --git a/themes/pmahomme/img/b_routines.png b/themes/pmahomme/img/b_routines.png
new file mode 100644
index 0000000..428b0db
Binary files /dev/null and b/themes/pmahomme/img/b_routines.png differ
diff --git a/themes/pmahomme/img/b_trigger_add.png b/themes/pmahomme/img/b_trigger_add.png
new file mode 100644
index 0000000..5b91c50
Binary files /dev/null and b/themes/pmahomme/img/b_trigger_add.png differ
diff --git a/themes/pmahomme/img/b_triggers.png b/themes/pmahomme/img/b_triggers.png
new file mode 100644
index 0000000..e902511
Binary files /dev/null and b/themes/pmahomme/img/b_triggers.png differ
diff --git a/themes/pmahomme/img/bd_edit.png b/themes/pmahomme/img/bd_edit.png
new file mode 100644
index 0000000..6aa2a18
Binary files /dev/null and b/themes/pmahomme/img/bd_edit.png differ
diff --git a/themes/pmahomme/img/bd_export.png b/themes/pmahomme/img/bd_export.png
new file mode 100644
index 0000000..841c758
Binary files /dev/null and b/themes/pmahomme/img/bd_export.png differ


hooks/post-receive
-- 
phpMyAdmin




More information about the Git mailing list