diff --git a/adminer/drivers/mysql.inc.php b/adminer/drivers/mysql.inc.php index daabae7a..681a4e13 100644 --- a/adminer/drivers/mysql.inc.php +++ b/adminer/drivers/mysql.inc.php @@ -510,6 +510,16 @@ if (!defined("DRIVER")) { return h(preg_replace('~^You have an error.*syntax to use~U', "Syntax error", $connection->error)); } + /** Get line of error + * @return int 0 for first line + */ + function error_line() { + global $connection; + if (ereg(' at line ([0-9]+)$', $connection->error, $regs)) { + return $regs[1] - 1; + } + } + /** Return expression for binary comparison * @param string * @return string diff --git a/adminer/sql.inc.php b/adminer/sql.inc.php index 61acae2f..06a068cc 100644 --- a/adminer/sql.inc.php +++ b/adminer/sql.inc.php @@ -54,6 +54,8 @@ if (!$error && $_POST) { } $commands = 0; $errors = array(); + $error_lines = array(); + $line = 0; $parse = '[\'"' . ($jush == "sql" ? '`#' : ($jush == "sqlite" ? '`[' : ($jush == "mssql" ? '[' : ''))) . ']|/\\*|-- |$' . ($jush == "pgsql" ? '|\\$[^$]*\\$' : ''); $total_start = microtime(); parse_str($_COOKIE["adminer_export"], $adminer_export); @@ -64,16 +66,16 @@ if (!$error && $_POST) { $delimiter = $match[1]; $query = substr($query, strlen($match[0])); } else { - preg_match('(' . preg_quote($delimiter) . "|$parse)", $query, $match, PREG_OFFSET_CAPTURE, $offset); // should always match - $found = $match[0][0]; + preg_match('(' . preg_quote($delimiter) . "\\s*|$parse)", $query, $match, PREG_OFFSET_CAPTURE, $offset); // should always match + list($found, $pos) = $match[0]; if (!$found && $fp && !feof($fp)) { $query .= fread($fp, 1e5); } else { - $offset = $match[0][1] + strlen($found); + $offset = $pos + strlen($found); if (!$found && rtrim($query) == "") { break; } - if ($found && $found != $delimiter) { // find matching quote or comment end + if ($found && rtrim($found) != $delimiter) { // find matching quote or comment end while (preg_match('(' . ($found == '/*' ? '\\*/' : ($found == '[' ? ']' : (ereg('^-- |^#', $found) ? "\n" : preg_quote($found) . "|\\\\."))) . '|$)s', $query, $match, PREG_OFFSET_CAPTURE, $offset)) { //! respect sql_mode NO_BACKSLASH_ESCAPES $s = $match[0][0]; if (!$s && $fp && !feof($fp)) { @@ -87,7 +89,7 @@ if (!$error && $_POST) { } } else { // end of a query $empty = false; - $q = substr($query, 0, $match[0][1]); + $q = substr($query, 0, $pos); $commands++; $print = "
" . shorten_utf8(trim($q), 1000) . "
\n"; if (!$_POST["only_errors"]) { @@ -107,6 +109,7 @@ if (!$error && $_POST) { if ($connection->error) { echo ($_POST["only_errors"] ? $print : ""); echo "

" . lang('Error in query') . ": " . error() . "\n"; + $error_lines[] = $line + (function_exists('error_line') ? error_line() : 0); $errors[] = " $commands"; if ($_POST["error_stops"]) { break 2; @@ -146,6 +149,7 @@ if (!$error && $_POST) { } $start = $end; } while ($connection->next_result()); + $line += substr_count($q.$found, "\n"); $query = substr($query, $offset); $offset = 0; } @@ -220,6 +224,7 @@ if ($history) { diff --git a/adminer/static/default.css b/adminer/static/default.css index cd42bae0..b9d6c251 100644 --- a/adminer/static/default.css +++ b/adminer/static/default.css @@ -60,6 +60,7 @@ input[type=image] { vertical-align: middle; } .rtl #lang, .rtl #menu { left: auto; right: 0; } .CodeMirror { border: 1px inset #777; } +.CodeMirror .error { background: #fee; } @media print { #lang, #menu { display: none; } diff --git a/changes.txt b/changes.txt index 4e71f397..97a93b38 100644 --- a/changes.txt +++ b/changes.txt @@ -1,6 +1,6 @@ Adminer 3.4.0-dev: Print current time next to executed SQL queries -Highlight code in textarea by CodeMirror +Highlight code in SQL command by CodeMirror Link to original table in EXPLAIN of SELECT * FROM table t Replace JSMin by better JavaScript minifier Don't use AJAX links and forms