mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
increase parser test coverage significantly
We now test the tuple-assignment at all, although it's
perhaps confusing because we expect a ()-list of columns
to go with a {}-list of values. We also test a lot more
errors and some more successes, and additional literal types
in mustParseLiteral.
This commit is contained in:
parent
d4fb807664
commit
3f7ae75e17
4 changed files with 103 additions and 9 deletions
|
|
@ -299,6 +299,8 @@ func CloneExpr(expr Expr) Expr {
|
|||
return expr.Clone()
|
||||
case *StringLit:
|
||||
return expr.Clone()
|
||||
case *TupleLiteralExpr:
|
||||
return expr.Clone()
|
||||
case *UnaryExpr:
|
||||
return expr.Clone()
|
||||
case *Variable:
|
||||
|
|
@ -1795,6 +1797,7 @@ func (t *Type) String() string {
|
|||
type StringLit struct {
|
||||
ValuePos Pos // literal position
|
||||
Value string // literal value (without quotes)
|
||||
IsBlob bool // are we a blob?
|
||||
}
|
||||
|
||||
func (expr *StringLit) IsLiteral() bool { return true }
|
||||
|
|
@ -1831,7 +1834,11 @@ func (lit *StringLit) Clone() *StringLit {
|
|||
|
||||
// String returns the string representation of the expression.
|
||||
func (lit *StringLit) String() string {
|
||||
return `'` + strings.Replace(lit.Value, `'`, `''`, -1) + `'`
|
||||
if lit.IsBlob {
|
||||
return `x'` + strings.Replace(lit.Value, `'`, `''`, -1) + `'`
|
||||
} else {
|
||||
return `'` + strings.Replace(lit.Value, `'`, `''`, -1) + `'`
|
||||
}
|
||||
}
|
||||
|
||||
type IntegerLit struct {
|
||||
|
|
|
|||
|
|
@ -414,6 +414,9 @@ func (p *Parser) parseCreateDatabaseStatement(createPos Pos) (_ *CreateDatabaseS
|
|||
if stmt.Options, err = p.parseDatabaseOptions(); err != nil {
|
||||
return &stmt, err
|
||||
}
|
||||
if len(stmt.Options) == 0 {
|
||||
return &stmt, p.errorExpected(stmt.With, p.peek(), "at least one option after WITH")
|
||||
}
|
||||
}
|
||||
|
||||
return &stmt, nil
|
||||
|
|
@ -443,19 +446,17 @@ func (p *Parser) parseDatabaseOptions() (_ []DatabaseOption, err error) {
|
|||
func (p *Parser) parseDatabaseOption() (_ DatabaseOption, err error) {
|
||||
assert(isDatabaseOptionStartToken(p.peek()))
|
||||
|
||||
var optionPos Pos
|
||||
|
||||
// Parse database options.
|
||||
switch p.peek() {
|
||||
case UNITS:
|
||||
return p.parseUnitsOption(optionPos)
|
||||
return p.parseUnitsOption()
|
||||
default:
|
||||
assert(p.peek() == COMMENT)
|
||||
return p.parseCommentOption(optionPos)
|
||||
return p.parseCommentOption()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parseUnitsOption(optionPos Pos) (_ *UnitsOption, err error) {
|
||||
func (p *Parser) parseUnitsOption() (_ *UnitsOption, err error) {
|
||||
assert(p.peek() == UNITS)
|
||||
|
||||
var opt UnitsOption
|
||||
|
|
@ -562,11 +563,11 @@ func (p *Parser) parseTableOption() (_ TableOption, err error) {
|
|||
return p.parseKeyPartitionsOption(optionPos)
|
||||
default:
|
||||
assert(p.peek() == COMMENT)
|
||||
return p.parseCommentOption(optionPos)
|
||||
return p.parseCommentOption()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parseCommentOption(optionPos Pos) (_ *CommentOption, err error) {
|
||||
func (p *Parser) parseCommentOption() (_ *CommentOption, err error) {
|
||||
assert(p.peek() == COMMENT)
|
||||
|
||||
var opt CommentOption
|
||||
|
|
@ -2731,7 +2732,7 @@ func (p *Parser) mustParseLiteral() Expr {
|
|||
case TRUE, FALSE:
|
||||
return &BoolLit{ValuePos: pos, Value: tok == TRUE}
|
||||
case BLOB:
|
||||
return &StringLit{ValuePos: pos, Value: lit}
|
||||
return &StringLit{ValuePos: pos, IsBlob: true, Value: lit}
|
||||
default:
|
||||
assert(tok == NULL)
|
||||
return &NullLit{ValuePos: pos}
|
||||
|
|
|
|||
|
|
@ -460,6 +460,11 @@ func TestParser_ParseAlterStatement(t *testing.T) {
|
|||
AssertParseStatementError(t, `ALTER TABLE tbl ADD`, `1:19: expected COLUMN keyword or column name, found 'EOF'`)
|
||||
AssertParseStatementError(t, `ALTER TABLE tbl ADD COLUMN`, `1:26: expected column name, found 'EOF'`)
|
||||
})
|
||||
t.Run("AlterView", func(t *testing.T) {
|
||||
AssertParseStatementError(t, `ALTER VIEW`, `1:10: expected view name, found 'EOF'`)
|
||||
AssertParseStatementError(t, `ALTER VIEW vw 23`, `1:15: expected AS, found 23`)
|
||||
AssertParseStatementError(t, `ALTER VIEW vw AS 23`, `1:18: expected SELECT, found 23`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestParser_ParseFunctionStatement(t *testing.T) {
|
||||
|
|
@ -900,11 +905,63 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
},
|
||||
},
|
||||
})
|
||||
AssertParseStatement(t, `CREATE DATABASE db WITH COMMENT 'foo' COMMENT 23.5 COMMENT true COMMENT x'foo' COMMENT NULL`, &parser.CreateDatabaseStatement{
|
||||
Create: pos(0),
|
||||
Database: pos(7),
|
||||
Name: &parser.Ident{
|
||||
Name: "db",
|
||||
NamePos: pos(16),
|
||||
},
|
||||
With: pos(19),
|
||||
Options: []parser.DatabaseOption{
|
||||
&parser.CommentOption{
|
||||
Comment: pos(24),
|
||||
Expr: &parser.StringLit{
|
||||
ValuePos: pos(32),
|
||||
Value: "foo",
|
||||
},
|
||||
},
|
||||
&parser.CommentOption{
|
||||
Comment: pos(38),
|
||||
Expr: &parser.FloatLit{
|
||||
ValuePos: pos(46),
|
||||
Value: "23.5",
|
||||
},
|
||||
},
|
||||
&parser.CommentOption{
|
||||
Comment: pos(51),
|
||||
Expr: &parser.BoolLit{
|
||||
ValuePos: pos(59),
|
||||
Value: true,
|
||||
},
|
||||
},
|
||||
&parser.CommentOption{
|
||||
Comment: pos(64),
|
||||
Expr: &parser.StringLit{
|
||||
IsBlob: true,
|
||||
ValuePos: pos(72),
|
||||
Value: "foo",
|
||||
},
|
||||
},
|
||||
&parser.CommentOption{
|
||||
Comment: pos(79),
|
||||
Expr: &parser.NullLit{
|
||||
ValuePos: pos(87),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
AssertParseStatementError(t, `CREATE`, `1:1: expected DATABASE, TABLE, VIEW or FUNCTION`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE`, `1:15: expected database name, found 'EOF'`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE IF`, `1:18: expected NOT, found 'EOF'`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE IF NOT`, `1:22: expected EXISTS, found 'EOF'`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE db (`, `1:20: expected semicolon or EOF, found '('`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE db extra`, `1:20: expected semicolon or EOF, found extra`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE db WITH`, `1:20: expected at least one option after WITH`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE db WITH UNITS`, `1:29: expected literal, found 'EOF'`)
|
||||
AssertParseStatementError(t, `CREATE DATABASE db WITH COMMENT`, `1:31: expected literal, found 'EOF'`)
|
||||
|
||||
})
|
||||
|
||||
t.Run("CreateTable", func(t *testing.T) {
|
||||
|
|
@ -3769,6 +3826,29 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
},
|
||||
},
|
||||
})
|
||||
AssertParseStatement(t, `UPDATE tbl SET (x, y) = {1, 2}`, &parser.UpdateStatement{
|
||||
Update: pos(0),
|
||||
Table: &parser.QualifiedTableName{
|
||||
Name: &parser.Ident{NamePos: pos(7), Name: "tbl"},
|
||||
},
|
||||
Set: pos(11),
|
||||
Assignments: []*parser.Assignment{
|
||||
{
|
||||
Lparen: pos(15),
|
||||
Rparen: pos(20),
|
||||
Columns: []*parser.Ident{{NamePos: pos(16), Name: "x"}, {NamePos: pos(19), Name: "y"}},
|
||||
Eq: pos(22),
|
||||
Expr: &parser.TupleLiteralExpr{
|
||||
Lbrace: pos(24),
|
||||
Rbrace: pos(29),
|
||||
Members: []parser.Expr{
|
||||
&parser.IntegerLit{ValuePos: pos(25), Value: "1"},
|
||||
&parser.IntegerLit{ValuePos: pos(28), Value: "2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
AssertParseStatement(t, `UPDATE tbl SET x = 1 WHERE y = 2`, &parser.UpdateStatement{
|
||||
Update: pos(0),
|
||||
Table: &parser.QualifiedTableName{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ func TestScanner_Scan(t *testing.T) {
|
|||
t.Run("NoEndQuote", func(t *testing.T) {
|
||||
AssertScan(t, `'unfinished`, parser.ILLEGAL, `'unfinished`)
|
||||
})
|
||||
t.Run("NoEndQuoteNL", func(t *testing.T) {
|
||||
AssertScan(t, "'unfinished\n", parser.UNTERMSTRING, `'unfinished`)
|
||||
})
|
||||
})
|
||||
t.Run("BLOB", func(t *testing.T) {
|
||||
t.Run("LowerX", func(t *testing.T) {
|
||||
|
|
@ -52,6 +55,9 @@ func TestScanner_Scan(t *testing.T) {
|
|||
t.Run("NoEndQuote", func(t *testing.T) {
|
||||
AssertScan(t, `x'0123`, parser.ILLEGAL, `x'0123`)
|
||||
})
|
||||
t.Run("QuotedQuote", func(t *testing.T) {
|
||||
AssertScan(t, `x'01''23'`, parser.BLOB, `01'23`)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("INTEGER", func(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue