package parser

import (
	"fmt"
	"strings"
)

// Parser parses CQL statements
type Parser struct {
	lexer     *Lexer
	token     Token
	peekToken Token
	errors    []string
}

// NewParser creates a new parser
func NewParser(input string) *Parser {
	p := &Parser{
		lexer:  NewLexer(input),
		errors: make([]string, 0),
	}
	// Read two tokens to set up token and peekToken
	p.nextToken()
	p.nextToken()
	return p
}

// nextToken advances to the next token
func (p *Parser) nextToken() {
	p.token = p.peekToken
	p.peekToken = p.lexer.NextToken()
	if p.token.Type == TokenError {
		p.addError(p.token.Value)
	}
}

// addError adds a parsing error
func (p *Parser) addError(format string, args ...interface{}) {
	p.errors = append(p.errors, fmt.Sprintf(format, args...))
}

// Parse parses a CQL statement
func (p *Parser) Parse() (Statement, error) {
	if len(p.errors) > 0 {
		return nil, fmt.Errorf("lexing errors: %v", p.errors)
	}

	var stmt Statement
	var err error

	switch p.token.Type {
	case TokenSelect:
		stmt, err = p.parseSelect()
	case TokenInsert:
		stmt, err = p.parseInsert()
	case TokenUpdate:
		stmt, err = p.parseUpdate()
	case TokenDelete:
		stmt, err = p.parseDelete()
	case TokenCreate:
		stmt, err = p.parseCreate()
	case TokenDrop:
		stmt, err = p.parseDrop()
	case TokenAlter:
		stmt, err = p.parseAlter()
	case TokenTruncate:
		stmt, err = p.parseTruncate()
	case TokenBegin:
		stmt, err = p.parseBatch()
	case TokenUse:
		stmt, err = p.parseUse()
	case TokenList:
		stmt, err = p.parseList()
	case TokenGrant:
		stmt, err = p.parseGrant()
	case TokenDescribe, TokenDescending:
		stmt, err = p.parseDescribe()
	case TokenEOF:
		return nil, fmt.Errorf("empty query")
	default:
		return nil, fmt.Errorf("unexpected token %s: expected SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, TRUNCATE, USE, LIST, GRANT, or DESCRIBE", p.token)
	}

	if err != nil {
		return nil, err
	}

	// Check for semicolon but don't require it
	if p.token.Type == TokenSemicolon {
		p.nextToken()
	}

	// Check for EOF
	if p.token.Type != TokenEOF {
		p.addError("unexpected token %s at end of statement", p.token)
	}

	if len(p.errors) > 0 {
		return nil, fmt.Errorf("parsing errors: %v", p.errors)
	}

	return stmt, nil
}

// parseSelect parses a SELECT statement
func (p *Parser) parseSelect() (*SelectStatement, error) {
	stmt := &SelectStatement{
		Token:   p.token.Pos,
		Columns: make([]Expression, 0),
	}

	// Already consumed SELECT
	p.nextToken()

	// Optional JSON
	if p.token.Type == TokenJSON {
		stmt.JSON = true
		p.nextToken()
	}

	// Check for DISTINCT
	if p.token.Type == TokenDistinct {
		stmt.Distinct = true
		p.nextToken()
	}

	// Parse select list
	for {
		expr, err := p.parseExpression()
		if err != nil {
			return nil, err
		}

		// Optional alias
		if p.token.Type == TokenAs {
			p.nextToken()
			alias, err := p.parseIdentifierValue()
			if err != nil {
				return nil, err
			}
			expr = &AliasedExpr{
				Token: expr.Position(),
				Expr:  expr,
				Alias: alias,
			}
		}

		stmt.Columns = append(stmt.Columns, expr)

		if p.token.Type != TokenComma {
			break
		}
		p.nextToken() // Skip comma
	}

	// Parse FROM clause
	if p.token.Type != TokenFrom {
		return nil, fmt.Errorf("expected FROM, got %s", p.token)
	}
	p.nextToken()

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.From = tableName

	// Parse optional USING CONSISTENCY
	if p.token.Type == TokenUsing {
		if err := p.parseUsingConsistency(); err != nil {
			return nil, err
		}
	}

	// Parse optional WHERE clause
	if p.token.Type == TokenWhere {
		p.nextToken()
		where, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Where = where
	}

	// Parse optional USING CONSISTENCY after WHERE
	if p.token.Type == TokenUsing {
		if err := p.parseUsingConsistency(); err != nil {
			return nil, err
		}
	}

	// Parse optional GROUP BY clause
	if p.token.Type == TokenGroup {
		p.nextToken()
		if p.token.Type != TokenBy {
			return nil, fmt.Errorf("expected BY after GROUP")
		}
		p.nextToken()

		groupBy := make([]Expression, 0)
		for {
			expr, err := p.parseExpression()
			if err != nil {
				return nil, err
			}
			groupBy = append(groupBy, expr)

			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
		stmt.GroupBy = groupBy
	}

	// Parse optional ORDER BY clause
	if p.token.Type == TokenOrder {
		orderBy, err := p.parseOrderBy()
		if err != nil {
			return nil, err
		}
		stmt.Options.OrderBy = orderBy
	}

	// Parse optional LIMIT clause
	if p.token.Type == TokenLimit {
		p.nextToken()
		limit, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Options.Limit = limit
	}

	// Parse optional PER PARTITION LIMIT clause
	if p.token.Type == TokenPer {
		if p.peekToken.Type != TokenPartition {
			return nil, fmt.Errorf("expected PARTITION after PER")
		}
		p.nextToken() // Consume PER
		p.nextToken() // Consume PARTITION
		if p.token.Type != TokenLimit {
			return nil, fmt.Errorf("expected LIMIT after PER PARTITION")
		}
		p.nextToken()
		perLimit, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Options.PerPartitionLimit = perLimit
	}

	// Parse optional OFFSET clause
	if p.token.Type == TokenOffset {
		p.nextToken()
		offset, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Options.Offset = offset
	}

	// Parse optional ALLOW FILTERING
	if p.token.Type == TokenAllow {
		if p.peekToken.Type == TokenFiltering {
			stmt.Options.AllowFiltering = true
			p.nextToken() // Consume ALLOW
			p.nextToken() // Consume FILTERING
		} else {
			return nil, fmt.Errorf("expected FILTERING after ALLOW")
		}
	}

	return stmt, nil
}

// Continue building the parser.  We've completed parsing for SELECT, INSERT, UPDATE, DELETE, CREATE, DROP.
// Next steps will include parsing expressions, table names, ORDER BY, types, etc.

// parseCountFunction parses COUNT(*) or COUNT(column)
func (p *Parser) parseCountFunction() (*FunctionCall, error) {
	token := p.token
	p.nextToken() // Consume COUNT

	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after COUNT")
	}
	p.nextToken()

	var arg Expression
	if p.token.Type == TokenAsterisk {
		arg = &StarExpr{Token: p.token.Pos}
		p.nextToken()
	} else {
		expr, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		arg = expr
	}

	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after COUNT argument")
	}
	p.nextToken()

	return &FunctionCall{
		Token: token.Pos,
		Name:  "COUNT",
		Args:  []Expression{arg},
	}, nil
}

// parseInsert parses an INSERT statement
func (p *Parser) parseInsert() (*InsertStatement, error) {
	stmt := &InsertStatement{
		Token:   p.token.Pos,
		Columns: make([]string, 0),
		Values:  make([][]Expression, 0),
	}

	// Already consumed INSERT
	p.nextToken()

	// Check for optional INTO
	if p.token.Type == TokenInto {
		p.nextToken()
	}

	// Parse table name
	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Table = tableName

	// Parse optional column list
	if p.token.Type == TokenLeftParen {
		p.nextToken()
		for {
			if p.token.Type != TokenIdentifier && !isKeywordThatCanBeIdentifier(p.token.Type) {
				return nil, fmt.Errorf("expected column name, got %s", p.token)
			}
			stmt.Columns = append(stmt.Columns, p.token.Value)
			p.nextToken()

			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}

		if p.token.Type != TokenRightParen {
			return nil, fmt.Errorf("expected ')' after column list")
		}
		p.nextToken()
	}

	// Parse VALUES or JSON
	if p.token.Type != TokenValues {
		if p.token.Type == TokenJSON {
			stmt.JSON = true
			p.nextToken()
			jsonExpr, err := p.parseExpression()
			if err != nil {
				return nil, err
			}
			stmt.JSONValue = jsonExpr
		} else {
			return nil, fmt.Errorf("expected VALUES or JSON, got %s", p.token)
		}
	} else {
		p.nextToken()

		// Parse value lists
		for {
			if p.token.Type != TokenLeftParen {
				return nil, fmt.Errorf("expected '(' before value list")
			}
			p.nextToken()

			values := make([]Expression, 0)
			for {
				expr, err := p.parseExpression()
				if err != nil {
					return nil, err
				}
				values = append(values, expr)

				if p.token.Type != TokenComma {
					break
				}
				p.nextToken()
			}

			if p.token.Type != TokenRightParen {
				return nil, fmt.Errorf("expected ')' after value list")
			}
			p.nextToken()

			stmt.Values = append(stmt.Values, values)

			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
	}

	// Parse optional USING clause
	if p.token.Type == TokenUsing {
		ttl, ts, err := p.parseUsingClause()
		if err != nil {
			return nil, err
		}
		stmt.TTL = ttl
		stmt.Timestamp = ts
	}

	// Parse optional IF NOT EXISTS
	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF in INSERT")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT in INSERT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	return stmt, nil
}

// Continue parsing functions for UPDATE, DELETE, CREATE, etc.

// Simple helper functions
func (p *Parser) parseUpdate() (*UpdateStatement, error) {
	stmt := &UpdateStatement{
		Token:      p.token.Pos,
		Assigments: make([]*Assignment, 0),
	}

	// Already consumed UPDATE
	p.nextToken()

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Table = tableName

	if p.token.Type == TokenUsing {
		ttl, ts, err := p.parseUsingClause()
		if err != nil {
			return nil, err
		}
		stmt.TTL = ttl
		stmt.Timestamp = ts
	}

	if p.token.Type != TokenSet {
		return nil, fmt.Errorf("expected SET, got %s", p.token)
	}
	p.nextToken()

	for {
		target, err := p.parsePrimary()
		if err != nil {
			return nil, err
		}
		if p.token.Type != TokenEqual {
			return nil, fmt.Errorf("expected '=' in SET clause")
		}
		p.nextToken()
		value, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Assigments = append(stmt.Assigments, &Assignment{
			Target: target,
			Column: assignmentBaseColumnName(target),
			Value:  value,
			Op:     "=",
		})

		if p.token.Type != TokenComma {
			break
		}
		p.nextToken()
	}

	if p.token.Type != TokenWhere {
		return nil, fmt.Errorf("expected WHERE clause")
	}
	p.nextToken()
	where, err := p.parseExpression()
	if err != nil {
		return nil, err
	}
	stmt.Where = where

	if p.token.Type == TokenUsing {
		ttl, ts, err := p.parseUsingClause()
		if err != nil {
			return nil, err
		}
		if stmt.TTL == nil {
			stmt.TTL = ttl
		}
		if stmt.Timestamp == nil {
			stmt.Timestamp = ts
		}
	}

	if p.token.Type == TokenIf {
		ifExists, cond, err := p.parseIfClause()
		if err != nil {
			return nil, err
		}
		stmt.IfExists = ifExists
		stmt.IfCondition = cond
	}

	return stmt, nil
}

func (p *Parser) parseDelete() (*DeleteStatement, error) {
	stmt := &DeleteStatement{
		Token:   p.token.Pos,
		Columns: make([]string, 0),
		Targets: make([]Expression, 0),
	}

	// Already consumed DELETE
	p.nextToken()

	if p.token.Type != TokenFrom {
		for {
			target, err := p.parsePrimary()
			if err != nil {
				return nil, err
			}
			stmt.Targets = append(stmt.Targets, target)
			stmt.Columns = append(stmt.Columns, assignmentBaseColumnName(target))

			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
	}

	if p.token.Type != TokenFrom {
		return nil, fmt.Errorf("expected FROM, got %s", p.token)
	}
	p.nextToken()

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.From = tableName

	if p.token.Type == TokenUsing {
		_, ts, err := p.parseUsingClause()
		if err != nil {
			return nil, err
		}
		stmt.Timestamp = ts
	}

	if p.token.Type != TokenWhere {
		return nil, fmt.Errorf("expected WHERE clause")
	}
	p.nextToken()
	where, err := p.parseExpression()
	if err != nil {
		return nil, err
	}
	stmt.Where = where

	if p.token.Type == TokenIf {
		ifExists, cond, err := p.parseIfClause()
		if err != nil {
			return nil, err
		}
		stmt.IfExists = ifExists
		stmt.IfCondition = cond
	}

	return stmt, nil
}

func (p *Parser) parseCreate() (Statement, error) {
	token := p.token.Pos
	p.nextToken()

	orReplace := false
	if p.token.Type == TokenOr {
		p.nextToken()
		if p.token.Type != TokenReplace {
			return nil, fmt.Errorf("expected REPLACE after OR in CREATE")
		}
		orReplace = true
		p.nextToken()
	}

	custom := false
	if p.token.Type == TokenCustom {
		custom = true
		p.nextToken()
	}

	switch p.token.Type {
	case TokenTable, TokenColumnFamily:
		return p.parseCreateTableOrLike(token)
	case TokenKeyspace:
		return p.parseCreateKeyspace(token)
	case TokenIndex:
		stmt, err := p.parseCreateIndex(token)
		if err != nil {
			return nil, err
		}
		stmt.Custom = custom
		return stmt, nil
	case TokenTypeKeyword:
		if orReplace {
			return nil, fmt.Errorf("OR REPLACE is not valid for CREATE TYPE")
		}
		return p.parseCreateType(token)
	case TokenMaterialized:
		if orReplace {
			return nil, fmt.Errorf("OR REPLACE is not valid for CREATE MATERIALIZED VIEW")
		}
		return p.parseCreateMaterializedView(token)
	case TokenTrigger:
		if orReplace {
			return nil, fmt.Errorf("OR REPLACE is not valid for CREATE TRIGGER")
		}
		return p.parseCreateTrigger(token)
	case TokenFunction:
		return p.parseCreateFunction(token, orReplace)
	case TokenAggregate:
		return p.parseCreateAggregate(token, orReplace)
	case TokenUser:
		if orReplace {
			return nil, fmt.Errorf("OR REPLACE is not valid for CREATE USER")
		}
		return p.parseCreateUser(token)
	default:
		if orReplace {
			return nil, fmt.Errorf("expected FUNCTION or AGGREGATE after OR REPLACE")
		}
		return nil, fmt.Errorf("expected TABLE, KEYSPACE, INDEX, TYPE, MATERIALIZED VIEW, TRIGGER, FUNCTION, AGGREGATE, or USER after CREATE")
	}
}

func (p *Parser) parseDrop() (Statement, error) {
	token := p.token.Pos
	p.nextToken()

	switch p.token.Type {
	case TokenTable, TokenColumnFamily:
		return p.parseDropTable(token)
	case TokenIndex:
		return p.parseDropIndex(token)
	case TokenKeyspace:
		return p.parseDropKeyspace(token)
	case TokenTypeKeyword:
		return p.parseDropType(token)
	case TokenMaterialized:
		return p.parseDropMaterializedView(token)
	case TokenTrigger:
		return p.parseDropTrigger(token)
	case TokenFunction:
		return p.parseDropFunction(token)
	case TokenAggregate:
		return p.parseDropAggregate(token)
	case TokenUser:
		return p.parseDropUser(token)
	default:
		return nil, fmt.Errorf("expected TABLE, INDEX, KEYSPACE, TYPE, MATERIALIZED VIEW, TRIGGER, FUNCTION, AGGREGATE, or USER after DROP")
	}
}

func (p *Parser) parseAlter() (Statement, error) {
	token := p.token.Pos
	p.nextToken()

	switch p.token.Type {
	case TokenTable, TokenColumnFamily:
		return p.parseAlterTable(token)
	case TokenKeyspace:
		return p.parseAlterKeyspace(token)
	case TokenTypeKeyword:
		return p.parseAlterType(token)
	case TokenMaterialized:
		return p.parseAlterMaterializedView(token)
	case TokenUser:
		return p.parseAlterUser(token)
	default:
		return nil, fmt.Errorf("expected TABLE, KEYSPACE, TYPE, MATERIALIZED VIEW, or USER after ALTER")
	}
}

func (p *Parser) parseCreateUser(token Position) (*CreateUserStatement, error) {
	stmt := &CreateUserStatement{Token: token}
	p.nextToken() // Consume USER

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	name, err := p.parseUserName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	for p.token.Type != TokenEOF && p.token.Type != TokenSemicolon {
		switch p.token.Type {
		case TokenWith:
			p.nextToken()
			if p.token.Type != TokenPassword {
				return nil, fmt.Errorf("expected PASSWORD after WITH")
			}
			p.nextToken()
			password, err := p.parsePasswordLiteral()
			if err != nil {
				return nil, err
			}
			stmt.Password = password
			stmt.HasPassword = true
		case TokenSuperuser, TokenNoSuperuser:
			superuser := p.token.Type == TokenSuperuser
			stmt.Superuser = &superuser
			p.nextToken()
		default:
			return nil, fmt.Errorf("unexpected token %s in CREATE USER", p.token)
		}
	}
	if !stmt.HasPassword {
		return nil, fmt.Errorf("CREATE USER requires WITH PASSWORD in TiDB-native mode")
	}
	return stmt, nil
}

func (p *Parser) parseAlterUser(token Position) (*AlterUserStatement, error) {
	stmt := &AlterUserStatement{Token: token}
	p.nextToken() // Consume USER

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseUserName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	for p.token.Type != TokenEOF && p.token.Type != TokenSemicolon {
		switch p.token.Type {
		case TokenWith:
			p.nextToken()
			if p.token.Type != TokenPassword {
				return nil, fmt.Errorf("expected PASSWORD after WITH")
			}
			p.nextToken()
			password, err := p.parsePasswordLiteral()
			if err != nil {
				return nil, err
			}
			stmt.Password = &password
		case TokenSuperuser, TokenNoSuperuser:
			superuser := p.token.Type == TokenSuperuser
			stmt.Superuser = &superuser
			p.nextToken()
		default:
			return nil, fmt.Errorf("unexpected token %s in ALTER USER", p.token)
		}
	}
	if stmt.Password == nil && stmt.Superuser == nil {
		return nil, fmt.Errorf("ALTER USER requires WITH PASSWORD in TiDB-native mode")
	}
	return stmt, nil
}

func (p *Parser) parseDropUser(token Position) (*DropUserStatement, error) {
	stmt := &DropUserStatement{Token: token}
	p.nextToken() // Consume USER

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseUserName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name
	return stmt, nil
}

func (p *Parser) parseList() (Statement, error) {
	stmt := &ListUsersStatement{Token: p.token.Pos}
	p.nextToken() // Consume LIST
	if p.token.Type != TokenUsers {
		return nil, fmt.Errorf("expected USERS after LIST")
	}
	p.nextToken()
	return stmt, nil
}

func (p *Parser) parseGrant() (*GrantStatement, error) {
	stmt := &GrantStatement{Token: p.token.Pos, Resource: "KEYSPACE"}
	p.nextToken() // Consume GRANT

	permissions, err := p.parseGrantPermissions()
	if err != nil {
		return nil, err
	}
	stmt.Permissions = permissions

	if p.token.Type != TokenOn {
		return nil, fmt.Errorf("expected ON after GRANT permission")
	}
	p.nextToken()
	if p.token.Type != TokenKeyspace {
		return nil, fmt.Errorf("only GRANT ... ON KEYSPACE is supported")
	}
	p.nextToken()
	keyspace, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Keyspace = keyspace

	if p.token.Type != TokenTo {
		return nil, fmt.Errorf("expected TO after GRANT resource")
	}
	p.nextToken()
	role, err := p.parseUserName()
	if err != nil {
		return nil, err
	}
	stmt.Role = role
	return stmt, nil
}

func (p *Parser) parseGrantPermissions() ([]string, error) {
	var permissions []string
	for {
		permission, err := grantPermissionFromToken(p.token)
		if err != nil {
			return nil, err
		}
		permissions = append(permissions, permission)
		p.nextToken()
		if permission == "ALL" && (p.token.Type == TokenPermission || p.token.Type == TokenPermissions) {
			p.nextToken()
		}
		if p.token.Type != TokenComma {
			break
		}
		p.nextToken()
	}
	return permissions, nil
}

func grantPermissionFromToken(token Token) (string, error) {
	switch token.Type {
	case TokenAll:
		return "ALL", nil
	case TokenSelect:
		return "SELECT", nil
	case TokenModify:
		return "MODIFY", nil
	case TokenCreate:
		return "CREATE", nil
	case TokenAlter:
		return "ALTER", nil
	case TokenDrop:
		return "DROP", nil
	case TokenAuthorize:
		return "AUTHORIZE", nil
	default:
		return "", fmt.Errorf("expected GRANT permission, got %s", token)
	}
}

func (p *Parser) parseTruncate() (Statement, error) {
	stmt := &TruncateStatement{Token: p.token.Pos}
	p.nextToken()

	if p.token.Type == TokenTable || p.token.Type == TokenColumnFamily {
		p.nextToken()
	}

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Table = tableName
	return stmt, nil
}

func (p *Parser) parseBatch() (Statement, error) {
	stmt := &BatchStatement{
		Token:     p.token.Pos,
		BatchType: "LOGGED",
		Entries:   make([]Statement, 0),
	}
	p.nextToken() // Consume BEGIN

	switch p.token.Type {
	case TokenUnlogged, TokenLogged, TokenCounter:
		stmt.BatchType = strings.ToUpper(p.token.Value)
		p.nextToken()
	}

	if p.token.Type != TokenBatch {
		return nil, fmt.Errorf("expected BATCH after BEGIN")
	}
	p.nextToken()

	if p.token.Type == TokenUsing {
		ts, err := p.parseBatchUsingTimestamp()
		if err != nil {
			return nil, err
		}
		stmt.Using = ts
	}

	for {
		if p.token.Type == TokenSemicolon {
			p.nextToken()
			continue
		}
		if p.token.Type == TokenApply {
			if len(stmt.Entries) == 0 {
				return nil, fmt.Errorf("expected batch entry before APPLY BATCH")
			}
			p.nextToken()
			if p.token.Type != TokenBatch {
				return nil, fmt.Errorf("expected BATCH after APPLY")
			}
			p.nextToken()
			return stmt, nil
		}
		if p.token.Type == TokenEOF {
			return nil, fmt.Errorf("expected APPLY BATCH")
		}

		var entry Statement
		var err error
		switch p.token.Type {
		case TokenInsert:
			entry, err = p.parseInsert()
		case TokenUpdate:
			entry, err = p.parseUpdate()
		case TokenDelete:
			entry, err = p.parseDelete()
		default:
			return nil, fmt.Errorf("expected INSERT, UPDATE, or DELETE in BATCH")
		}
		if err != nil {
			return nil, err
		}
		stmt.Entries = append(stmt.Entries, entry)
		if p.token.Type != TokenSemicolon {
			return nil, fmt.Errorf("expected ';' after batch entry")
		}
		p.nextToken()
	}
}

func (p *Parser) parseBatchUsingTimestamp() (Expression, error) {
	p.nextToken() // Consume USING
	if p.token.Type != TokenTimestamp && p.token.Type != TokenTimestampType {
		return nil, fmt.Errorf("expected TIMESTAMP in BATCH USING clause")
	}
	p.nextToken()
	expr, err := p.parseBinary(3)
	if err != nil {
		return nil, err
	}
	if p.token.Type == TokenAnd {
		return nil, fmt.Errorf("TTL is not allowed in BATCH USING clause")
	}
	return expr, nil
}

func (p *Parser) parseIfClause() (bool, Expression, error) {
	p.nextToken() // Consume IF
	if p.token.Type == TokenExists {
		p.nextToken()
		return true, nil, nil
	}
	expr, err := p.parseExpression()
	if err != nil {
		return false, nil, err
	}
	return false, expr, nil
}

func (p *Parser) parseCreateTableOrLike(token Position) (Statement, error) {
	p.nextToken() // Consume TABLE or COLUMNFAMILY

	ifNotExists := false
	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		ifNotExists = true
		p.nextToken()
	}

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}

	if p.token.Type == TokenLike {
		p.nextToken()
		sourceName, err := p.parseTableName()
		if err != nil {
			return nil, err
		}
		stmt := &CreateTableLikeStatement{
			Token:           token,
			IfNotExists:     ifNotExists,
			Name:            tableName,
			Source:          sourceName,
			Options:         make(map[string]interface{}),
			ClusteringOrder: make(map[string]string),
		}

		if p.token.Type == TokenWith {
			withIndexes, err := p.parseTableOptions(stmt.Options, stmt.ClusteringOrder, true)
			if err != nil {
				return nil, err
			}
			if wrappedTTLKey, ok := directTTLOptionWrappedKey(stmt.Options); ok {
				return nil, fmt.Errorf("WITH %s = ... is not supported, use direct TiDB TTL syntax", wrappedTTLKey)
			}
			stmt.WithIndexes = withIndexes
		}

		if !stmt.WithIndexes && p.token.Type == TokenAnd && p.peekToken.Type == TokenIdentifier && strings.EqualFold(p.peekToken.Value, "indexes") {
			p.nextToken() // Consume AND
			p.nextToken() // Consume INDEXES
			stmt.WithIndexes = true
		}

		return stmt, nil
	}

	return p.parseCreateTable(token, tableName, ifNotExists)
}

func (p *Parser) parseCreateTable(token Position, tableName *TableName, ifNotExists bool) (*CreateTableStatement, error) {
	stmt := &CreateTableStatement{
		Token:           token,
		Columns:         make([]*ColumnDefinition, 0),
		Options:         make(map[string]interface{}),
		ClusteringOrder: make(map[string]string),
		IfNotExists:     ifNotExists,
	}
	stmt.Name = tableName

	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after table name")
	}
	p.nextToken()

	for {
		// Be permissive with schema generators that put a leading comma at the start
		// of each line (can produce consecutive comma tokens like ",\n,").
		for p.token.Type == TokenComma {
			p.nextToken()
		}
		if p.token.Type == TokenRightParen {
			break
		}

		if p.token.Type == TokenPrimary {
			pk, err := p.parsePrimaryKeyClause()
			if err != nil {
				return nil, err
			}
			stmt.PrimaryKey = pk
		} else {
			colDef, inlinePK, err := p.parseColumnDefinition()
			if err != nil {
				return nil, err
			}
			stmt.Columns = append(stmt.Columns, colDef)
			if inlinePK {
				if stmt.PrimaryKey == nil {
					stmt.PrimaryKey = &PrimaryKey{PartitionKeys: []string{colDef.Name}}
				} else {
					stmt.PrimaryKey.ClusteringColumns = append(stmt.PrimaryKey.ClusteringColumns, colDef.Name)
				}
			}
		}

		if p.token.Type == TokenComma {
			for p.token.Type == TokenComma {
				p.nextToken()
			}
			if p.token.Type == TokenRightParen {
				break
			}
			continue
		}
		if p.token.Type == TokenRightParen {
			break
		}
		return nil, fmt.Errorf("expected ',' or ')' after column definition, got %s", p.token)
	}

	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after column definitions")
	}
	p.nextToken()

	if stmt.PrimaryKey == nil {
		return nil, fmt.Errorf("missing PRIMARY KEY")
	}

	if p.token.Type == TokenWith {
		_, err := p.parseTableOptions(stmt.Options, stmt.ClusteringOrder, false)
		if err != nil {
			return nil, err
		}
		if wrappedTTLKey, ok := directTTLOptionWrappedKey(stmt.Options); ok {
			return nil, fmt.Errorf("WITH %s = ... is not supported, use direct TiDB TTL syntax", wrappedTTLKey)
		}
	}

	if p.token.Type == TokenTTL {
		rawClause, err := p.parseDirectTTLRawClause()
		if err != nil {
			return nil, err
		}
		stmt.Options[directTTLOptionKey] = &StringLiteral{Value: rawClause}
	}

	return stmt, nil
}

func (p *Parser) parseColumnDefinition() (*ColumnDefinition, bool, error) {
	token := p.token.Pos
	wrapped := false
	if p.token.Type == TokenLeftParen {
		wrapped = true
		p.nextToken()
	}

	name, err := p.parseIdentifierValue()
	if err != nil {
		return nil, false, err
	}

	typ, err := p.parseType()
	if err != nil {
		return nil, false, err
	}

	if wrapped {
		if p.token.Type != TokenRightParen {
			return nil, false, fmt.Errorf("expected ')' after column definition")
		}
		p.nextToken()
	}

	col := &ColumnDefinition{
		Name:  name,
		Type:  typ,
		Token: token,
	}
	inlinePK := false

	for {
		switch p.token.Type {
		case TokenPrimary:
			if col.Primary {
				return nil, false, fmt.Errorf("duplicate PRIMARY KEY in column definition")
			}
			inlinePK = true
			col.Primary = true
			p.nextToken()
			if p.token.Type == TokenKey {
				p.nextToken()
			}
		case TokenStatic:
			if col.Static {
				return nil, false, fmt.Errorf("duplicate STATIC in column definition")
			}
			col.Static = true
			p.nextToken()
		case TokenDefault:
			if col.HasDefault {
				return nil, false, fmt.Errorf("duplicate DEFAULT in column definition")
			}
			p.nextToken()
			expr, err := p.parseBinary(3)
			if err != nil {
				return nil, false, err
			}
			col.HasDefault = true
			col.DefaultExpr = expr
		case TokenOn:
			if col.HasOnUpdate {
				return nil, false, fmt.Errorf("duplicate ON UPDATE in column definition")
			}
			p.nextToken()
			if p.token.Type != TokenUpdate {
				return nil, false, fmt.Errorf("expected UPDATE after ON in column definition")
			}
			p.nextToken()
			expr, err := p.parseBinary(3)
			if err != nil {
				return nil, false, err
			}
			col.HasOnUpdate = true
			col.OnUpdateExpr = expr
		default:
			return col, inlinePK, nil
		}
	}
}

func (p *Parser) parsePrimaryKeyClause() (*PrimaryKey, error) {
	p.nextToken() // Consume PRIMARY
	if p.token.Type == TokenKey {
		p.nextToken()
	}
	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after PRIMARY KEY")
	}
	p.nextToken()

	pk := &PrimaryKey{
		PartitionKeys:     make([]string, 0),
		ClusteringColumns: make([]string, 0),
	}

	if p.token.Type == TokenLeftParen {
		p.nextToken()
		for {
			name, err := p.parseIdentifierValue()
			if err != nil {
				return nil, err
			}
			pk.PartitionKeys = append(pk.PartitionKeys, name)
			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
		if p.token.Type != TokenRightParen {
			return nil, fmt.Errorf("expected ')' after partition key list")
		}
		p.nextToken()
	} else {
		name, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		pk.PartitionKeys = append(pk.PartitionKeys, name)
	}

	for p.token.Type == TokenComma {
		p.nextToken()
		name, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		pk.ClusteringColumns = append(pk.ClusteringColumns, name)
	}

	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after PRIMARY KEY clause")
	}
	p.nextToken()

	return pk, nil
}

func (p *Parser) parseTableOptions(options map[string]interface{}, clustering map[string]string, allowIndexes bool) (bool, error) {
	withIndexes := false
	p.nextToken() // Consume WITH

	for {
		if p.token.Type == TokenClustering {
			p.nextToken()
			if p.token.Type != TokenOrder {
				return withIndexes, fmt.Errorf("expected ORDER after CLUSTERING")
			}
			p.nextToken()
			if p.token.Type != TokenBy {
				return withIndexes, fmt.Errorf("expected BY after ORDER")
			}
			p.nextToken()

			hasParen := false
			if p.token.Type == TokenLeftParen {
				hasParen = true
				p.nextToken()
			}

			for {
				col, err := p.parseIdentifierValue()
				if err != nil {
					return withIndexes, err
				}
				direction := ""
				if p.token.Type == TokenAscending || p.token.Type == TokenDescending {
					direction = strings.ToUpper(p.token.Value)
					p.nextToken()
				}
				clustering[col] = direction

				if p.token.Type != TokenComma {
					break
				}
				p.nextToken()
			}

			if hasParen {
				if p.token.Type != TokenRightParen {
					return withIndexes, fmt.Errorf("expected ')' after CLUSTERING ORDER BY")
				}
				p.nextToken()
			}
		} else {
			key, err := p.parseIdentifierValue()
			if err != nil {
				return withIndexes, err
			}
			if p.token.Type != TokenEqual {
				return withIndexes, fmt.Errorf("expected '=' after option %s", key)
			}
			p.nextToken()
			// Parse option values without consuming AND/OR separators.
			val, err := p.parseBinary(3)
			if err != nil {
				return withIndexes, err
			}
			options[strings.ToLower(key)] = val
		}

		if p.token.Type != TokenAnd {
			break
		}
		if allowIndexes && p.peekToken.Type == TokenIdentifier && strings.EqualFold(p.peekToken.Value, "indexes") {
			p.nextToken() // Consume AND
			p.nextToken() // Consume INDEXES
			withIndexes = true
			break
		}
		p.nextToken()
	}

	return withIndexes, nil
}

const (
	directTTLOptionKey         = "ttl"
	removedDirectTTLOptionKey  = "tidb_ttl_raw"
	ttlEnableDirectOptionKey   = "ttl_enable"
	ttlJobIntervalOptionKey    = "ttl_job_interval"
	removeDirectOperationValue = "remove"
)

func directTTLOptionWrappedKey(options map[string]interface{}) (string, bool) {
	if options == nil {
		return "", false
	}
	if _, ok := options[directTTLOptionKey]; ok {
		return directTTLOptionKey, true
	}
	if _, ok := options[removedDirectTTLOptionKey]; ok {
		return removedDirectTTLOptionKey, true
	}
	return "", false
}

func (p *Parser) parseDirectTTLRawClause() (string, error) {
	parts := make([]string, 0, 8)
	for p.token.Type != TokenEOF && p.token.Type != TokenSemicolon {
		switch p.token.Type {
		case TokenString:
			parts = append(parts, "'"+strings.ReplaceAll(p.token.Value, "'", "''")+"'")
		default:
			parts = append(parts, p.token.Value)
		}
		p.nextToken()
	}
	raw := strings.TrimSpace(strings.Join(parts, " "))
	if raw == "" {
		return "", fmt.Errorf("empty TTL clause")
	}
	return raw, nil
}

func isDirectAlterTTLStart(token Token) bool {
	if token.Type == TokenTTL {
		return true
	}
	if token.Type != TokenIdentifier {
		return false
	}
	switch strings.ToLower(token.Value) {
	case removeDirectOperationValue, ttlEnableDirectOptionKey, ttlJobIntervalOptionKey:
		return true
	default:
		return false
	}
}

func (p *Parser) parseCreateKeyspace(token Position) (*CreateKeyspaceStatement, error) {
	stmt := &CreateKeyspaceStatement{Token: token}
	p.nextToken() // Consume KEYSPACE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	name, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type == TokenWith {
		p.nextToken()
		options, err := p.parseOptionAssignments()
		if err != nil {
			return nil, err
		}
		if rep, ok := options["replication"]; ok {
			if mapLit, ok := rep.(*MapLiteral); ok {
				stmt.Replication = make(map[string]interface{}, len(mapLit.Entries))
				for _, entry := range mapLit.Entries {
					stmt.Replication[entry.Key.String()] = entry.Value
				}
			}
		}
	}

	return stmt, nil
}

func (p *Parser) parseCreateIndex(token Position) (*CreateIndexStatement, error) {
	stmt := &CreateIndexStatement{
		Token:   token,
		Options: make(map[string]interface{}),
	}

	p.nextToken() // Consume INDEX

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	if p.token.Type != TokenOn {
		name, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		stmt.Name = name
		if p.token.Type != TokenOn {
			return nil, fmt.Errorf("expected ON after index name")
		}
	}

	if p.token.Type == TokenOn {
		p.nextToken()
	}

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Table = tableName

	if p.token.Type == TokenKeys {
		p.nextToken()
	}
	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' before index column")
	}
	p.nextToken()
	columns := make([]string, 0, 1)
	for {
		col, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		columns = append(columns, col)
		if p.token.Type == TokenComma {
			p.nextToken()
			continue
		}
		if p.token.Type != TokenRightParen {
			return nil, fmt.Errorf("expected ')' after index column")
		}
		p.nextToken()
		break
	}
	stmt.Columns = columns

	if p.token.Type == TokenUsing {
		p.nextToken()
		if p.token.Type != TokenString && p.token.Type != TokenIdentifier {
			return nil, fmt.Errorf("expected index class after USING")
		}
		stmt.UsingClass = p.token.Value
		p.nextToken()
	}

	if p.token.Type == TokenWith {
		p.nextToken()
		if strings.EqualFold(p.token.Value, "OPTIONS") {
			p.nextToken()
		}
		if p.token.Type != TokenEqual {
			return nil, fmt.Errorf("expected '=' after OPTIONS")
		}
		p.nextToken()
		expr, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Options["options"] = expr
	}

	return stmt, nil
}

func (p *Parser) parseOptionAssignments() (map[string]interface{}, error) {
	options := make(map[string]interface{})
	// Some clients/tools (e.g. cassandra-stress variants) may separate WITH options using
	// commas instead of AND. Be permissive here.
	for p.token.Type == TokenComma {
		p.nextToken()
	}
	for {
		key, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		if p.token.Type != TokenEqual {
			return nil, fmt.Errorf("expected '=' after option %s", key)
		}
		p.nextToken()
		val, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		options[strings.ToLower(key)] = val

		if p.token.Type != TokenAnd && p.token.Type != TokenComma {
			break
		}
		p.nextToken()
		for p.token.Type == TokenComma {
			p.nextToken()
		}
	}
	return options, nil
}

func (p *Parser) parseCreateType(token Position) (*CreateTypeStatement, error) {
	stmt := &CreateTypeStatement{
		Token:  token,
		Fields: make([]*TypeField, 0),
	}
	p.nextToken() // Consume TYPE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	typeName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	if err := validateUserDefinedTypeName(typeName.Name); err != nil {
		return nil, err
	}
	stmt.Name = typeName

	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after type name")
	}
	p.nextToken()

	for {
		fieldToken := p.token.Pos
		fieldName, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		fieldType, err := p.parseType()
		if err != nil {
			return nil, err
		}
		stmt.Fields = append(stmt.Fields, &TypeField{
			Name:  fieldName,
			Type:  fieldType,
			Token: fieldToken,
		})
		if p.token.Type != TokenComma {
			break
		}
		p.nextToken()
	}

	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after type definition")
	}
	p.nextToken()

	return stmt, nil
}

func (p *Parser) parseCreateMaterializedView(token Position) (Statement, error) {
	stmt := &CreateMaterializedViewStatement{
		Token:           token,
		Options:         make(map[string]interface{}),
		ClusteringOrder: make(map[string]string),
	}
	p.nextToken() // Consume MATERIALIZED
	if p.token.Type != TokenView {
		return nil, fmt.Errorf("expected VIEW after MATERIALIZED")
	}
	p.nextToken()

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	viewName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = viewName

	if p.token.Type != TokenAs {
		return nil, fmt.Errorf("expected AS before SELECT in MATERIALIZED VIEW")
	}
	p.nextToken()
	if p.token.Type != TokenSelect {
		return nil, fmt.Errorf("expected SELECT in MATERIALIZED VIEW")
	}
	selectStmt, err := p.parseSelect()
	if err != nil {
		return nil, err
	}
	stmt.Select = selectStmt

	if p.token.Type != TokenPrimary {
		return nil, fmt.Errorf("expected PRIMARY KEY in MATERIALIZED VIEW")
	}
	pk, err := p.parsePrimaryKeyClause()
	if err != nil {
		return nil, err
	}
	stmt.PrimaryKey = pk

	if p.token.Type == TokenWith {
		_, err := p.parseTableOptions(stmt.Options, stmt.ClusteringOrder, false)
		if err != nil {
			return nil, err
		}
	}

	return stmt, nil
}

func (p *Parser) parseCreateTrigger(token Position) (Statement, error) {
	stmt := &CreateTriggerStatement{Token: token}
	p.nextToken() // Consume TRIGGER

	name, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenOn {
		return nil, fmt.Errorf("expected ON after trigger name")
	}
	p.nextToken()

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Table = tableName

	if p.token.Type != TokenUsing {
		return nil, fmt.Errorf("expected USING after trigger table")
	}
	p.nextToken()
	switch p.token.Type {
	case TokenString:
		stmt.Using = p.token.Value
		p.nextToken()
	case TokenIdentifier:
		stmt.Using = p.token.Value
		p.nextToken()
	default:
		return nil, fmt.Errorf("expected trigger class after USING")
	}

	return stmt, nil
}

func (p *Parser) parseCreateFunction(token Position, orReplace bool) (Statement, error) {
	stmt := &CreateFunctionStatement{
		Token:     token,
		OrReplace: orReplace,
		Args:      make([]FunctionArg, 0),
	}
	p.nextToken() // Consume FUNCTION

	if p.token.Type == TokenIf {
		if orReplace {
			return nil, fmt.Errorf("OR REPLACE and IF NOT EXISTS cannot be used together")
		}
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	name, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after function name")
	}
	p.nextToken()
	if p.token.Type != TokenRightParen {
		for {
			argName, err := p.parseIdentifierValue()
			if err != nil {
				return nil, err
			}
			argType, err := p.parseType()
			if err != nil {
				return nil, err
			}
			stmt.Args = append(stmt.Args, FunctionArg{Name: argName, Type: argType})
			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
	}
	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after function arguments")
	}
	p.nextToken()

	switch p.token.Type {
	case TokenReturns:
		p.nextToken()
		if p.token.Type != TokenNull {
			return nil, fmt.Errorf("expected NULL after RETURNS")
		}
		p.nextToken()
		if p.token.Type != TokenOn {
			return nil, fmt.Errorf("expected ON after RETURNS NULL")
		}
		p.nextToken()
		if p.token.Type != TokenNull {
			return nil, fmt.Errorf("expected NULL after ON")
		}
		p.nextToken()
		if p.token.Type != TokenInput {
			return nil, fmt.Errorf("expected INPUT after ON NULL")
		}
		p.nextToken()
		stmt.CalledOnNull = false
	case TokenCalled:
		p.nextToken()
		if p.token.Type != TokenOn {
			return nil, fmt.Errorf("expected ON after CALLED")
		}
		p.nextToken()
		if p.token.Type != TokenNull {
			return nil, fmt.Errorf("expected NULL after ON")
		}
		p.nextToken()
		if p.token.Type != TokenInput {
			return nil, fmt.Errorf("expected INPUT after ON NULL")
		}
		p.nextToken()
		stmt.CalledOnNull = true
	default:
		return nil, fmt.Errorf("expected RETURNS NULL ON NULL INPUT or CALLED ON NULL INPUT")
	}

	if p.token.Type != TokenReturns {
		return nil, fmt.Errorf("expected RETURNS before return type")
	}
	p.nextToken()
	returnType, err := p.parseType()
	if err != nil {
		return nil, err
	}
	stmt.ReturnType = returnType

	if p.token.Type != TokenLanguage {
		return nil, fmt.Errorf("expected LANGUAGE in CREATE FUNCTION")
	}
	p.nextToken()
	switch p.token.Type {
	case TokenIdentifier:
		stmt.Language = p.token.Value
		p.nextToken()
	case TokenString:
		stmt.Language = p.token.Value
		p.nextToken()
	default:
		return nil, fmt.Errorf("expected language after LANGUAGE")
	}

	if p.token.Type != TokenAs {
		return nil, fmt.Errorf("expected AS before function body")
	}
	p.nextToken()
	if p.token.Type != TokenString {
		return nil, fmt.Errorf("expected string literal for function body")
	}
	stmt.Body = p.token.Value
	p.nextToken()

	return stmt, nil
}

func (p *Parser) parseCreateAggregate(token Position, orReplace bool) (Statement, error) {
	stmt := &CreateAggregateStatement{
		Token:     token,
		OrReplace: orReplace,
		ArgTypes:  make([]Type, 0),
	}
	p.nextToken() // Consume AGGREGATE

	if p.token.Type == TokenIf {
		if orReplace {
			return nil, fmt.Errorf("OR REPLACE and IF NOT EXISTS cannot be used together")
		}
		p.nextToken()
		if p.token.Type != TokenNot {
			return nil, fmt.Errorf("expected NOT after IF")
		}
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF NOT")
		}
		stmt.IfNotExists = true
		p.nextToken()
	}

	name, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after aggregate name")
	}
	p.nextToken()
	if p.token.Type != TokenRightParen {
		for {
			argType, err := p.parseType()
			if err != nil {
				return nil, err
			}
			stmt.ArgTypes = append(stmt.ArgTypes, argType)
			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
	}
	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after aggregate arguments")
	}
	p.nextToken()

	if p.token.Type != TokenSFunc {
		return nil, fmt.Errorf("expected SFUNC in CREATE AGGREGATE")
	}
	p.nextToken()
	stateFunc, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.StateFunc = stateFunc

	if p.token.Type != TokenSType {
		return nil, fmt.Errorf("expected STYPE in CREATE AGGREGATE")
	}
	p.nextToken()
	stateType, err := p.parseType()
	if err != nil {
		return nil, err
	}
	stmt.StateType = stateType

	for {
		switch p.token.Type {
		case TokenFinalFunc:
			p.nextToken()
			finalFunc, err := p.parseTableName()
			if err != nil {
				return nil, err
			}
			stmt.FinalFunc = finalFunc
		case TokenInitCond:
			p.nextToken()
			initCond, err := p.parseExpression()
			if err != nil {
				return nil, err
			}
			stmt.InitCond = initCond
		default:
			return stmt, nil
		}
	}
}

func (p *Parser) parseDropTable(token Position) (Statement, error) {
	stmt := &DropTableStatement{Token: token}
	p.nextToken() // Consume TABLE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = tableName
	return stmt, nil
}

func (p *Parser) parseDropIndex(token Position) (Statement, error) {
	stmt := &DropIndexStatement{Token: token}
	p.nextToken() // Consume INDEX

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Name = name
	if p.token.Type == TokenDot {
		p.nextToken()
		part, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		stmt.Name = stmt.Name + "." + part
	}

	return stmt, nil
}

func (p *Parser) parseDropKeyspace(token Position) (Statement, error) {
	stmt := &DropKeyspaceStatement{Token: token}
	p.nextToken() // Consume KEYSPACE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Name = name
	return stmt, nil
}

func (p *Parser) parseDropType(token Position) (Statement, error) {
	stmt := &DropTypeStatement{Token: token}
	p.nextToken() // Consume TYPE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name
	return stmt, nil
}

func (p *Parser) parseDropMaterializedView(token Position) (Statement, error) {
	stmt := &DropMaterializedViewStatement{Token: token}
	p.nextToken() // Consume MATERIALIZED
	if p.token.Type != TokenView {
		return nil, fmt.Errorf("expected VIEW after MATERIALIZED")
	}
	p.nextToken()

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name
	return stmt, nil
}

func (p *Parser) parseDropTrigger(token Position) (Statement, error) {
	stmt := &DropTriggerStatement{Token: token}
	p.nextToken() // Consume TRIGGER

	name, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenOn {
		return nil, fmt.Errorf("expected ON after trigger name")
	}
	p.nextToken()

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Table = tableName
	return stmt, nil
}

func (p *Parser) parseDropFunction(token Position) (Statement, error) {
	stmt := &DropFunctionStatement{Token: token}
	p.nextToken() // Consume FUNCTION

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after function name")
	}
	p.nextToken()
	if p.token.Type != TokenRightParen {
		for {
			argType, err := p.parseType()
			if err != nil {
				return nil, err
			}
			stmt.ArgTypes = append(stmt.ArgTypes, argType)
			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
	}
	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after function arguments")
	}
	p.nextToken()

	return stmt, nil
}

func (p *Parser) parseDropAggregate(token Position) (Statement, error) {
	stmt := &DropAggregateStatement{Token: token}
	p.nextToken() // Consume AGGREGATE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	name, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenLeftParen {
		return nil, fmt.Errorf("expected '(' after aggregate name")
	}
	p.nextToken()
	if p.token.Type != TokenRightParen {
		for {
			argType, err := p.parseType()
			if err != nil {
				return nil, err
			}
			stmt.ArgTypes = append(stmt.ArgTypes, argType)
			if p.token.Type != TokenComma {
				break
			}
			p.nextToken()
		}
	}
	if p.token.Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')' after aggregate arguments")
	}
	p.nextToken()

	return stmt, nil
}

func (p *Parser) parseAlterTable(token Position) (Statement, error) {
	stmt := &AlterTableStatement{
		Token:   token,
		Options: make(map[string]interface{}),
	}
	p.nextToken() // Consume TABLE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	tableName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Table = tableName

	if isDirectAlterTTLStart(p.token) {
		rawClause, err := p.parseDirectTTLRawClause()
		if err != nil {
			return nil, err
		}
		stmt.Operation = "WITH"
		stmt.Options[directTTLOptionKey] = &StringLiteral{Value: rawClause}
		return stmt, nil
	}

	switch p.token.Type {
	case TokenAddKeyword:
		stmt.Operation = "ADD"
		p.nextToken()
		if p.token.Type == TokenIf {
			p.nextToken()
			if p.token.Type != TokenNot {
				return nil, fmt.Errorf("expected NOT after IF in ADD clause")
			}
			p.nextToken()
			if p.token.Type != TokenExists {
				return nil, fmt.Errorf("expected EXISTS after IF NOT in ADD clause")
			}
			stmt.IfNotExists = true
			p.nextToken()
		}
		col, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		typ, err := p.parseType()
		if err != nil {
			return nil, err
		}
		stmt.Column = col
		stmt.Type = typ
	case TokenDrop:
		stmt.Operation = "DROP"
		p.nextToken()
		if p.token.Type == TokenIf {
			p.nextToken()
			if p.token.Type != TokenExists {
				return nil, fmt.Errorf("expected EXISTS after IF in DROP clause")
			}
			stmt.ColumnIfExists = true
			p.nextToken()
		}
		col, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		stmt.Column = col
	case TokenRename:
		stmt.Operation = "RENAME"
		p.nextToken()
		if p.token.Type == TokenIf {
			p.nextToken()
			if p.token.Type != TokenExists {
				return nil, fmt.Errorf("expected EXISTS after IF in RENAME clause")
			}
			stmt.ColumnIfExists = true
			p.nextToken()
		}
		renames := make([]RenamePair, 0)
		for {
			from, err := p.parseIdentifierValue()
			if err != nil {
				return nil, err
			}
			if p.token.Type != TokenTo {
				return nil, fmt.Errorf("expected TO in RENAME clause")
			}
			p.nextToken()
			to, err := p.parseIdentifierValue()
			if err != nil {
				return nil, err
			}
			renames = append(renames, RenamePair{From: from, To: to})
			if p.token.Type != TokenAnd {
				break
			}
			p.nextToken()
		}
		stmt.Renames = renames
	case TokenWith:
		stmt.Operation = "WITH"
		p.nextToken()
		options, err := p.parseOptionAssignments()
		if err != nil {
			return nil, err
		}
		if wrappedTTLKey, ok := directTTLOptionWrappedKey(options); ok {
			return nil, fmt.Errorf("WITH %s = ... is not supported, use direct TiDB TTL syntax", wrappedTTLKey)
		}
		stmt.Options = options
	default:
		return nil, fmt.Errorf("expected ADD, DROP, RENAME, or WITH in ALTER TABLE")
	}

	return stmt, nil
}

func (p *Parser) parseAlterKeyspace(token Position) (Statement, error) {
	stmt := &AlterKeyspaceStatement{
		Token:   token,
		Options: make(map[string]interface{}),
	}
	p.nextToken() // Consume KEYSPACE

	name, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenWith {
		return nil, fmt.Errorf("expected WITH in ALTER KEYSPACE")
	}
	p.nextToken()
	options, err := p.parseOptionAssignments()
	if err != nil {
		return nil, err
	}
	stmt.Options = options
	return stmt, nil
}

func (p *Parser) parseAlterType(token Position) (Statement, error) {
	stmt := &AlterTypeStatement{Token: token}
	p.nextToken() // Consume TYPE

	if p.token.Type == TokenIf {
		p.nextToken()
		if p.token.Type != TokenExists {
			return nil, fmt.Errorf("expected EXISTS after IF")
		}
		stmt.IfExists = true
		p.nextToken()
	}

	typeName, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = typeName

	switch p.token.Type {
	case TokenAddKeyword:
		stmt.Operation = "ADD"
		p.nextToken()
		if p.token.Type == TokenIf {
			p.nextToken()
			if p.token.Type != TokenNot {
				return nil, fmt.Errorf("expected NOT after IF in ADD clause")
			}
			p.nextToken()
			if p.token.Type != TokenExists {
				return nil, fmt.Errorf("expected EXISTS after IF NOT in ADD clause")
			}
			stmt.IfNotExists = true
			p.nextToken()
		}
		fieldName, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		fieldType, err := p.parseType()
		if err != nil {
			return nil, err
		}
		stmt.Field = fieldName
		stmt.Type = fieldType
	case TokenRename:
		stmt.Operation = "RENAME"
		p.nextToken()
		if p.token.Type == TokenIf {
			p.nextToken()
			if p.token.Type != TokenExists {
				return nil, fmt.Errorf("expected EXISTS after IF in RENAME clause")
			}
			stmt.FieldIfExists = true
			p.nextToken()
		}
		renames := make([]RenamePair, 0)
		for {
			from, err := p.parseIdentifierValue()
			if err != nil {
				return nil, err
			}
			if p.token.Type != TokenTo {
				return nil, fmt.Errorf("expected TO in RENAME clause")
			}
			p.nextToken()
			to, err := p.parseIdentifierValue()
			if err != nil {
				return nil, err
			}
			renames = append(renames, RenamePair{From: from, To: to})
			if p.token.Type != TokenAnd {
				break
			}
			p.nextToken()
		}
		stmt.Renames = renames
	default:
		return nil, fmt.Errorf("expected ADD or RENAME in ALTER TYPE")
	}

	return stmt, nil
}

func (p *Parser) parseAlterMaterializedView(token Position) (Statement, error) {
	stmt := &AlterMaterializedViewStatement{
		Token:   token,
		Options: make(map[string]interface{}),
	}
	p.nextToken() // Consume MATERIALIZED
	if p.token.Type != TokenView {
		return nil, fmt.Errorf("expected VIEW after MATERIALIZED")
	}
	p.nextToken()

	name, err := p.parseTableName()
	if err != nil {
		return nil, err
	}
	stmt.Name = name

	if p.token.Type != TokenWith {
		return nil, fmt.Errorf("expected WITH in ALTER MATERIALIZED VIEW")
	}
	p.nextToken()
	options, err := p.parseOptionAssignments()
	if err != nil {
		return nil, err
	}
	stmt.Options = options
	return stmt, nil
}

func (p *Parser) parseUse() (Statement, error) {
	stmt := &UseStatement{Token: p.token.Pos}
	p.nextToken() // Consume USE

	keyspace, err := p.parseIdentifierValue()
	if err != nil {
		return nil, err
	}
	stmt.Keyspace = keyspace
	return stmt, nil
}

func (p *Parser) parseDescribe() (Statement, error) {
	stmt := &DescribeStatement{Token: p.token.Pos}
	p.nextToken() // Consume DESCRIBE or DESC

	switch p.token.Type {
	case TokenKeyspaces:
		stmt.Target = DescribeTargetKeyspaces
		p.nextToken()
		return stmt, nil
	case TokenKeyspace:
		stmt.Target = DescribeTargetKeyspace
		p.nextToken()
		keyspace, err := p.parseIdentifierValue()
		if err != nil {
			return nil, err
		}
		stmt.Keyspace = keyspace
		return stmt, nil
	case TokenTable:
		stmt.Target = DescribeTargetTable
		p.nextToken()
		tableName, err := p.parseTableName()
		if err != nil {
			return nil, err
		}
		stmt.Table = tableName
		return stmt, nil
	case TokenColumnFamily:
		stmt.Target = DescribeTargetTable
		p.nextToken()
		tableName, err := p.parseTableName()
		if err != nil {
			return nil, err
		}
		stmt.Table = tableName
		return stmt, nil
	case TokenIdentifier:
		if p.token.Value == "tables" {
			stmt.Target = DescribeTargetTables
			p.nextToken()
			if err := p.parseDescribeTablesScope(stmt); err != nil {
				return nil, err
			}
			return stmt, nil
		}
		stmt.Target = DescribeTargetTable
		tableName, err := p.parseTableName()
		if err != nil {
			return nil, err
		}
		stmt.Table = tableName
		return stmt, nil
	default:
		return nil, fmt.Errorf("expected KEYSPACES, KEYSPACE, TABLES, TABLE, COLUMNFAMILY, or table name after DESCRIBE, got %s", p.token)
	}
}

func (p *Parser) parseDescribeTablesScope(stmt *DescribeStatement) error {
	if stmt == nil {
		return fmt.Errorf("describe statement is required")
	}
	switch p.token.Type {
	case TokenIn, TokenFrom:
		p.nextToken()
		if p.token.Type == TokenKeyspace {
			p.nextToken()
		}
		keyspace, err := p.parseIdentifierValue()
		if err != nil {
			return err
		}
		stmt.Keyspace = keyspace
	}
	return nil
}

func (p *Parser) parseTableName() (*TableName, error) {
	// Accept identifier or certain keywords that can be used as table names
	if p.token.Type != TokenIdentifier && !isKeywordThatCanBeIdentifier(p.token.Type) {
		return nil, fmt.Errorf("expected identifier, got %s", p.token)
	}

	firstIdent := p.token.Value
	firstPos := p.token.Pos
	p.nextToken()

	// Check for qualified name (keyspace.table)
	if p.token.Type == TokenDot {
		p.nextToken() // Consume dot
		if p.token.Type != TokenIdentifier && !isKeywordThatCanBeIdentifier(p.token.Type) {
			return nil, fmt.Errorf("expected identifier after '.', got %s", p.token)
		}
		tableName := &TableName{
			Schema: firstIdent,
			Name:   p.token.Value,
			Token:  firstPos,
		}
		p.nextToken()
		return tableName, nil
	}

	// Simple table name
	return &TableName{Name: firstIdent, Token: firstPos}, nil
}

func (p *Parser) parseIdentifierValue() (string, error) {
	if p.token.Type != TokenIdentifier && !isKeywordThatCanBeIdentifier(p.token.Type) {
		return "", fmt.Errorf("expected identifier, got %s", p.token)
	}
	val := p.token.Value
	p.nextToken()
	return val, nil
}

func (p *Parser) parseUserName() (string, error) {
	if p.token.Type == TokenString {
		val := p.token.Value
		p.nextToken()
		return val, nil
	}
	return p.parseIdentifierValue()
}

func (p *Parser) parsePasswordLiteral() (string, error) {
	if p.token.Type != TokenString {
		return "", fmt.Errorf("expected password string literal, got %s", p.token)
	}
	val := p.token.Value
	p.nextToken()
	return val, nil
}

func assignmentColumnName(expr Expression) string {
	switch e := expr.(type) {
	case *ColumnExpr:
		if e.Table != "" {
			return e.Table + "." + e.Name
		}
		return e.Name
	default:
		return expr.String()
	}
}

func assignmentBaseColumnName(expr Expression) string {
	switch e := expr.(type) {
	case *ColumnExpr:
		return assignmentColumnName(e)
	case *CollectionAccessExpr:
		if col, ok := e.Target.(*ColumnExpr); ok {
			return assignmentColumnName(col)
		}
	}
	return assignmentColumnName(expr)
}

func (p *Parser) parseUsingConsistency() error {
	p.nextToken() // Consume USING
	if !strings.EqualFold(p.token.Value, "CONSISTENCY") {
		return fmt.Errorf("expected CONSISTENCY after USING")
	}
	p.nextToken()
	if p.token.Type == TokenIdentifier || isKeywordThatCanBeIdentifier(p.token.Type) || isConsistencyToken(p.token.Type) {
		p.nextToken()
		return nil
	}
	return fmt.Errorf("expected consistency level after USING CONSISTENCY")
}

func (p *Parser) parseUsingClause() (Expression, Expression, error) {
	var ttl Expression
	var ts Expression

	p.nextToken() // Consume USING
	for {
		switch p.token.Type {
		case TokenTTL:
			p.nextToken()
			expr, err := p.parseBinary(3)
			if err != nil {
				return nil, nil, err
			}
			ttl = expr
		case TokenTimestamp, TokenTimestampType:
			p.nextToken()
			expr, err := p.parseBinary(3)
			if err != nil {
				return nil, nil, err
			}
			ts = expr
		default:
			return nil, nil, fmt.Errorf("expected TTL or TIMESTAMP in USING clause")
		}

		if p.token.Type != TokenAnd {
			break
		}
		p.nextToken()
	}

	return ttl, ts, nil
}

func isConsistencyToken(t TokenType) bool {
	switch t {
	case TokenConsistencyOne, TokenConsistencyTwo, TokenConsistencyThree,
		TokenConsistencyQuorum, TokenConsistencyAll, TokenConsistencyLocalQuorum,
		TokenConsistencyEachQuorum, TokenConsistencyLocalOne, TokenConsistencySerial,
		TokenConsistencyLocalSerial:
		return true
	default:
		return false
	}
}

// isKeywordThatCanBeIdentifier returns true if the token type can be used as an identifier
// in table/column names (keywords like keyspace, table, etc.)
func isKeywordThatCanBeIdentifier(t TokenType) bool {
	switch t {
	case TokenAggregate, TokenAll, TokenAs, TokenAscii, TokenBigint, TokenBlobType,
		TokenBoolean, TokenCalled, TokenCast, TokenClustering, TokenCompact,
		TokenContains, TokenCount, TokenCounter, TokenCustom, TokenDate, TokenDecimal,
		TokenDistinct, TokenDouble, TokenDuration, TokenExists, TokenFiltering,
		TokenFinalFunc, TokenFloatType, TokenFrozen, TokenFunction, TokenFunctions,
		TokenGroup, TokenInet, TokenInitCond, TokenInput, TokenInt, TokenJSON,
		TokenKey, TokenKeys, TokenKeyspaces, TokenLanguage, TokenLike, TokenList,
		TokenLogin, TokenMap, TokenMasked, TokenNoLogin, TokenNoSuperuser,
		TokenOptions, TokenPartition, TokenPassword, TokenPer, TokenPermission,
		TokenPermissions, TokenReturns, TokenRole, TokenRoles, TokenSelectMasked,
		TokenSFunc, TokenSmallint, TokenStatic, TokenStorage, TokenSType,
		TokenSuperuser, TokenText, TokenTime, TokenTimestampType, TokenTimeUUID,
		TokenTinyint, TokenTrigger, TokenTTL, TokenTuple, TokenTypeKeyword,
		TokenUnmask, TokenUser, TokenUsers, TokenUUIDType, TokenValues, TokenVector,
		TokenVarchar, TokenVarint, TokenWriteTime:
		return true
	}
	return false
}

func validateUserDefinedTypeName(name string) error {
	lower := strings.ToLower(name)
	if isBuiltinTypeName(lower) || isReservedTypeName(lower) {
		return fmt.Errorf("type name %q is reserved", name)
	}
	return nil
}

func isBuiltinTypeName(name string) bool {
	switch name {
	case "ascii", "bigint", "blob", "boolean", "counter", "date", "decimal",
		"double", "float", "inet", "int", "smallint", "text", "time", "timestamp",
		"timeuuid", "tinyint", "uuid", "varchar", "varint", "list", "set", "map",
		"tuple", "frozen", "duration":
		return true
	default:
		return false
	}
}

func isReservedTypeName(name string) bool {
	switch name {
	case "bitstring", "byte", "complex", "date", "enum", "interval", "macaddr":
		return true
	default:
		return false
	}
}

func (p *Parser) parseOrderBy() ([]*OrderByClause, error) {
	// Consume ORDER
	p.nextToken()
	if p.token.Type != TokenBy {
		return nil, fmt.Errorf("expected BY after ORDER")
	}
	p.nextToken()

	clauses := make([]*OrderByClause, 0)
	for {
		expr, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		direction := ""
		if p.token.Type == TokenAscending || p.token.Type == TokenDescending {
			direction = strings.ToUpper(p.token.Value)
			p.nextToken()
		}
		clauses = append(clauses, &OrderByClause{
			Token:     expr.Position(),
			Column:    expr.String(),
			Direction: direction,
		})

		if p.token.Type != TokenComma {
			break
		}
		p.nextToken()
	}

	return clauses, nil
}
