/** * Displays a MySQL error message in the main panel when $exit is true. * Returns the error message otherwise. * * @param string|bool $server_msg Server's error message. * @param string $sql_query The SQL query that failed. * @param bool $is_modify_link Whether to show a "modify" link or not. * @param string $back_url URL for the "back" link (full path is * not required). * @param bool $exit Whether execution should be stopped or * the error message should be returned. * * @return string * * @global string $table The current table. * @global string $db The current database. * * @access public */ public static function mysqlDie($server_msg = '', $sql_query = '', $is_modify_link = true, $back_url = '', $exit = true) { global $table, $db; /** * Error message to be built. * @var string $error_msg */ $error_msg = ''; // Checking for any server errors. if (empty($server_msg)) { $server_msg = $GLOBALS['dbi']->getError(); } // Finding the query that failed, if not specified. if (empty($sql_query) && !empty($GLOBALS['sql_query'])) { $sql_query = $GLOBALS['sql_query']; } $sql_query = trim($sql_query); $errors = array(); if (!empty($sql_query)) { /** * The lexer used for analysis. * @var SqlParser\Lexer $lexer */ $lexer = new SqlParser\Lexer($sql_query); /** * The parser used for analysis. * @var SqlParser\Parser $parser */ $parser = new SqlParser\Parser($lexer->list); /** * The errors found by the lexer and the parser. * @var array $errors */ $errors = SqlParser\Utils\Error::get(array($lexer, $parser)); } if (empty($sql_query)) { $formatted_sql = ''; } elseif (count($errors)) { $formatted_sql = htmlspecialchars($sql_query); } else { $formatted_sql = self::formatSql($sql_query, true); } $error_msg .= '<div class="error"><h1>' . __('Error') . '</h1>'; // For security reasons, if the MySQL refuses the connection, the query // is hidden so no details are revealed. if (!empty($sql_query) && !mb_strstr($sql_query, 'connect')) { // Static analysis errors. if (!empty($errors)) { $error_msg .= '<p><strong>' . __('Static analysis:') . '</strong></p>'; $error_msg .= '<p>' . sprintf(__('%d errors were found during analysis.'), count($errors)) . '</p>'; $error_msg .= '<p><ol>'; $error_msg .= implode(SqlParser\Utils\Error::format($errors, '<li>%2$s (near "%4$s" at position %5$d)</li>')); $error_msg .= '</ol></p>'; } // Display the SQL query and link to MySQL documentation. $error_msg .= '<p><strong>' . __('SQL query:') . '</strong>' . "\n"; $formattedSqlToLower = mb_strtolower($formatted_sql); // TODO: Show documentation for all statement types. if (mb_strstr($formattedSqlToLower, 'select')) { // please show me help to the error on select $error_msg .= self::showMySQLDocu('SELECT'); } if ($is_modify_link) { $_url_params = array('sql_query' => $sql_query, 'show_query' => 1); if (mb_strlen($table)) { $_url_params['db'] = $db; $_url_params['table'] = $table; $doedit_goto = '<a href="tbl_sql.php' . PMA_URL_getCommon($_url_params) . '">'; } elseif (mb_strlen($db)) { $_url_params['db'] = $db; $doedit_goto = '<a href="db_sql.php' . PMA_URL_getCommon($_url_params) . '">'; } else { $doedit_goto = '<a href="server_sql.php' . PMA_URL_getCommon($_url_params) . '">'; } $error_msg .= $doedit_goto . self::getIcon('b_edit.png', __('Edit')) . '</a>'; } $error_msg .= ' </p>' . "\n" . '<p>' . "\n" . $formatted_sql . "\n" . '</p>' . "\n"; } // Display server's error. if (!empty($server_msg)) { $server_msg = preg_replace("@((\r\n)|(\r)|(\n)){3,}@", "\n\n", $server_msg); // Adds a link to MySQL documentation. $error_msg .= '<p>' . "\n" . ' <strong>' . __('MySQL said: ') . '</strong>' . self::showMySQLDocu('Error-messages-server') . "\n" . '</p>' . "\n"; // The error message will be displayed within a CODE segment. // To preserve original formatting, but allow word-wrapping, // a couple of replacements are done. // All non-single blanks and TAB-characters are replaced with their // HTML-counterpart $server_msg = str_replace(array(' ', "\t"), array(' ', ' '), $server_msg); // Replace line breaks $server_msg = nl2br($server_msg); $error_msg .= '<code>' . $server_msg . '</code><br/>'; } $error_msg .= '</div>'; $_SESSION['Import_message']['message'] = $error_msg; if (!$exit) { return $error_msg; } /** * If this is an AJAX request, there is no "Back" link and * `PMA_Response()` is used to send the response. */ if (!empty($GLOBALS['is_ajax_request'])) { $response = PMA_Response::getInstance(); $response->isSuccess(false); $response->addJSON('message', $error_msg); exit; } if (!empty($back_url)) { if (mb_strstr($back_url, '?')) { $back_url .= '&no_history=true'; } else { $back_url .= '?no_history=true'; } $_SESSION['Import_message']['go_back_url'] = $back_url; $error_msg .= '<fieldset class="tblFooters">' . '[ <a href="' . $back_url . '">' . __('Back') . '</a> ]' . '</fieldset>' . "\n\n"; } exit($error_msg); }
/** * Runs the linting process. * * @param string $query The query to be checked. * * @return array */ public static function lint($query) { // Disabling lint for huge queries to save some resources. if (mb_strlen($query) > 10000) { return array(array('message' => __('Linting is disabled for this query because it exceeds the ' . 'maximum length.'), 'fromLine' => 0, 'fromColumn' => 0, 'toLine' => 0, 'toColumn' => 0, 'severity' => 'warning')); } /** * Lexer used for tokenizing the query. * * @var SqlParser\Lexer */ $lexer = new SqlParser\Lexer($query); /** * Parsed used for analysing the query. * * @var SqlParser\Parser */ $parser = new SqlParser\Parser($lexer->list); /** * Array containing all errors. * * @var array */ $errors = SqlParser\Utils\Error::get(array($lexer, $parser)); /** * The response containing of all errors. * * @var array */ $response = array(); /** * The starting position for each line. * * CodeMirror requires relative position to line, but the parser stores * only the absolute position of the character in string. * * @var array */ $lines = static::getLines($query); // Building the response. foreach ($errors as $idx => $error) { // Starting position of the string that caused the error. list($fromLine, $fromColumn) = static::findLineNumberAndColumn($lines, $error[3]); // Ending position of the string that caused the error. list($toLine, $toColumn) = static::findLineNumberAndColumn($lines, $error[3] + mb_strlen($error[2])); // Building the response. $response[] = array('message' => sprintf(__('%1$s (near <code>%2$s</code>)'), $error[0], $error[2]), 'fromLine' => $fromLine, 'fromColumn' => $fromColumn, 'toLine' => $toLine, 'toColumn' => $toColumn, 'severity' => 'error'); } // Sending back the answer. return $response; }