withData([ 'query' => self::truncateQuery($query), 'sqlstate' => $sqlState->code, 'sqlstate_class' => $sqlState->getClass(), 'error_category' => 'Syntax Error or Access Violation', ]) ->withDebug([ 'full_query' => $query, 'sqlstate_subclass' => $sqlState->getSubclass(), ]); return self::fromContext($message, $context, DatabaseErrorCode::QUERY_SYNTAX_ERROR, $previous, 500, $sqlState); } /** * Create exception for undefined table * * @param string $tableName The table name that was not found * @param SqlState $sqlState The SQLSTATE error code (typically 42P01 or 42S02) * @param string|null $query Optional SQL query */ public static function tableNotFound( string $tableName, SqlState $sqlState, ?string $query = null ): self { $message = "Table '{$tableName}' does not exist"; $context = ExceptionContext::forOperation('query.validate', 'Database') ->withData([ 'table_name' => $tableName, 'sqlstate' => $sqlState->code, 'error_category' => 'Syntax Error or Access Violation', ]); if ($query !== null) { $context = $context->withDebug(['query' => self::truncateQuery($query)]); } return self::fromContext($message, $context, DatabaseErrorCode::QUERY_SYNTAX_ERROR, null, 500, $sqlState); } /** * Create exception for undefined column * * @param string $columnName The column name that was not found * @param string|null $tableName Optional table name * @param SqlState $sqlState The SQLSTATE error code (typically 42703 or 42S22) * @param string|null $query Optional SQL query */ public static function columnNotFound( string $columnName, ?string $tableName, SqlState $sqlState, ?string $query = null ): self { $message = $tableName !== null ? "Column '{$tableName}.{$columnName}' does not exist" : "Column '{$columnName}' does not exist"; $context = ExceptionContext::forOperation('query.validate', 'Database') ->withData([ 'column_name' => $columnName, 'sqlstate' => $sqlState->code, 'error_category' => 'Syntax Error or Access Violation', ]); if ($tableName !== null) { $context = $context->withData(['table_name' => $tableName]); } if ($query !== null) { $context = $context->withDebug(['query' => self::truncateQuery($query)]); } return self::fromContext($message, $context, DatabaseErrorCode::QUERY_SYNTAX_ERROR, null, 500, $sqlState); } /** * Create exception for undefined function * * @param string $functionName The function name that was not found * @param SqlState $sqlState The SQLSTATE error code (typically 42883) * @param string|null $query Optional SQL query */ public static function functionNotFound( string $functionName, SqlState $sqlState, ?string $query = null ): self { $message = "Function '{$functionName}' does not exist"; $context = ExceptionContext::forOperation('query.validate', 'Database') ->withData([ 'function_name' => $functionName, 'sqlstate' => $sqlState->code, 'error_category' => 'Syntax Error or Access Violation', ]); if ($query !== null) { $context = $context->withDebug(['query' => self::truncateQuery($query)]); } return self::fromContext($message, $context, DatabaseErrorCode::QUERY_SYNTAX_ERROR, null, 500, $sqlState); } /** * Create exception for insufficient privileges * * @param string $operation The operation that was attempted (e.g., SELECT, INSERT, DROP) * @param string|null $objectName Optional database object name * @param SqlState $sqlState The SQLSTATE error code (typically 42501) */ public static function insufficientPrivileges( string $operation, ?string $objectName, SqlState $sqlState ): self { $message = $objectName !== null ? "Insufficient privileges to {$operation} on '{$objectName}'" : "Insufficient privileges to perform {$operation}"; $context = ExceptionContext::forOperation('query.authorize', 'Database') ->withData([ 'operation' => $operation, 'sqlstate' => $sqlState->code, 'error_category' => 'Syntax Error or Access Violation', ]); if ($objectName !== null) { $context = $context->withData(['object_name' => $objectName]); } return self::fromContext($message, $context, DatabaseErrorCode::QUERY_SYNTAX_ERROR, null, 500, $sqlState); } /** * Create exception for ambiguous column reference * * @param string $columnName The ambiguous column name * @param SqlState $sqlState The SQLSTATE error code * @param string|null $query Optional SQL query */ public static function ambiguousColumn( string $columnName, SqlState $sqlState, ?string $query = null ): self { $message = "Ambiguous column reference '{$columnName}' - specify table name"; $context = ExceptionContext::forOperation('query.validate', 'Database') ->withData([ 'column_name' => $columnName, 'sqlstate' => $sqlState->code, 'error_category' => 'Syntax Error or Access Violation', ]); if ($query !== null) { $context = $context->withDebug(['query' => self::truncateQuery($query)]); } return self::fromContext($message, $context, DatabaseErrorCode::QUERY_SYNTAX_ERROR, null, 500, $sqlState); } /** * Create exception for invalid SQL syntax at specific position * * @param string $query The SQL query * @param int $position Error position in query * @param string $nearText Text near the error * @param SqlState $sqlState The SQLSTATE error code */ public static function syntaxErrorAt( string $query, int $position, string $nearText, SqlState $sqlState ): self { $message = "Syntax error at position {$position} near '{$nearText}'"; $context = ExceptionContext::forOperation('query.parse', 'Database') ->withData([ 'error_position' => $position, 'near_text' => $nearText, 'query' => self::truncateQuery($query), 'sqlstate' => $sqlState->code, 'error_category' => 'Syntax Error or Access Violation', ]) ->withDebug([ 'full_query' => $query, ]); return self::fromContext($message, $context, DatabaseErrorCode::QUERY_SYNTAX_ERROR, null, 500, $sqlState); } /** * Truncate query for safe logging * * @param string $query The SQL query * @param int $maxLength Maximum length * @return string Truncated query */ private static function truncateQuery(string $query, int $maxLength = 200): string { if (strlen($query) <= $maxLength) { return $query; } return substr($query, 0, $maxLength) . '... (truncated)'; } }