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