Skip to main content
The databas_sql_parser crate provides detailed error reporting for SQL parsing failures, including position tracking and descriptive error messages.

SQLError

The main error type returned by the lexer and parser.
pub struct SQLError<'a> {
    pub kind: SQLErrorKind<'a>,
    pub pos: usize,
}
kind
SQLErrorKind<'a>
The specific kind of parsing error that occurred.
pos
usize
Byte offset in the source string where the error was detected.

Constructor

pub fn new(kind: SQLErrorKind<'a>, pos: usize) -> Self
Creates a new SQL error with the given kind and position. Example:
use databas_sql_parser::error::{SQLError, SQLErrorKind};

let error = SQLError::new(
    SQLErrorKind::UnexpectedEnd,
    42
);

SQLErrorKind

Enum describing the specific type of parsing error.
pub enum SQLErrorKind<'a> {
    ExpectedCommaOrSemicolon,
    ExpectedExpression,
    ExpectedIdentifier { got: TokenKind<'a> },
    ExpectedInteger { got: TokenKind<'a> },
    ExpectedNonNegativeInteger { got: i32 },
    ExpectedOther { expected: TokenKind<'a> },
    InvalidCharacter { c: char },
    InvalidNumber,
    InvalidOperator { op: TokenKind<'a> },
    InvalidPrefixOperator { op: TokenKind<'a> },
    InvalidDataType { got: TokenKind<'a> },
    Other(TokenKind<'a>),
    UnclosedParenthesis,
    UnexpectedEnd,
    UnexpectedTokenKind { expected: TokenKind<'a>, got: TokenKind<'a> },
    UnterminatedStatement,
    UnterminatedString,
    DuplicateConstraint { column: &'a str, constraint: ColumnConstraint },
}

Syntax Errors

ExpectedCommaOrSemicolon

ExpectedCommaOrSemicolon
Expected a comma , or semicolon ; but found a different token. Occurs in contexts like:
  • Column lists in SELECT
  • Value lists in INSERT
  • End of statements

ExpectedExpression

ExpectedExpression
Expected an expression but found a token that cannot start an expression. Example that triggers this:
SELECT FROM users;  -- Missing column expression

ExpectedIdentifier

ExpectedIdentifier { got: TokenKind<'a> }
Expected an identifier (column name, table name) but found a different token. Example:
CREATE TABLE 123 (id INT);  -- Table name must be identifier

ExpectedInteger

ExpectedInteger { got: TokenKind<'a> }
Expected an integer literal but found a different token type. Occurs with:
  • LIMIT clause
  • OFFSET clause
Example:
SELECT * FROM users LIMIT 'ten';  -- LIMIT requires integer

ExpectedNonNegativeInteger

ExpectedNonNegativeInteger { got: i32 }
Expected a non-negative integer but found a negative number. Example:
SELECT * FROM users LIMIT -10;  -- LIMIT must be non-negative

ExpectedOther

ExpectedOther { expected: TokenKind<'a> }
Expected a specific token but found something else. Generic error for unexpected tokens in specific contexts.

Lexical Errors

InvalidCharacter

InvalidCharacter { c: char }
Encountered an invalid character that cannot be part of any token. Example:
SELECT @ FROM users;  -- '@' is not a valid character

InvalidNumber

InvalidNumber
Number literal has invalid format and cannot be parsed. Example:
SELECT 3.14.159 FROM pi;  -- Multiple decimal points

UnterminatedString

UnterminatedString
String literal is missing closing quote. Example:
INSERT INTO users (name) VALUES ('Alice;  -- Missing closing '

Expression Errors

InvalidOperator

InvalidOperator { op: TokenKind<'a> }
Token cannot be used as an infix operator in the current context. Example:
SELECT id AND FROM users;  -- 'FROM' is not an operator

InvalidPrefixOperator

InvalidPrefixOperator { op: TokenKind<'a> }
Token cannot be used as a unary prefix operator. Example:
SELECT + * FROM users;  -- '+' cannot prefix '*'

Statement Errors

InvalidDataType

InvalidDataType { got: TokenKind<'a> }
Expected a valid data type (INT, FLOAT, TEXT) but found something else. Example:
CREATE TABLE users (id STRING);  -- STRING is not a valid type

DuplicateConstraint

DuplicateConstraint { column: &'a str, constraint: ColumnConstraint }
A column constraint was specified multiple times. Example:
CREATE TABLE users (
    id INT PRIMARY KEY PRIMARY KEY  -- PRIMARY KEY specified twice
);

Structural Errors

UnclosedParenthesis

UnclosedParenthesis
Opening parenthesis has no matching closing parenthesis. Example:
SELECT (id + 1 FROM users;  -- Missing )

UnexpectedEnd

UnexpectedEnd
Input ended unexpectedly while parsing was still in progress. Example:
SELECT * FROM  -- Missing table name

UnexpectedTokenKind

UnexpectedTokenKind { expected: TokenKind<'a>, got: TokenKind<'a> }
Found a specific token when expecting a different specific token. Most specific error for token mismatches. Example:
SELECT * FORM users;  -- Expected FROM, got FORM (identifier)

UnterminatedStatement

UnterminatedStatement
Statement appears incomplete or malformed.

Other

Other(TokenKind<'a>)
Unexpected token in current parsing context. Generic fallback error.

Error Display

All error types implement Display for human-readable messages:
use databas_sql_parser::parser::Parser;

let mut parser = Parser::new("SELECT * FORM users");
match parser.stmt() {
    Ok(_) => println!("Parsed successfully"),
    Err(e) => eprintln!("Parse error at position {}: {}", e.pos, e.kind),
}
Example output:
Parse error at position 9: expected FROM, got identifier 'FORM'

Error Recovery

The parser does not attempt error recovery. When an error is encountered:
  1. Parsing stops immediately
  2. The error is returned with position information
  3. No partial AST is produced
Example with multiple statements:
use databas_sql_parser::parser::Parser;

let sql = "
    SELECT * FROM users;
    SELECT * FORM products;  -- Error here
    SELECT * FROM orders;
";

let parser = Parser::new(sql);
for result in parser {
    match result {
        Ok(stmt) => println!("Parsed: {}", stmt),
        Err(e) => {
            eprintln!("Error at {}: {}", e.pos, e.kind);
            break;  // Stop processing on first error
        }
    }
}

Position Tracking

The pos field contains the byte offset (not character offset) where the error occurred:
let sql = "SELECT * FROM users WHERE name = 'Alice";
let mut parser = Parser::new(sql);

match parser.stmt() {
    Err(e) => {
        println!("Error at byte offset: {}", e.pos);
        // Extract context around error:
        let start = e.pos.saturating_sub(10);
        let end = (e.pos + 10).min(sql.len());
        println!("Context: {}", &sql[start..end]);
    }
    _ => {}
}

Common Errors and Fixes

Missing semicolon

-- Error:
SELECT * FROM users SELECT * FROM products

-- Fix:
SELECT * FROM users;
SELECT * FROM products;

Unterminated string

-- Error:
INSERT INTO users VALUES ('Alice)

-- Fix:
INSERT INTO users VALUES ('Alice')

Wrong keyword spelling

-- Error:
SELECT * FORM users

-- Fix:
SELECT * FROM users

Invalid operator

-- Error:
SELECT id <> 5 FROM users  -- <> not supported

-- Fix:
SELECT id != 5 FROM users

Missing expression

-- Error:
SELECT , name FROM users

-- Fix:
SELECT id, name FROM users

Build docs developers (and LLMs) love