Translated using Weblate (Catalan)
[phpmyadmin.git] / libraries / rte / rte_routines.lib.php
blob35a04ba9d5df84d88f17f50e7be3f0f918b49132
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Functions for routine management.
6 * @package PhpMyAdmin
7 */
8 if (! defined('PHPMYADMIN')) {
9 exit;
12 /**
13 * Sets required globals
15 * @return void
17 function PMA_RTN_setGlobals()
19 global $param_directions, $param_opts_num, $param_sqldataaccess;
21 $param_directions = array('IN',
22 'OUT',
23 'INOUT');
24 $param_opts_num = array('UNSIGNED',
25 'ZEROFILL',
26 'UNSIGNED ZEROFILL');
27 $param_sqldataaccess = array('NO SQL',
28 'CONTAINS SQL',
29 'READS SQL DATA',
30 'MODIFIES SQL DATA');
33 /**
34 * Main function for the routines functionality
36 * @param string $type 'FUNCTION' for functions,
37 * 'PROCEDURE' for procedures,
38 * null for both
40 * @return void
42 function PMA_RTN_main($type)
44 global $db;
46 PMA_RTN_setGlobals();
47 /**
48 * Process all requests
50 PMA_RTN_handleEditor();
51 PMA_RTN_handleExecute();
52 PMA_RTN_handleExport();
53 /**
54 * Display a list of available routines
56 $columns = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`, ";
57 $columns .= "`DTD_IDENTIFIER`, `ROUTINE_DEFINITION`";
58 $where = "ROUTINE_SCHEMA " . PMA_Util::getCollateForIS() . "="
59 . "'" . PMA_Util::sqlAddSlashes($db) . "'";
60 if (PMA_isValid($type, array('FUNCTION','PROCEDURE'))) {
61 $where .= " AND `ROUTINE_TYPE`='" . $type . "'";
63 $items = $GLOBALS['dbi']->fetchResult(
64 "SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE $where;"
66 echo PMA_RTE_getList('routine', $items);
67 /**
68 * Display the form for adding a new routine, if the user has the privileges.
70 echo PMA_RTN_getFooterLinks();
71 /**
72 * Display a warning for users with PHP's old "mysql" extension.
74 if (! PMA_DatabaseInterface::checkDbExtension('mysqli')) {
75 trigger_error(
76 __(
77 'You are using PHP\'s deprecated \'mysql\' extension, '
78 . 'which is not capable of handling multi queries. '
79 . '[strong]The execution of some stored routines may fail![/strong] '
80 . 'Please use the improved \'mysqli\' extension to '
81 . 'avoid any problems.'
83 E_USER_WARNING
86 } // end PMA_RTN_main()
88 /**
89 * This function parses a string containing one parameter of a routine,
90 * as returned by PMA_RTN_parseAllParameters() and returns an array containing
91 * the information about this parameter.
93 * @param string $value A string containing one parameter of a routine
95 * @return array Parsed information about the input parameter
97 function PMA_RTN_parseOneParameter($value)
99 global $param_directions;
101 $retval = array(0 => '',
102 1 => '',
103 2 => '',
104 3 => '',
105 4 => '');
106 $parsed_param = PMA_SQP_parse($value);
107 $pos = 0;
108 if (in_array(
109 /*overload*/mb_strtoupper($parsed_param[$pos]['data']),
110 $param_directions
111 )) {
112 $retval[0] = /*overload*/mb_strtoupper($parsed_param[0]['data']);
113 $pos++;
115 if ($parsed_param[$pos]['type'] == 'alpha_identifier'
116 || $parsed_param[$pos]['type'] == 'quote_backtick'
118 $retval[1] = PMA_Util::unQuote(
119 $parsed_param[$pos]['data']
121 $pos++;
123 $depth = 0;
124 $param_length = '';
125 $param_opts = array();
126 for ($i=$pos; $i<$parsed_param['len']; $i++) {
127 if (($parsed_param[$i]['type'] == 'alpha_columnType'
128 || $parsed_param[$i]['type'] == 'alpha_functionName') && $depth == 0
130 $retval[2] = /*overload*/mb_strtoupper($parsed_param[$i]['data']);
131 } else if ($parsed_param[$i]['type'] == 'punct_bracket_open_round'
132 && $depth == 0
134 $depth = 1;
135 } else if ($parsed_param[$i]['type'] == 'punct_bracket_close_round'
136 && $depth == 1
138 $depth = 0;
139 } else if ($depth == 1) {
140 $param_length .= $parsed_param[$i]['data'];
141 } else if ($parsed_param[$i]['type'] == 'alpha_reservedWord'
142 && /*overload*/mb_strtoupper($parsed_param[$i]['data']) == 'CHARSET'
143 && $depth == 0
145 if ($parsed_param[$i+1]['type'] == 'alpha_charset'
146 || $parsed_param[$i+1]['type'] == 'alpha_identifier'
148 $param_opts[] = /*overload*/mb_strtolower(
149 $parsed_param[$i+1]['data']
152 } else if ($parsed_param[$i]['type'] == 'alpha_columnAttrib'
153 && $depth == 0
155 $param_opts[] = /*overload*/mb_strtoupper($parsed_param[$i]['data']);
158 $retval[3] = $param_length;
159 sort($param_opts);
160 $retval[4] = implode(' ', $param_opts);
162 return $retval;
163 } // end PMA_RTN_parseOneParameter()
166 * This function looks through the contents of a parsed
167 * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts
168 * information about the routine's parameters.
170 * @param array $parsed_query Parsed query, returned by by PMA_SQP_parse()
171 * @param string $routine_type Routine type: 'PROCEDURE' or 'FUNCTION'
173 * @return array Information about the parameters of a routine.
175 function PMA_RTN_parseAllParameters($parsed_query, $routine_type)
177 $retval = array();
178 $retval['num'] = 0;
180 if ($parsed_query) {
181 // First get the list of parameters from the query
182 $buffer = '';
183 $params = array();
184 $fetching = false;
185 $depth = 0;
186 for ($i=0; $i<$parsed_query['len']; $i++) {
187 if ($parsed_query[$i]['type'] == 'alpha_reservedWord'
188 && $parsed_query[$i]['data'] == $routine_type
190 $fetching = true;
191 } else if ($fetching == true
192 && $parsed_query[$i]['type'] == 'punct_bracket_open_round'
194 $depth++;
195 if ($depth > 1) {
196 $buffer .= $parsed_query[$i]['data'] . ' ';
198 } else if ($fetching == true
199 && $parsed_query[$i]['type'] == 'punct_bracket_close_round'
201 $depth--;
202 if ($depth > 0) {
203 $buffer .= $parsed_query[$i]['data'] . ' ';
204 } else {
205 break;
207 } else if ($parsed_query[$i]['type'] == 'punct_listsep' && $depth == 1) {
208 $params[] = $buffer;
209 $retval['num']++;
210 $buffer = '';
211 } else if ($fetching == true && $depth > 0) {
212 $buffer .= $parsed_query[$i]['data'] . ' ';
215 if (! empty($buffer)) {
216 $params[] = $buffer;
217 $retval['num']++;
219 // Now parse each parameter individually
220 foreach ($params as $key => $value) {
221 list($retval['dir'][],
222 $retval['name'][],
223 $retval['type'][],
224 $retval['length'][],
225 $retval['opts'][]) = PMA_RTN_parseOneParameter($value);
228 // Since some indices of $retval may be still undefined, we fill
229 // them each with an empty array to avoid E_ALL errors in PHP.
230 foreach (array('dir', 'name', 'type', 'length', 'opts') as $key => $index) {
231 if (! isset($retval[$index])) {
232 $retval[$index] = array();
236 return $retval;
237 } // end PMA_RTN_parseAllParameters()
240 * This function looks through the contents of a parsed
241 * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts
242 * information about the routine's definer.
244 * @param array $parsed_query Parsed query, returned by PMA_SQP_parse()
246 * @return string The definer of a routine.
248 function PMA_RTN_parseRoutineDefiner($parsed_query)
250 $retval = '';
251 $fetching = false;
252 for ($i=0; $i<$parsed_query['len']; $i++) {
253 if ($parsed_query[$i]['type'] == 'alpha_reservedWord'
254 && $parsed_query[$i]['data'] == 'DEFINER'
256 $fetching = true;
257 } else if ($fetching == true
258 && $parsed_query[$i]['type'] != 'quote_backtick'
259 && /*overload*/mb_substr($parsed_query[$i]['type'], 0, 5) != 'punct'
261 break;
262 } else if ($fetching == true
263 && $parsed_query[$i]['type'] == 'quote_backtick'
265 $retval .= PMA_Util::unQuote(
266 $parsed_query[$i]['data']
268 } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_user') {
269 $retval .= $parsed_query[$i]['data'];
272 return $retval;
273 } // end PMA_RTN_parseRoutineDefiner()
276 * Handles editor requests for adding or editing an item
278 * @return void
280 function PMA_RTN_handleEditor()
282 global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $errors;
284 if (! empty($_REQUEST['editor_process_add'])
285 || ! empty($_REQUEST['editor_process_edit'])
288 * Handle a request to create/edit a routine
290 $sql_query = '';
291 $routine_query = PMA_RTN_getQueryFromRequest();
292 if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest()
293 // Execute the created query
294 if (! empty($_REQUEST['editor_process_edit'])) {
295 $isProcOrFunc = in_array(
296 $_REQUEST['item_original_type'],
297 array('PROCEDURE', 'FUNCTION')
299 if (!$isProcOrFunc) {
300 $errors[] = sprintf(
301 __('Invalid routine type: "%s"'),
302 htmlspecialchars($_REQUEST['item_original_type'])
304 } else {
305 // Backup the old routine, in case something goes wrong
306 $create_routine = $GLOBALS['dbi']->getDefinition(
307 $db, $_REQUEST['item_original_type'],
308 $_REQUEST['item_original_name']
310 $drop_routine = "DROP {$_REQUEST['item_original_type']} "
311 . PMA_Util::backquote($_REQUEST['item_original_name'])
312 . ";\n";
313 $result = $GLOBALS['dbi']->tryQuery($drop_routine);
314 if (! $result) {
315 $errors[] = sprintf(
316 __('The following query has failed: "%s"'),
317 htmlspecialchars($drop_routine)
319 . '<br />'
320 . __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
321 } else {
322 $result = $GLOBALS['dbi']->tryQuery($routine_query);
323 if (! $result) {
324 $errors[] = sprintf(
325 __('The following query has failed: "%s"'),
326 htmlspecialchars($routine_query)
328 . '<br />'
329 . __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
330 // We dropped the old routine,
331 // but were unable to create the new one
332 // Try to restore the backup query
333 $result = $GLOBALS['dbi']->tryQuery($create_routine);
334 $errors = checkResult(
335 $result,
337 'Sorry, we failed to restore'
338 . ' the dropped routine.'
340 $create_routine,
341 $errors
343 } else {
344 $message = PMA_Message::success(
345 __('Routine %1$s has been modified.')
347 $message->addParam(
348 PMA_Util::backquote($_REQUEST['item_name'])
350 $sql_query = $drop_routine . $routine_query;
354 } else {
355 // 'Add a new routine' mode
356 $result = $GLOBALS['dbi']->tryQuery($routine_query);
357 if (! $result) {
358 $errors[] = sprintf(
359 __('The following query has failed: "%s"'),
360 htmlspecialchars($routine_query)
362 . '<br /><br />'
363 . __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
364 } else {
365 $message = PMA_Message::success(
366 __('Routine %1$s has been created.')
368 $message->addParam(
369 PMA_Util::backquote($_REQUEST['item_name'])
371 $sql_query = $routine_query;
376 if (count($errors)) {
377 $message = PMA_Message::error(
379 'One or more errors have occurred while'
380 . ' processing your request:'
383 $message->addString('<ul>');
384 foreach ($errors as $string) {
385 $message->addString('<li>' . $string . '</li>');
387 $message->addString('</ul>');
390 $output = PMA_Util::getMessage($message, $sql_query);
391 if ($GLOBALS['is_ajax_request']) {
392 $response = PMA_Response::getInstance();
393 if ($message->isSuccess()) {
394 $columns = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`,"
395 . " `DTD_IDENTIFIER`, `ROUTINE_DEFINITION`";
396 $where = "ROUTINE_SCHEMA " . PMA_Util::getCollateForIS() . "="
397 . "'" . PMA_Util::sqlAddSlashes($db) . "' "
398 . "AND ROUTINE_NAME='"
399 . PMA_Util::sqlAddSlashes($_REQUEST['item_name']) . "'"
400 . "AND ROUTINE_TYPE='"
401 . PMA_Util::sqlAddSlashes($_REQUEST['item_type']) . "'";
402 $routine = $GLOBALS['dbi']->fetchSingleRow(
403 "SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES`"
404 . " WHERE $where;"
406 $response->addJSON(
407 'name',
408 htmlspecialchars(
409 /*overload*/mb_strtoupper($_REQUEST['item_name'])
412 $response->addJSON('new_row', PMA_RTN_getRowForList($routine));
413 $response->addJSON('insert', ! empty($routine));
414 $response->addJSON('message', $output);
415 } else {
416 $response->isSuccess(false);
417 $response->addJSON('message', $output);
419 exit;
424 * Display a form used to add/edit a routine, if necessary
426 // FIXME: this must be simpler than that
427 if (count($errors)
428 || ( empty($_REQUEST['editor_process_add'])
429 && empty($_REQUEST['editor_process_edit'])
430 && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item'])
431 || ! empty($_REQUEST['routine_addparameter'])
432 || ! empty($_REQUEST['routine_removeparameter'])
433 || ! empty($_REQUEST['routine_changetype'])))
435 // Handle requests to add/remove parameters and changing routine type
436 // This is necessary when JS is disabled
437 $operation = '';
438 if (! empty($_REQUEST['routine_addparameter'])) {
439 $operation = 'add';
440 } else if (! empty($_REQUEST['routine_removeparameter'])) {
441 $operation = 'remove';
442 } else if (! empty($_REQUEST['routine_changetype'])) {
443 $operation = 'change';
445 // Get the data for the form (if any)
446 if (! empty($_REQUEST['add_item'])) {
447 $title = PMA_RTE_getWord('add');
448 $routine = PMA_RTN_getDataFromRequest();
449 $mode = 'add';
450 } else if (! empty($_REQUEST['edit_item'])) {
451 $title = __("Edit routine");
452 if (! $operation && ! empty($_REQUEST['item_name'])
453 && empty($_REQUEST['editor_process_edit'])
455 $routine = PMA_RTN_getDataFromName(
456 $_REQUEST['item_name'], $_REQUEST['item_type']
458 if ($routine !== false) {
459 $routine['item_original_name'] = $routine['item_name'];
460 $routine['item_original_type'] = $routine['item_type'];
462 } else {
463 $routine = PMA_RTN_getDataFromRequest();
465 $mode = 'edit';
467 if ($routine !== false) {
468 // Show form
469 $editor = PMA_RTN_getEditorForm($mode, $operation, $routine);
470 if ($GLOBALS['is_ajax_request']) {
471 $response = PMA_Response::getInstance();
472 $response->addJSON('message', $editor);
473 $response->addJSON('title', $title);
474 $response->addJSON('param_template', PMA_RTN_getParameterRow());
475 $response->addJSON('type', $routine['item_type']);
476 } else {
477 echo "\n\n<h2>$title</h2>\n\n$editor";
479 exit;
480 } else {
481 $message = __('Error in processing request:') . ' ';
482 $message .= sprintf(
483 PMA_RTE_getWord('not_found'),
484 htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])),
485 htmlspecialchars(PMA_Util::backquote($db))
487 $message = PMA_message::error($message);
488 if ($GLOBALS['is_ajax_request']) {
489 $response->isSuccess(false);
490 $response->addJSON('message', $message);
491 exit;
492 } else {
493 $message->display();
497 } // end PMA_RTN_handleEditor()
500 * This function will generate the values that are required to
501 * complete the editor form. It is especially necessary to handle
502 * the 'Add another parameter', 'Remove last parameter' and
503 * 'Change routine type' functionalities when JS is disabled.
505 * @return array Data necessary to create the routine editor.
507 function PMA_RTN_getDataFromRequest()
509 global $_REQUEST, $param_directions, $param_sqldataaccess;
511 $retval = array();
512 $indices = array('item_name',
513 'item_original_name',
514 'item_returnlength',
515 'item_returnopts_num',
516 'item_returnopts_text',
517 'item_definition',
518 'item_comment',
519 'item_definer');
520 foreach ($indices as $index) {
521 $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : '';
524 $retval['item_type'] = 'PROCEDURE';
525 $retval['item_type_toggle'] = 'FUNCTION';
526 if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'FUNCTION') {
527 $retval['item_type'] = 'FUNCTION';
528 $retval['item_type_toggle'] = 'PROCEDURE';
530 $retval['item_original_type'] = 'PROCEDURE';
531 if (isset($_REQUEST['item_original_type'])
532 && $_REQUEST['item_original_type'] == 'FUNCTION'
534 $retval['item_original_type'] = 'FUNCTION';
536 $retval['item_num_params'] = 0;
537 $retval['item_param_dir'] = array();
538 $retval['item_param_name'] = array();
539 $retval['item_param_type'] = array();
540 $retval['item_param_length'] = array();
541 $retval['item_param_opts_num'] = array();
542 $retval['item_param_opts_text'] = array();
543 if ( isset($_REQUEST['item_param_name'])
544 && isset($_REQUEST['item_param_type'])
545 && isset($_REQUEST['item_param_length'])
546 && isset($_REQUEST['item_param_opts_num'])
547 && isset($_REQUEST['item_param_opts_text'])
548 && is_array($_REQUEST['item_param_name'])
549 && is_array($_REQUEST['item_param_type'])
550 && is_array($_REQUEST['item_param_length'])
551 && is_array($_REQUEST['item_param_opts_num'])
552 && is_array($_REQUEST['item_param_opts_text'])
554 if ($_REQUEST['item_type'] == 'PROCEDURE') {
555 $retval['item_param_dir'] = $_REQUEST['item_param_dir'];
556 foreach ($retval['item_param_dir'] as $key => $value) {
557 if (! in_array($value, $param_directions, true)) {
558 $retval['item_param_dir'][$key] = '';
562 $retval['item_param_name'] = $_REQUEST['item_param_name'];
563 $retval['item_param_type'] = $_REQUEST['item_param_type'];
564 foreach ($retval['item_param_type'] as $key => $value) {
565 if (! in_array($value, PMA_Util::getSupportedDatatypes(), true)) {
566 $retval['item_param_type'][$key] = '';
569 $retval['item_param_length'] = $_REQUEST['item_param_length'];
570 $retval['item_param_opts_num'] = $_REQUEST['item_param_opts_num'];
571 $retval['item_param_opts_text'] = $_REQUEST['item_param_opts_text'];
572 $retval['item_num_params'] = max(
573 count($retval['item_param_name']),
574 count($retval['item_param_type']),
575 count($retval['item_param_length']),
576 count($retval['item_param_opts_num']),
577 count($retval['item_param_opts_text'])
580 $retval['item_returntype'] = '';
581 if (isset($_REQUEST['item_returntype'])
582 && in_array($_REQUEST['item_returntype'], PMA_Util::getSupportedDatatypes())
584 $retval['item_returntype'] = $_REQUEST['item_returntype'];
587 $retval['item_isdeterministic'] = '';
588 if (isset($_REQUEST['item_isdeterministic'])
589 && /*overload*/mb_strtolower($_REQUEST['item_isdeterministic']) == 'on'
591 $retval['item_isdeterministic'] = " checked='checked'";
593 $retval['item_securitytype_definer'] = '';
594 $retval['item_securitytype_invoker'] = '';
595 if (isset($_REQUEST['item_securitytype'])) {
596 if ($_REQUEST['item_securitytype'] === 'DEFINER') {
597 $retval['item_securitytype_definer'] = " selected='selected'";
598 } else if ($_REQUEST['item_securitytype'] === 'INVOKER') {
599 $retval['item_securitytype_invoker'] = " selected='selected'";
602 $retval['item_sqldataaccess'] = '';
603 if (isset($_REQUEST['item_sqldataaccess'])
604 && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess, true)
606 $retval['item_sqldataaccess'] = $_REQUEST['item_sqldataaccess'];
609 return $retval;
610 } // end function PMA_RTN_getDataFromRequest()
613 * This function will generate the values that are required to complete
614 * the "Edit routine" form given the name of a routine.
616 * @param string $name The name of the routine.
617 * @param string $type Type of routine (ROUTINE|PROCEDURE)
618 * @param bool $all Whether to return all data or just
619 * the info about parameters.
621 * @return array Data necessary to create the routine editor.
623 function PMA_RTN_getDataFromName($name, $type, $all = true)
625 global $db;
627 $retval = array();
629 // Build and execute the query
630 $fields = "SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, "
631 . "ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, "
632 . "ROUTINE_COMMENT, SECURITY_TYPE";
633 $where = "ROUTINE_SCHEMA " . PMA_Util::getCollateForIS() . "="
634 . "'" . PMA_Util::sqlAddSlashes($db) . "' "
635 . "AND SPECIFIC_NAME='" . PMA_Util::sqlAddSlashes($name) . "'"
636 . "AND ROUTINE_TYPE='" . PMA_Util::sqlAddSlashes($type) . "'";
637 $query = "SELECT $fields FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;";
639 $routine = $GLOBALS['dbi']->fetchSingleRow($query);
641 if (! $routine) {
642 return false;
645 // Get required data
646 $retval['item_name'] = $routine['SPECIFIC_NAME'];
647 $retval['item_type'] = $routine['ROUTINE_TYPE'];
648 $parsed_query = PMA_SQP_parse(
649 $GLOBALS['dbi']->getDefinition(
650 $db,
651 $routine['ROUTINE_TYPE'],
652 $routine['SPECIFIC_NAME']
655 $params = PMA_RTN_parseAllParameters($parsed_query, $routine['ROUTINE_TYPE']);
656 $retval['item_num_params'] = $params['num'];
657 $retval['item_param_dir'] = $params['dir'];
658 $retval['item_param_name'] = $params['name'];
659 $retval['item_param_type'] = $params['type'];
660 $retval['item_param_length'] = $params['length'];
661 $retval['item_param_opts_num'] = $params['opts'];
662 $retval['item_param_opts_text'] = $params['opts'];
664 // Get extra data
665 if (!$all) {
666 return $retval;
669 if ($retval['item_type'] == 'FUNCTION') {
670 $retval['item_type_toggle'] = 'PROCEDURE';
671 } else {
672 $retval['item_type_toggle'] = 'FUNCTION';
674 $retval['item_returntype'] = '';
675 $retval['item_returnlength'] = '';
676 $retval['item_returnopts_num'] = '';
677 $retval['item_returnopts_text'] = '';
678 if (! empty($routine['DTD_IDENTIFIER'])) {
679 if (/*overload*/mb_strlen($routine['DTD_IDENTIFIER']) > 63) {
680 // If the DTD_IDENTIFIER string from INFORMATION_SCHEMA is
681 // at least 64 characters, then it may actually have been
682 // chopped because that column is a varchar(64), so we will
683 // parse the output of SHOW CREATE query to get accurate
684 // information about the return variable.
685 $dtd = '';
686 $fetching = false;
687 for ($i=0; $i<$parsed_query['len']; $i++) {
688 if ($parsed_query[$i]['type'] == 'alpha_reservedWord'
689 && /*overload*/mb_strtoupper($parsed_query[$i]['data']) == 'RETURNS'
691 $fetching = true;
692 } else if ($fetching == true
693 && $parsed_query[$i]['type'] == 'alpha_reservedWord'
695 // We will not be looking for options such as UNSIGNED
696 // or ZEROFILL because there is no way that a numeric
697 // field's DTD_IDENTIFIER can be longer than 64
698 // characters. We can safely assume that the return
699 // datatype is either ENUM or SET, so we only look
700 // for CHARSET.
701 $word = /*overload*/mb_strtoupper($parsed_query[$i]['data']);
702 if ($word == 'CHARSET'
703 && ($parsed_query[$i+1]['type'] == 'alpha_charset'
704 || $parsed_query[$i+1]['type'] == 'alpha_identifier')
706 $dtd .= $word . ' ' . $parsed_query[$i+1]['data'];
708 break;
709 } else if ($fetching == true) {
710 $dtd .= $parsed_query[$i]['data'] . ' ';
713 $routine['DTD_IDENTIFIER'] = $dtd;
715 $returnparam = PMA_RTN_parseOneParameter($routine['DTD_IDENTIFIER']);
716 $retval['item_returntype'] = $returnparam[2];
717 $retval['item_returnlength'] = $returnparam[3];
718 $retval['item_returnopts_num'] = $returnparam[4];
719 $retval['item_returnopts_text'] = $returnparam[4];
722 $retval['item_definer'] = PMA_RTN_parseRoutineDefiner($parsed_query);
723 $retval['item_definition'] = $routine['ROUTINE_DEFINITION'];
724 $retval['item_isdeterministic'] = '';
725 if ($routine['IS_DETERMINISTIC'] == 'YES') {
726 $retval['item_isdeterministic'] = " checked='checked'";
728 $retval['item_securitytype_definer'] = '';
729 $retval['item_securitytype_invoker'] = '';
730 if ($routine['SECURITY_TYPE'] == 'DEFINER') {
731 $retval['item_securitytype_definer'] = " selected='selected'";
732 } else if ($routine['SECURITY_TYPE'] == 'INVOKER') {
733 $retval['item_securitytype_invoker'] = " selected='selected'";
735 $retval['item_sqldataaccess'] = $routine['SQL_DATA_ACCESS'];
736 $retval['item_comment'] = $routine['ROUTINE_COMMENT'];
738 return $retval;
739 } // PMA_RTN_getDataFromName()
742 * Creates one row for the parameter table used in the routine editor.
744 * @param array $routine Data for the routine returned by
745 * PMA_RTN_getDataFromRequest() or
746 * PMA_RTN_getDataFromName()
747 * @param mixed $index Either a numeric index of the row being processed
748 * or NULL to create a template row for AJAX request
749 * @param string $class Class used to hide the direction column, if the
750 * row is for a stored function.
752 * @return string HTML code of one row of parameter table for the editor.
754 function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '')
756 global $param_directions, $param_opts_num, $titles;
758 if ($index === null) {
759 // template row for AJAX request
760 $i = 0;
761 $index = '%s';
762 $drop_class = '';
763 $routine = array(
764 'item_param_dir' => array(0 => ''),
765 'item_param_name' => array(0 => ''),
766 'item_param_type' => array(0 => ''),
767 'item_param_length' => array(0 => ''),
768 'item_param_opts_num' => array(0 => ''),
769 'item_param_opts_text' => array(0 => '')
771 } else if (! empty($routine)) {
772 // regular row for routine editor
773 $drop_class = ' hide';
774 $i = $index;
775 } else {
776 // No input data. This shouldn't happen,
777 // but better be safe than sorry.
778 return '';
781 // Create the output
782 $retval = "";
783 $retval .= " <tr>\n";
784 $retval .= " <td class='routine_direction_cell$class'>\n";
785 $retval .= " <select name='item_param_dir[$index]'>\n";
786 foreach ($param_directions as $key => $value) {
787 $selected = "";
788 if (! empty($routine['item_param_dir'][$i])
789 && $routine['item_param_dir'][$i] == $value
791 $selected = " selected='selected'";
793 $retval .= " <option$selected>$value</option>\n";
795 $retval .= " </select>\n";
796 $retval .= " </td>\n";
797 $retval .= " <td><input name='item_param_name[$index]' type='text'\n"
798 . " value='{$routine['item_param_name'][$i]}' /></td>\n";
799 $retval .= " <td><select name='item_param_type[$index]'>";
800 $retval .= PMA_Util::getSupportedDatatypes(
801 true, $routine['item_param_type'][$i]
802 ) . "\n";
803 $retval .= " </select></td>\n";
804 $retval .= " <td>\n";
805 $retval .= " <input id='item_param_length_$index'\n"
806 . " name='item_param_length[$index]' type='text'\n"
807 . " value='{$routine['item_param_length'][$i]}' />\n";
808 $retval .= " <div class='enum_hint'>\n";
809 $retval .= " <a href='#' class='open_enum_editor'>\n";
810 $retval .= " "
811 . PMA_Util::getImage('b_edit', '', array('title'=>__('ENUM/SET editor')))
812 . "\n";
813 $retval .= " </a>\n";
814 $retval .= " </div>\n";
815 $retval .= " </td>\n";
816 $retval .= " <td class='hide no_len'>---</td>\n";
817 $retval .= " <td class='routine_param_opts_text'>\n";
818 $retval .= PMA_generateCharsetDropdownBox(
819 PMA_CSDROPDOWN_CHARSET,
820 "item_param_opts_text[$index]",
821 null,
822 $routine['item_param_opts_text'][$i]
824 $retval .= " </td>\n";
825 $retval .= " <td class='hide no_opts'>---</td>\n";
826 $retval .= " <td class='routine_param_opts_num'>\n";
827 $retval .= " <select name='item_param_opts_num[$index]'>\n";
828 $retval .= " <option value=''></option>";
829 foreach ($param_opts_num as $key => $value) {
830 $selected = "";
831 if (! empty($routine['item_param_opts_num'][$i])
832 && $routine['item_param_opts_num'][$i] == $value
834 $selected = " selected='selected'";
836 $retval .= "<option$selected>$value</option>";
838 $retval .= "\n </select>\n";
839 $retval .= " </td>\n";
840 $retval .= " <td class='routine_param_remove$drop_class'>\n";
841 $retval .= " <a href='#' class='routine_param_remove_anchor'>\n";
842 $retval .= " {$titles['Drop']}\n";
843 $retval .= " </a>\n";
844 $retval .= " </td>\n";
845 $retval .= " </tr>\n";
847 return $retval;
848 } // end PMA_RTN_getParameterRow()
851 * Displays a form used to add/edit a routine
853 * @param string $mode If the editor will be used edit a routine
854 * or add a new one: 'edit' or 'add'.
855 * @param string $operation If the editor was previously invoked with
856 * JS turned off, this will hold the name of
857 * the current operation
858 * @param array $routine Data for the routine returned by
859 * PMA_RTN_getDataFromRequest() or
860 * PMA_RTN_getDataFromName()
862 * @return string HTML code for the editor.
864 function PMA_RTN_getEditorForm($mode, $operation, $routine)
866 global $db, $errors, $param_sqldataaccess, $param_opts_num;
868 // Escape special characters
869 $need_escape = array(
870 'item_original_name',
871 'item_name',
872 'item_returnlength',
873 'item_definition',
874 'item_definer',
875 'item_comment'
877 foreach ($need_escape as $key => $index) {
878 $routine[$index] = htmlentities($routine[$index], ENT_QUOTES, 'UTF-8');
880 for ($i=0; $i<$routine['item_num_params']; $i++) {
881 $routine['item_param_name'][$i] = htmlentities(
882 $routine['item_param_name'][$i],
883 ENT_QUOTES
885 $routine['item_param_length'][$i] = htmlentities(
886 $routine['item_param_length'][$i],
887 ENT_QUOTES
891 // Handle some logic first
892 if ($operation == 'change') {
893 if ($routine['item_type'] == 'PROCEDURE') {
894 $routine['item_type'] = 'FUNCTION';
895 $routine['item_type_toggle'] = 'PROCEDURE';
896 } else {
897 $routine['item_type'] = 'PROCEDURE';
898 $routine['item_type_toggle'] = 'FUNCTION';
900 } else if ($operation == 'add'
901 || ($routine['item_num_params'] == 0 && $mode == 'add' && ! $errors)
903 $routine['item_param_dir'][] = '';
904 $routine['item_param_name'][] = '';
905 $routine['item_param_type'][] = '';
906 $routine['item_param_length'][] = '';
907 $routine['item_param_opts_num'][] = '';
908 $routine['item_param_opts_text'][] = '';
909 $routine['item_num_params']++;
910 } else if ($operation == 'remove') {
911 unset($routine['item_param_dir'][$routine['item_num_params']-1]);
912 unset($routine['item_param_name'][$routine['item_num_params']-1]);
913 unset($routine['item_param_type'][$routine['item_num_params']-1]);
914 unset($routine['item_param_length'][$routine['item_num_params']-1]);
915 unset($routine['item_param_opts_num'][$routine['item_num_params']-1]);
916 unset($routine['item_param_opts_text'][$routine['item_num_params']-1]);
917 $routine['item_num_params']--;
919 $disableRemoveParam = '';
920 if (! $routine['item_num_params']) {
921 $disableRemoveParam = " color: gray;' disabled='disabled";
923 $original_routine = '';
924 if ($mode == 'edit') {
925 $original_routine = "<input name='item_original_name' "
926 . "type='hidden' "
927 . "value='{$routine['item_original_name']}'/>\n"
928 . "<input name='item_original_type' "
929 . "type='hidden' "
930 . "value='{$routine['item_original_type']}'/>\n";
932 $isfunction_class = '';
933 $isprocedure_class = '';
934 $isfunction_select = '';
935 $isprocedure_select = '';
936 if ($routine['item_type'] == 'PROCEDURE') {
937 $isfunction_class = ' hide';
938 $isprocedure_select = " selected='selected'";
939 } else {
940 $isprocedure_class = ' hide';
941 $isfunction_select = " selected='selected'";
944 // Create the output
945 $retval = "";
946 $retval .= "<!-- START " . /*overload*/mb_strtoupper($mode)
947 . " ROUTINE FORM -->\n\n";
948 $retval .= "<form class='rte_form' action='db_routines.php' method='post'>\n";
949 $retval .= "<input name='{$mode}_item' type='hidden' value='1' />\n";
950 $retval .= $original_routine;
951 $retval .= PMA_URL_getHiddenInputs($db) . "\n";
952 $retval .= "<fieldset>\n";
953 $retval .= "<legend>" . __('Details') . "</legend>\n";
954 $retval .= "<table class='rte_table' style='width: 100%'>\n";
955 $retval .= "<tr>\n";
956 $retval .= " <td style='width: 20%;'>" . __('Routine name') . "</td>\n";
957 $retval .= " <td><input type='text' name='item_name' maxlength='64'\n";
958 $retval .= " value='{$routine['item_name']}' /></td>\n";
959 $retval .= "</tr>\n";
960 $retval .= "<tr>\n";
961 $retval .= " <td>" . __('Type') . "</td>\n";
962 $retval .= " <td>\n";
963 if ($GLOBALS['is_ajax_request']) {
964 $retval .= " <select name='item_type'>\n"
965 . "<option value='PROCEDURE'$isprocedure_select>PROCEDURE</option>\n"
966 . "<option value='FUNCTION'$isfunction_select>FUNCTION</option>\n"
967 . "</select>\n";
968 } else {
969 $retval .= "<input name='item_type' type='hidden'"
970 . " value='{$routine['item_type']}' />\n"
971 . "<div style='width: 49%; float: left; text-align: center;"
972 . " font-weight: bold;'>\n"
973 . $routine['item_type'] . "\n"
974 . "</div>\n"
975 . "<input style='width: 49%;' type='submit' name='routine_changetype'\n"
976 . " value='" . sprintf(__('Change to %s'), $routine['item_type_toggle'])
977 . "' />\n";
979 $retval .= " </td>\n";
980 $retval .= "</tr>\n";
981 $retval .= "<tr>\n";
982 $retval .= " <td>" . __('Parameters') . "</td>\n";
983 $retval .= " <td>\n";
984 // parameter handling start
985 $retval .= " <table class='routine_params_table'>\n";
986 $retval .= " <tr>\n";
987 $retval .= " <th class='routine_direction_cell$isprocedure_class'>"
988 . __('Direction') . "</th>\n";
989 $retval .= " <th>" . __('Name') . "</th>\n";
990 $retval .= " <th>" . __('Type') . "</th>\n";
991 $retval .= " <th>" . __('Length/Values') . "</th>\n";
992 $retval .= " <th colspan='2'>" . __('Options') . "</th>\n";
993 $retval .= " <th class='routine_param_remove hide'>&nbsp;</th>\n";
994 $retval .= " </tr>";
995 for ($i=0; $i<$routine['item_num_params']; $i++) { // each parameter
996 $retval .= PMA_RTN_getParameterRow($routine, $i, $isprocedure_class);
998 $retval .= " </table>";
999 $retval .= " </td>";
1000 $retval .= "</tr>";
1001 $retval .= "<tr>";
1002 $retval .= " <td>&nbsp;</td>";
1003 $retval .= " <td>";
1004 $retval .= " <input style='width: 49%;' type='button'";
1005 $retval .= " name='routine_addparameter'";
1006 $retval .= " value='" . __('Add parameter') . "' />";
1007 $retval .= " <input style='width: 49%;" . $disableRemoveParam . "'";
1008 $retval .= " type='submit' ";
1009 $retval .= " name='routine_removeparameter'";
1010 $retval .= " value='" . __('Remove last parameter') . "' />";
1011 $retval .= " </td>";
1012 $retval .= "</tr>";
1013 // parameter handling end
1014 $retval .= "<tr class='routine_return_row" . $isfunction_class . "'>";
1015 $retval .= " <td>" . __('Return type') . "</td>";
1016 $retval .= " <td><select name='item_returntype'>";
1017 $retval .= PMA_Util::getSupportedDatatypes(true, $routine['item_returntype']);
1018 $retval .= " </select></td>";
1019 $retval .= "</tr>";
1020 $retval .= "<tr class='routine_return_row" . $isfunction_class . "'>";
1021 $retval .= " <td>" . __('Return length/values') . "</td>";
1022 $retval .= " <td><input type='text' name='item_returnlength'";
1023 $retval .= " value='" . $routine['item_returnlength'] . "' /></td>";
1024 $retval .= " <td class='hide no_len'>---</td>";
1025 $retval .= "</tr>";
1026 $retval .= "<tr class='routine_return_row" . $isfunction_class . "'>";
1027 $retval .= " <td>" . __('Return options') . "</td>";
1028 $retval .= " <td><div>";
1029 $retval .= PMA_generateCharsetDropdownBox(
1030 PMA_CSDROPDOWN_CHARSET,
1031 "item_returnopts_text",
1032 null,
1033 $routine['item_returnopts_text']
1035 $retval .= " </div>";
1036 $retval .= " <div><select name='item_returnopts_num'>";
1037 $retval .= " <option value=''></option>";
1038 foreach ($param_opts_num as $key => $value) {
1039 $selected = "";
1040 if (! empty($routine['item_returnopts_num'])
1041 && $routine['item_returnopts_num'] == $value
1043 $selected = " selected='selected'";
1045 $retval .= "<option" . $selected . ">" . $value . "</option>";
1047 $retval .= " </select></div>";
1048 $retval .= " <div class='hide no_opts'>---</div>";
1049 $retval .= "</td>";
1050 $retval .= "</tr>";
1051 $retval .= "<tr>";
1052 $retval .= " <td>" . __('Definition') . "</td>";
1053 $retval .= " <td><textarea name='item_definition' rows='15' cols='40'>";
1054 $retval .= $routine['item_definition'];
1055 $retval .= "</textarea></td>";
1056 $retval .= "</tr>";
1057 $retval .= "<tr>";
1058 $retval .= " <td>" . __('Is deterministic') . "</td>";
1059 $retval .= " <td><input type='checkbox' name='item_isdeterministic'"
1060 . $routine['item_isdeterministic'] . " /></td>";
1061 $retval .= "</tr>";
1062 $retval .= "<tr>";
1063 $retval .= " <td>" . __('Definer') . "</td>";
1064 $retval .= " <td><input type='text' name='item_definer'";
1065 $retval .= " value='" . $routine['item_definer'] . "' /></td>";
1066 $retval .= "</tr>";
1067 $retval .= "<tr>";
1068 $retval .= " <td>" . __('Security type') . "</td>";
1069 $retval .= " <td><select name='item_securitytype'>";
1070 $retval .= " <option value='DEFINER'"
1071 . $routine['item_securitytype_definer'] . ">DEFINER</option>";
1072 $retval .= " <option value='INVOKER'"
1073 . $routine['item_securitytype_invoker'] . ">INVOKER</option>";
1074 $retval .= " </select></td>";
1075 $retval .= "</tr>";
1076 $retval .= "<tr>";
1077 $retval .= " <td>" . __('SQL data access') . "</td>";
1078 $retval .= " <td><select name='item_sqldataaccess'>";
1079 foreach ($param_sqldataaccess as $key => $value) {
1080 $selected = "";
1081 if ($routine['item_sqldataaccess'] == $value) {
1082 $selected = " selected='selected'";
1084 $retval .= " <option" . $selected . ">" . $value . "</option>";
1086 $retval .= " </select></td>";
1087 $retval .= "</tr>";
1088 $retval .= "<tr>";
1089 $retval .= " <td>" . __('Comment') . "</td>";
1090 $retval .= " <td><input type='text' name='item_comment' maxlength='64'";
1091 $retval .= " value='" . $routine['item_comment'] . "' /></td>";
1092 $retval .= "</tr>";
1093 $retval .= "</table>";
1094 $retval .= "</fieldset>";
1095 if ($GLOBALS['is_ajax_request']) {
1096 $retval .= "<input type='hidden' name='editor_process_" . $mode . "'";
1097 $retval .= " value='true' />";
1098 $retval .= "<input type='hidden' name='ajax_request' value='true' />";
1099 } else {
1100 $retval .= "<fieldset class='tblFooters'>";
1101 $retval .= " <input type='submit' name='editor_process_" . $mode . "'";
1102 $retval .= " value='" . __('Go') . "' />";
1103 $retval .= "</fieldset>";
1105 $retval .= "</form>";
1106 $retval .= "<!-- END " . /*overload*/mb_strtoupper($mode) . " ROUTINE FORM -->";
1108 return $retval;
1109 } // end PMA_RTN_getEditorForm()
1112 * Composes the query necessary to create a routine from an HTTP request.
1114 * @return string The CREATE [ROUTINE | PROCEDURE] query.
1116 function PMA_RTN_getQueryFromRequest()
1118 global $_REQUEST, $errors, $param_sqldataaccess, $param_directions, $PMA_Types;
1120 $_REQUEST['item_type'] = isset($_REQUEST['item_type'])
1121 ? $_REQUEST['item_type'] : '';
1123 $query = 'CREATE ';
1124 if (! empty($_REQUEST['item_definer'])) {
1125 if (/*overload*/mb_strpos($_REQUEST['item_definer'], '@') !== false) {
1126 $arr = explode('@', $_REQUEST['item_definer']);
1127 $query .= 'DEFINER=' . PMA_Util::backquote($arr[0]);
1128 $query .= '@' . PMA_Util::backquote($arr[1]) . ' ';
1129 } else {
1130 $errors[] = __('The definer must be in the "username@hostname" format!');
1133 if ($_REQUEST['item_type'] == 'FUNCTION'
1134 || $_REQUEST['item_type'] == 'PROCEDURE'
1136 $query .= $_REQUEST['item_type'] . ' ';
1137 } else {
1138 $errors[] = sprintf(
1139 __('Invalid routine type: "%s"'),
1140 htmlspecialchars($_REQUEST['item_type'])
1143 if (! empty($_REQUEST['item_name'])) {
1144 $query .= PMA_Util::backquote($_REQUEST['item_name']);
1145 } else {
1146 $errors[] = __('You must provide a routine name!');
1148 $params = '';
1149 $warned_about_dir = false;
1150 $warned_about_length = false;
1152 if ( ! empty($_REQUEST['item_param_name'])
1153 && ! empty($_REQUEST['item_param_type'])
1154 && ! empty($_REQUEST['item_param_length'])
1155 && is_array($_REQUEST['item_param_name'])
1156 && is_array($_REQUEST['item_param_type'])
1157 && is_array($_REQUEST['item_param_length'])
1159 $item_param_name = $_REQUEST['item_param_name'];
1160 $item_param_type = $_REQUEST['item_param_type'];
1161 $item_param_length = $_REQUEST['item_param_length'];
1163 for ($i=0, $nb = count($item_param_name); $i < $nb; $i++) {
1164 if (! empty($item_param_name[$i])
1165 && ! empty($item_param_type[$i])
1167 if ($_REQUEST['item_type'] == 'PROCEDURE'
1168 && ! empty($_REQUEST['item_param_dir'][$i])
1169 && in_array($_REQUEST['item_param_dir'][$i], $param_directions)
1171 $params .= $_REQUEST['item_param_dir'][$i] . " "
1172 . PMA_Util::backquote($item_param_name[$i])
1173 . " " . $item_param_type[$i];
1174 } else if ($_REQUEST['item_type'] == 'FUNCTION') {
1175 $params .= PMA_Util::backquote($item_param_name[$i])
1176 . " " . $item_param_type[$i];
1177 } else if (! $warned_about_dir) {
1178 $warned_about_dir = true;
1179 $errors[] = sprintf(
1180 __('Invalid direction "%s" given for parameter.'),
1181 htmlspecialchars($_REQUEST['item_param_dir'][$i])
1184 if ($item_param_length[$i] != ''
1185 && !preg_match(
1186 '@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|'
1187 . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|'
1188 . 'SERIAL|BOOLEAN)$@i',
1189 $item_param_type[$i]
1192 $params .= "(" . $item_param_length[$i] . ")";
1193 } else if ($item_param_length[$i] == ''
1194 && preg_match(
1195 '@^(ENUM|SET|VARCHAR|VARBINARY)$@i',
1196 $item_param_type[$i]
1199 if (! $warned_about_length) {
1200 $warned_about_length = true;
1201 $errors[] = __(
1202 'You must provide length/values for routine parameters'
1203 . ' of type ENUM, SET, VARCHAR and VARBINARY.'
1207 if (! empty($_REQUEST['item_param_opts_text'][$i])) {
1208 if ($PMA_Types->getTypeClass($item_param_type[$i]) == 'CHAR') {
1209 $params .= ' CHARSET '
1210 . /*overload*/mb_strtolower(
1211 $_REQUEST['item_param_opts_text'][$i]
1215 if (! empty($_REQUEST['item_param_opts_num'][$i])) {
1216 if ($PMA_Types->getTypeClass($item_param_type[$i]) == 'NUMBER') {
1217 $params .= ' '
1218 . /*overload*/mb_strtoupper(
1219 $_REQUEST['item_param_opts_num'][$i]
1223 if ($i != (count($item_param_name) - 1)) {
1224 $params .= ", ";
1226 } else {
1227 $errors[] = __(
1228 'You must provide a name and a type for each routine parameter.'
1230 break;
1234 $query .= "(" . $params . ") ";
1235 if ($_REQUEST['item_type'] == 'FUNCTION') {
1236 $item_returntype = isset($_REQUEST['item_returntype'])
1237 ? $_REQUEST['item_returntype']
1238 : null;
1240 if (! empty($item_returntype)
1241 && in_array(
1242 $item_returntype, PMA_Util::getSupportedDatatypes()
1245 $query .= "RETURNS " . $item_returntype;
1246 } else {
1247 $errors[] = __('You must provide a valid return type for the routine.');
1249 if (! empty($_REQUEST['item_returnlength'])
1250 && !preg_match(
1251 '@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|'
1252 . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i',
1253 $item_returntype
1256 $query .= "(" . $_REQUEST['item_returnlength'] . ")";
1257 } else if (empty($_REQUEST['item_returnlength'])
1258 && preg_match(
1259 '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $item_returntype
1262 if (! $warned_about_length) {
1263 $warned_about_length = true;
1264 $errors[] = __(
1265 'You must provide length/values for routine parameters'
1266 . ' of type ENUM, SET, VARCHAR and VARBINARY.'
1270 if (! empty($_REQUEST['item_returnopts_text'])) {
1271 if ($PMA_Types->getTypeClass($item_returntype) == 'CHAR') {
1272 $query .= ' CHARSET '
1273 . /*overload*/mb_strtolower($_REQUEST['item_returnopts_text']);
1276 if (! empty($_REQUEST['item_returnopts_num'])) {
1277 if ($PMA_Types->getTypeClass($item_returntype) == 'NUMBER') {
1278 $query .= ' '
1279 . /*overload*/mb_strtoupper($_REQUEST['item_returnopts_num']);
1282 $query .= ' ';
1284 if (! empty($_REQUEST['item_comment'])) {
1285 $query .= "COMMENT '" . PMA_Util::sqlAddslashes($_REQUEST['item_comment'])
1286 . "' ";
1288 if (isset($_REQUEST['item_isdeterministic'])) {
1289 $query .= 'DETERMINISTIC ';
1290 } else {
1291 $query .= 'NOT DETERMINISTIC ';
1293 if (! empty($_REQUEST['item_sqldataaccess'])
1294 && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess)
1296 $query .= $_REQUEST['item_sqldataaccess'] . ' ';
1298 if (! empty($_REQUEST['item_securitytype'])) {
1299 if ($_REQUEST['item_securitytype'] == 'DEFINER'
1300 || $_REQUEST['item_securitytype'] == 'INVOKER'
1302 $query .= 'SQL SECURITY ' . $_REQUEST['item_securitytype'] . ' ';
1305 if (! empty($_REQUEST['item_definition'])) {
1306 $query .= $_REQUEST['item_definition'];
1307 } else {
1308 $errors[] = __('You must provide a routine definition.');
1311 return $query;
1312 } // end PMA_RTN_getQueryFromRequest()
1315 * Handles requests for executing a routine
1317 * @return void
1319 function PMA_RTN_handleExecute()
1321 global $_GET, $_POST, $_REQUEST, $GLOBALS, $db;
1324 * Handle all user requests other than the default of listing routines
1326 if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['item_name'])) {
1327 // Build the queries
1328 $routine = PMA_RTN_getDataFromName(
1329 $_REQUEST['item_name'], $_REQUEST['item_type'], false
1331 if ($routine === false) {
1332 $message = __('Error in processing request:') . ' ';
1333 $message .= sprintf(
1334 PMA_RTE_getWord('not_found'),
1335 htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])),
1336 htmlspecialchars(PMA_Util::backquote($db))
1338 $message = PMA_message::error($message);
1339 if ($GLOBALS['is_ajax_request']) {
1340 $response = PMA_Response::getInstance();
1341 $response->isSuccess(false);
1342 $response->addJSON('message', $message);
1343 exit;
1344 } else {
1345 echo $message->getDisplay();
1346 unset($_POST);
1350 $queries = array();
1351 $end_query = array();
1352 $args = array();
1353 $all_functions = $GLOBALS['PMA_Types']->getAllFunctions();
1354 for ($i=0; $i<$routine['item_num_params']; $i++) {
1355 if (isset($_REQUEST['params'][$routine['item_param_name'][$i]])) {
1356 $value = $_REQUEST['params'][$routine['item_param_name'][$i]];
1357 if (is_array($value)) { // is SET type
1358 $value = implode(',', $value);
1360 $value = PMA_Util::sqlAddSlashes($value);
1361 if (! empty($_REQUEST['funcs'][$routine['item_param_name'][$i]])
1362 && in_array(
1363 $_REQUEST['funcs'][$routine['item_param_name'][$i]],
1364 $all_functions
1367 $queries[] = "SET @p$i="
1368 . $_REQUEST['funcs'][$routine['item_param_name'][$i]]
1369 . "('$value');\n";
1370 } else {
1371 $queries[] = "SET @p$i='$value';\n";
1373 $args[] = "@p$i";
1374 } else {
1375 $args[] = "@p$i";
1377 if ($routine['item_type'] == 'PROCEDURE') {
1378 if ($routine['item_param_dir'][$i] == 'OUT'
1379 || $routine['item_param_dir'][$i] == 'INOUT'
1381 $end_query[] = "@p$i AS "
1382 . PMA_Util::backquote($routine['item_param_name'][$i]);
1386 if ($routine['item_type'] == 'PROCEDURE') {
1387 $queries[] = "CALL " . PMA_Util::backquote($routine['item_name'])
1388 . "(" . implode(', ', $args) . ");\n";
1389 if (count($end_query)) {
1390 $queries[] = "SELECT " . implode(', ', $end_query) . ";\n";
1392 } else {
1393 $queries[] = "SELECT " . PMA_Util::backquote($routine['item_name'])
1394 . "(" . implode(', ', $args) . ") "
1395 . "AS " . PMA_Util::backquote($routine['item_name'])
1396 . ";\n";
1399 // Get all the queries as one SQL statement
1400 $multiple_query = implode("", $queries);
1402 $outcome = true;
1403 $affected = 0;
1405 // Execute query
1406 if (! $GLOBALS['dbi']->tryMultiQuery($multiple_query)) {
1407 $outcome = false;
1410 // Generate output
1411 if ($outcome) {
1413 // Pass the SQL queries through the "pretty printer"
1414 $output = PMA_Util::formatSql(implode($queries, "\n"));
1416 // Display results
1417 $output .= "<fieldset><legend>";
1418 $output .= sprintf(
1419 __('Execution results of routine %s'),
1420 PMA_Util::backquote(htmlspecialchars($routine['item_name']))
1422 $output .= "</legend>";
1424 $nbResultsetToDisplay = 0;
1426 do {
1428 $result = $GLOBALS['dbi']->storeResult();
1429 $num_rows = $GLOBALS['dbi']->numRows($result);
1431 if (($result !== false) && ($num_rows > 0)) {
1433 $output .= "<table><tr>";
1434 foreach ($GLOBALS['dbi']->getFieldsMeta($result) as $field) {
1435 $output .= "<th>";
1436 $output .= htmlspecialchars($field->name);
1437 $output .= "</th>";
1439 $output .= "</tr>";
1441 $color_class = 'odd';
1443 while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
1444 $output .= "<tr>" . browseRow($row, $color_class) . "</tr>";
1445 $color_class = ($color_class == 'odd') ? 'even' : 'odd';
1448 $output .= "</table>";
1449 $nbResultsetToDisplay++;
1450 $affected = $num_rows;
1454 if (! $GLOBALS['dbi']->moreResults()) {
1455 break;
1458 $output .= "<br/>";
1460 $GLOBALS['dbi']->freeResult($result);
1462 } while ($GLOBALS['dbi']->nextResult());
1464 $output .= "</fieldset>";
1466 $message = __('Your SQL query has been executed successfully.');
1467 if ($routine['item_type'] == 'PROCEDURE') {
1468 $message .= '<br />';
1470 // TODO : message need to be modified according to the
1471 // output from the routine
1472 $message .= sprintf(
1473 _ngettext(
1474 '%d row affected by the last statement inside the '
1475 . 'procedure.',
1476 '%d rows affected by the last statement inside the '
1477 . 'procedure.',
1478 $affected
1480 $affected
1483 $message = PMA_message::success($message);
1485 if ($nbResultsetToDisplay == 0) {
1486 $notice = __(
1487 'MySQL returned an empty result set (i.e. zero rows).'
1489 $output .= PMA_message::notice($notice)->getDisplay();
1492 } else {
1493 $output = '';
1494 $message = PMA_message::error(
1495 sprintf(
1496 __('The following query has failed: "%s"'),
1497 htmlspecialchars($multiple_query)
1499 . '<br /><br />'
1500 . __('MySQL said: ') . $GLOBALS['dbi']->getError(null)
1504 // Print/send output
1505 if ($GLOBALS['is_ajax_request']) {
1506 $response = PMA_Response::getInstance();
1507 $response->isSuccess($message->isSuccess());
1508 $response->addJSON('message', $message->getDisplay() . $output);
1509 $response->addJSON('dialog', false);
1510 exit;
1511 } else {
1512 echo $message->getDisplay() . $output;
1513 if ($message->isError()) {
1514 // At least one query has failed, so shouldn't
1515 // execute any more queries, so we quit.
1516 exit;
1518 unset($_POST);
1519 // Now deliberately fall through to displaying the routines list
1521 return;
1522 } else if (! empty($_GET['execute_dialog']) && ! empty($_GET['item_name'])) {
1524 * Display the execute form for a routine.
1526 $routine = PMA_RTN_getDataFromName(
1527 $_GET['item_name'], $_GET['item_type'], true
1529 if ($routine !== false) {
1530 $form = PMA_RTN_getExecuteForm($routine);
1531 if ($GLOBALS['is_ajax_request'] == true) {
1532 $title = __("Execute routine") . " " . PMA_Util::backquote(
1533 htmlentities($_GET['item_name'], ENT_QUOTES)
1535 $response = PMA_Response::getInstance();
1536 $response->addJSON('message', $form);
1537 $response->addJSON('title', $title);
1538 $response->addJSON('dialog', true);
1539 } else {
1540 echo "\n\n<h2>" . __("Execute routine") . "</h2>\n\n";
1541 echo $form;
1543 exit;
1544 } else if (($GLOBALS['is_ajax_request'] == true)) {
1545 $message = __('Error in processing request:') . ' ';
1546 $message .= sprintf(
1547 PMA_RTE_getWord('not_found'),
1548 htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])),
1549 htmlspecialchars(PMA_Util::backquote($db))
1551 $message = PMA_message::error($message);
1553 $response = PMA_Response::getInstance();
1554 $response->isSuccess(false);
1555 $response->addJSON('message', $message);
1556 exit;
1562 * Browse row array
1564 * @param array $row Columns
1565 * @param string $color_class CSS class
1567 * @return string
1569 function browseRow($row, $color_class)
1571 $output = null;
1572 foreach ($row as $value) {
1573 if ($value === null) {
1574 $value = '<i>NULL</i>';
1575 } else {
1576 $value = htmlspecialchars($value);
1578 $output .= "<td class='" . $color_class . "'>" . $value . "</td>";
1580 return $output;
1584 * Creates the HTML code that shows the routine execution dialog.
1586 * @param array $routine Data for the routine returned by
1587 * PMA_RTN_getDataFromName()
1589 * @return string HTML code for the routine execution dialog.
1591 function PMA_RTN_getExecuteForm($routine)
1593 global $db, $cfg;
1595 // Escape special characters
1596 $routine['item_name'] = htmlentities($routine['item_name'], ENT_QUOTES);
1597 for ($i=0; $i<$routine['item_num_params']; $i++) {
1598 $routine['item_param_name'][$i] = htmlentities(
1599 $routine['item_param_name'][$i],
1600 ENT_QUOTES
1604 // Create the output
1605 $retval = "";
1606 $retval .= "<!-- START ROUTINE EXECUTE FORM -->\n\n";
1607 $retval .= "<form action='db_routines.php' method='post'\n";
1608 $retval .= " class='rte_form ajax' onsubmit='return false'>\n";
1609 $retval .= "<input type='hidden' name='item_name'\n";
1610 $retval .= " value='{$routine['item_name']}' />\n";
1611 $retval .= "<input type='hidden' name='item_type'\n";
1612 $retval .= " value='{$routine['item_type']}' />\n";
1613 $retval .= PMA_URL_getHiddenInputs($db) . "\n";
1614 $retval .= "<fieldset>\n";
1615 if ($GLOBALS['is_ajax_request'] != true) {
1616 $retval .= "<legend>{$routine['item_name']}</legend>\n";
1617 $retval .= "<table class='rte_table'>\n";
1618 $retval .= "<caption class='tblHeaders'>\n";
1619 $retval .= __('Routine parameters');
1620 $retval .= "</caption>\n";
1621 } else {
1622 $retval .= "<legend>" . __('Routine parameters') . "</legend>\n";
1623 $retval .= "<table class='rte_table' style='width: 100%;'>\n";
1625 $retval .= "<tr>\n";
1626 $retval .= "<th>" . __('Name') . "</th>\n";
1627 $retval .= "<th>" . __('Type') . "</th>\n";
1628 if ($cfg['ShowFunctionFields']) {
1629 $retval .= "<th>" . __('Function') . "</th>\n";
1631 $retval .= "<th>" . __('Value') . "</th>\n";
1632 $retval .= "</tr>\n";
1633 // Get a list of data types that are not yet supported.
1634 $no_support_types = PMA_Util::unsupportedDatatypes();
1635 for ($i=0; $i<$routine['item_num_params']; $i++) { // Each parameter
1636 if ($routine['item_type'] == 'PROCEDURE'
1637 && $routine['item_param_dir'][$i] == 'OUT'
1639 continue;
1641 $rowclass = ($i % 2 == 0) ? 'even' : 'odd';
1642 $retval .= "\n<tr class='$rowclass'>\n";
1643 $retval .= "<td>{$routine['item_param_name'][$i]}</td>\n";
1644 $retval .= "<td>{$routine['item_param_type'][$i]}</td>\n";
1645 if ($cfg['ShowFunctionFields']) {
1646 $retval .= "<td>\n";
1647 if (stristr($routine['item_param_type'][$i], 'enum')
1648 || stristr($routine['item_param_type'][$i], 'set')
1649 || in_array(
1650 /*overload*/mb_strtolower($routine['item_param_type'][$i]),
1651 $no_support_types
1654 $retval .= "--\n";
1655 } else {
1656 $field = array(
1657 'True_Type' => /*overload*/mb_strtolower(
1658 $routine['item_param_type'][$i]
1660 'Type' => '',
1661 'Key' => '',
1662 'Field' => '',
1663 'Default' => '',
1664 'first_timestamp' => false
1666 $retval .= "<select name='funcs["
1667 . $routine['item_param_name'][$i] . "]'>";
1668 $retval .= PMA_Util::getFunctionsForField($field, false);
1669 $retval .= "</select>";
1671 $retval .= "</td>\n";
1673 // Append a class to date/time fields so that
1674 // jQuery can attach a datepicker to them
1675 $class = '';
1676 if ($routine['item_param_type'][$i] == 'DATETIME'
1677 || $routine['item_param_type'][$i] == 'TIMESTAMP'
1679 $class = 'datetimefield';
1680 } else if ($routine['item_param_type'][$i] == 'DATE') {
1681 $class = 'datefield';
1683 $retval .= "<td class='nowrap'>\n";
1684 if (in_array($routine['item_param_type'][$i], array('ENUM', 'SET'))) {
1685 $tokens = PMA_SQP_parse($routine['item_param_length'][$i]);
1686 if ($routine['item_param_type'][$i] == 'ENUM') {
1687 $input_type = 'radio';
1688 } else {
1689 $input_type = 'checkbox';
1691 for ($j=0; $j<$tokens['len']; $j++) {
1692 if ($tokens[$j]['type'] != 'punct_listsep') {
1693 $tokens[$j]['data'] = htmlentities(
1694 PMA_Util::unquote($tokens[$j]['data']),
1695 ENT_QUOTES
1697 $retval .= "<input name='params["
1698 . $routine['item_param_name'][$i] . "][]' "
1699 . "value='" . $tokens[$j]['data'] . "' type='"
1700 . $input_type . "' />"
1701 . $tokens[$j]['data'] . "<br />\n";
1704 } else if (in_array(
1705 /*overload*/mb_strtolower($routine['item_param_type'][$i]),
1706 $no_support_types
1707 )) {
1708 $retval .= "\n";
1709 } else {
1710 $retval .= "<input class='$class' type='text' name='params["
1711 . $routine['item_param_name'][$i] . "]' />\n";
1713 $retval .= "</td>\n";
1714 $retval .= "</tr>\n";
1716 $retval .= "\n</table>\n";
1717 if ($GLOBALS['is_ajax_request'] != true) {
1718 $retval .= "</fieldset>\n\n";
1719 $retval .= "<fieldset class='tblFooters'>\n";
1720 $retval .= " <input type='submit' name='execute_routine'\n";
1721 $retval .= " value='" . __('Go') . "' />\n";
1722 $retval .= "</fieldset>\n";
1723 } else {
1724 $retval .= "<input type='hidden' name='execute_routine' value='true' />";
1725 $retval .= "<input type='hidden' name='ajax_request' value='true' />";
1727 $retval .= "</form>\n\n";
1728 $retval .= "<!-- END ROUTINE EXECUTE FORM -->\n\n";
1730 return $retval;
1731 } // end PMA_RTN_getExecuteForm()