Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,18 @@ func (s *ShowCreateQuotaQuery) Pos() token.Position { return s.Position }
func (s *ShowCreateQuotaQuery) End() token.Position { return s.Position }
func (s *ShowCreateQuotaQuery) statementNode() {}

// CreateIndexQuery represents a CREATE INDEX statement.
type CreateIndexQuery struct {
Position token.Position `json:"-"`
IndexName string `json:"index_name"`
Table string `json:"table"`
Columns []Expression `json:"columns,omitempty"`
}

func (c *CreateIndexQuery) Pos() token.Position { return c.Position }
func (c *CreateIndexQuery) End() token.Position { return c.Position }
func (c *CreateIndexQuery) statementNode() {}

// -----------------------------------------------------------------------------
// Expressions

Expand Down
2 changes: 2 additions & 0 deletions internal/explain/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ func Node(sb *strings.Builder, node interface{}, depth int) {
explainTruncateQuery(sb, n, indent)
case *ast.CheckQuery:
explainCheckQuery(sb, n, indent)
case *ast.CreateIndexQuery:
explainCreateIndexQuery(sb, n, indent, depth)

// Types
case *ast.DataType:
Expand Down
35 changes: 35 additions & 0 deletions internal/explain/statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,38 @@ func explainCheckQuery(sb *strings.Builder, n *ast.CheckQuery, indent string) {
fmt.Fprintf(sb, "%s Set\n", indent)
}
}

func explainCreateIndexQuery(sb *strings.Builder, n *ast.CreateIndexQuery, indent string, depth int) {
if n == nil {
fmt.Fprintf(sb, "%s*ast.CreateIndexQuery\n", indent)
return
}

// CreateIndexQuery with two spaces before table name, always 3 children
fmt.Fprintf(sb, "%sCreateIndexQuery %s (children %d)\n", indent, n.Table, 3)

// Child 1: Index name
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.IndexName)

// Child 2: Index wrapper with columns
fmt.Fprintf(sb, "%s Index (children 1)\n", indent)

// For single column, output as Identifier
// For multiple columns or if there are any special cases, output as Function tuple
if len(n.Columns) == 1 {
if ident, ok := n.Columns[0].(*ast.Identifier); ok {
fmt.Fprintf(sb, "%s Identifier %s\n", indent, ident.Name())
} else {
// Non-identifier expression - wrap in tuple
fmt.Fprintf(sb, "%s Function tuple (children 1)\n", indent)
fmt.Fprintf(sb, "%s ExpressionList\n", indent)
}
} else {
// Multiple columns or empty - always Function tuple with ExpressionList
fmt.Fprintf(sb, "%s Function tuple (children 1)\n", indent)
fmt.Fprintf(sb, "%s ExpressionList\n", indent)
}

// Child 3: Table name
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table)
}
82 changes: 78 additions & 4 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -1247,12 +1247,25 @@ func (p *Parser) parseInsert() *ast.InsertQuery {
return ins
}

func (p *Parser) parseCreate() *ast.CreateQuery {
create := &ast.CreateQuery{
Position: p.current.Pos,
func (p *Parser) parseCreate() ast.Statement {
pos := p.current.Pos
p.nextToken() // skip CREATE

// Handle CREATE [UNIQUE] INDEX
if p.currentIs(token.INDEX) {
return p.parseCreateIndex(pos)
}
// Handle CREATE UNIQUE INDEX
if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "UNIQUE" {
p.nextToken() // skip UNIQUE
if p.currentIs(token.INDEX) {
return p.parseCreateIndex(pos)
}
}

p.nextToken() // skip CREATE
create := &ast.CreateQuery{
Position: pos,
}

// Handle OR REPLACE
if p.currentIs(token.OR) {
Expand Down Expand Up @@ -1328,6 +1341,67 @@ func (p *Parser) parseCreate() *ast.CreateQuery {
return create
}

func (p *Parser) parseCreateIndex(pos token.Position) *ast.CreateIndexQuery {
p.nextToken() // skip INDEX

query := &ast.CreateIndexQuery{
Position: pos,
}

// Parse index name
query.IndexName = p.parseIdentifierName()

// Skip IF NOT EXISTS if present
if p.currentIs(token.IF) {
p.nextToken() // IF
if p.currentIs(token.NOT) {
p.nextToken() // NOT
}
if p.currentIs(token.EXISTS) {
p.nextToken() // EXISTS
}
}

// Expect ON
if p.currentIs(token.ON) {
p.nextToken()
}

// Parse table name
query.Table = p.parseIdentifierName()
if p.currentIs(token.DOT) {
p.nextToken()
query.Table = p.parseIdentifierName()
}

// Parse column list in parentheses
if p.currentIs(token.LPAREN) {
p.nextToken() // skip (

for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) {
col := p.parseExpression(0)
query.Columns = append(query.Columns, col)

// Skip ASC/DESC modifiers
if p.currentIs(token.ASC) || p.currentIs(token.DESC) {
p.nextToken()
}

if p.currentIs(token.COMMA) {
p.nextToken()
} else {
break
}
}

if p.currentIs(token.RPAREN) {
p.nextToken() // skip )
}
}

return query
}

func (p *Parser) parseCreateTable(create *ast.CreateQuery) {
// Handle IF NOT EXISTS
if p.currentIs(token.IF) {
Expand Down
Loading