Cleanup parser statements, add delete and insert statement, add TASKS.md for tracking tasks
This commit is contained in:
219
sql/parseCreateStatement.go
Normal file
219
sql/parseCreateStatement.go
Normal file
@@ -0,0 +1,219 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
)
|
||||
|
||||
func (p *Parser) parseCreateTable() (*CreateTableStatement, error) {
|
||||
if !p.expectNext(TABLE) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
tok, ok := p.expectOne(QUOTE, SINGLE_QUOTE, BACKQUOTE, IDENT, IF)
|
||||
if !ok {
|
||||
return nil, p.unexpectedToken(IDENT, IF)
|
||||
}
|
||||
|
||||
switch tok {
|
||||
case IF:
|
||||
if !p.expectSequence(NOT, EXISTS) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
fallthrough
|
||||
case QUOTE, SINGLE_QUOTE, BACKQUOTE:
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
}
|
||||
_, _, lit := p.rescan()
|
||||
|
||||
stmt := CreateTableStatement{
|
||||
TableName: lit,
|
||||
Columns: make([]Column, 0),
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(LPAREN) {
|
||||
return nil, p.unexpectedToken(LPAREN)
|
||||
}
|
||||
|
||||
for {
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
_, tok, _ := p.scan()
|
||||
|
||||
switch tok {
|
||||
case RPAREN:
|
||||
if !p.expectNext(SEMI) {
|
||||
return nil, p.unexpectedToken(SEMI)
|
||||
}
|
||||
return &stmt, nil
|
||||
|
||||
case IDENT:
|
||||
column, err := p.parseColumn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Columns = append(stmt.Columns, column)
|
||||
|
||||
// TODO: HANDLE AND SAVE CONSTRAINTS
|
||||
case CONSTRAINT:
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
// _, _, constraintName := p.rescan()
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
case FOREIGN:
|
||||
if !p.expectSequence(KEY, LPAREN) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
_, _, columnName := p.rescan()
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectSequence(RPAREN, REFERENCES) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
ref, err := p.references()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
column := slices.IndexFunc(stmt.Columns, func(c Column) bool {
|
||||
return c.Name == columnName
|
||||
})
|
||||
|
||||
stmt.Columns[column].Extra = append(stmt.Columns[column].Extra, ref)
|
||||
|
||||
case PRIMARY:
|
||||
if !p.expectSequence(KEY, LPAREN) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
primaryKeyNames := make([]string, 0)
|
||||
_, _, columnName := p.rescan()
|
||||
primaryKeyNames = append(primaryKeyNames, columnName)
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
for {
|
||||
tok, ok := p.expectOne(RPAREN, COMMA)
|
||||
if !ok {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
if tok == RPAREN {
|
||||
break
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
_, _, columnName := p.rescan()
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
primaryKeyNames = append(primaryKeyNames, columnName)
|
||||
}
|
||||
|
||||
for _, pkName := range primaryKeyNames {
|
||||
column := slices.IndexFunc(stmt.Columns, func(c Column) bool {
|
||||
return c.Name == pkName
|
||||
})
|
||||
stmt.Columns[column].Extra = append(stmt.Columns[column].Extra, "PRIMARY_KEY")
|
||||
}
|
||||
|
||||
case COMMA:
|
||||
continue
|
||||
|
||||
default:
|
||||
return nil, p.unexpectedToken(IDENT, RPAREN, FOREIGN, COMMA)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parseColumn() (Column, error) {
|
||||
_, _, lit := p.rescan()
|
||||
column := Column{Name: lit, Extra: make([]string, 0)}
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if _, ok := p.expectOne(TEXT, INTEGER, REAL, BLOB, NUMERIC); !ok {
|
||||
return Column{}, p.unexpectedToken(TEXT, INTEGER, REAL, BLOB, NUMERIC)
|
||||
}
|
||||
_, _, column.Type = p.rescan()
|
||||
|
||||
for {
|
||||
_, tok, lit := p.scan()
|
||||
switch tok {
|
||||
case COMMA:
|
||||
return column, nil
|
||||
case RPAREN:
|
||||
p.unscan()
|
||||
return column, nil
|
||||
|
||||
case PRIMARY:
|
||||
fallthrough
|
||||
case NOT:
|
||||
if _, ok := p.expectOne(NULL, KEY); !ok {
|
||||
return Column{}, p.unexpectedToken(NULL, KEY)
|
||||
}
|
||||
_, _, rlit := p.rescan()
|
||||
column.Extra = append(column.Extra, fmt.Sprintf("%v_%v", lit, rlit))
|
||||
|
||||
case REFERENCES:
|
||||
ref, err := p.references()
|
||||
if err != nil {
|
||||
return Column{}, err
|
||||
}
|
||||
column.Extra = append(column.Extra, ref)
|
||||
|
||||
case AUTOINCREMENT:
|
||||
column.Extra = append(column.Extra, "AUTOINCREMENT")
|
||||
|
||||
default:
|
||||
return Column{}, p.unexpectedToken(COMMA, RPAREN, PRIMARY, NOT, REFERENCES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) references() (string, error) {
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(IDENT) {
|
||||
return "", p.unexpectedToken(IDENT)
|
||||
}
|
||||
_, _, referenceTableName := p.rescan()
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(LPAREN) {
|
||||
return "", p.unexpectedToken()
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(IDENT) {
|
||||
return "", p.unexpectedToken()
|
||||
}
|
||||
_, _, referenceColumnName := p.rescan()
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(RPAREN) {
|
||||
return "", p.unexpectedToken(RPAREN)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("ref %v.%v", referenceTableName, referenceColumnName), nil
|
||||
}
|
||||
Reference in New Issue
Block a user