SqlSyntaxException.php
PHP
Path: src/Parsing/SQL/SqlSyntaxException.php
<?php
namespace mini\Parsing\SQL;
/**
* SQL Syntax Exception with rich error reporting
*
* Provides line numbers and visual pointers to syntax errors
*/
class SqlSyntaxException extends \LogicException
{
public function __construct(string $message, string $sql, int $pos)
{
[$lineNum, $colNum, $lineSnippet, $pointer] = $this->getDetailedContext($sql, $pos);
$output = sprintf(
"%s at line %d, column %d\n\n%s\n%s",
$message,
$lineNum,
$colNum,
$lineSnippet,
$pointer
);
parent::__construct($output);
}
private function getDetailedContext(string $sql, int $pos): array
{
// Calculate line number by counting newlines up to $pos
$prefix = substr($sql, 0, $pos);
$lineNum = substr_count($prefix, "\n") + 1;
// Calculate column number: position - last newline position
$lastNewlinePos = strrpos($prefix, "\n");
if ($lastNewlinePos === false) {
$colNum = $pos + 1;
$lineStart = 0;
} else {
$colNum = $pos - $lastNewlinePos;
$lineStart = $lastNewlinePos + 1;
}
// Extract the specific line for display
$lineEnd = strpos($sql, "\n", $lineStart);
if ($lineEnd === false) {
$lineEnd = strlen($sql);
}
// Trim \r if present (for Windows line endings)
$lineSnippet = rtrim(substr($sql, $lineStart, $lineEnd - $lineStart), "\r");
// Create the pointer string (e.g., " ^")
$colIndex = max(0, $colNum - 1);
$pointer = str_repeat(' ', $colIndex) . '^';
return [$lineNum, $colNum, $lineSnippet, $pointer];
}
}