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
63 changes: 63 additions & 0 deletions embedded/sql/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3202,6 +3202,69 @@ func TestQuery(t *testing.T) {
})
}

func TestExtractFromTimestamp(t *testing.T) {
st, err := store.Open(t.TempDir(), store.DefaultOptions().WithMultiIndexing(true))
require.NoError(t, err)
defer closeStore(t, st)

engine, err := NewEngine(st, DefaultOptions().WithPrefix(sqlPrefix))
require.NoError(t, err)

t.Run("extract from constant expressions", func(t *testing.T) {
assertQueryShouldProduceResults(
t,
engine,
`SELECT
EXTRACT(YEAR FROM '2020-01-15'),
EXTRACT(MONTH FROM '2020-01-15'),
EXTRACT(DAY FROM '2020-01-15'::TIMESTAMP),
EXTRACT(HOUR FROM '2020-01-15 12:30:24'),
EXTRACT(MINUTE FROM '2020-01-15 12:30:24'),
EXTRACT(SECOND FROM '2020-01-15 12:30:24'::TIMESTAMP)
`,
`SELECT * FROM (
VALUES (2020, 01, 15, 12, 30, 24)
)`,
)
})

t.Run("extract from table", func(t *testing.T) {
_, _, err := engine.Exec(
context.Background(),
nil,
`CREATE TABLE events(ts TIMESTAMP PRIMARY KEY);
INSERT INTO events(ts) VALUES
('2021-07-04 14:45:30'::TIMESTAMP),
('1999-12-31 23:59:59'::TIMESTAMP);
`,
nil,
)
require.NoError(t, err)

assertQueryShouldProduceResults(
t,
engine,
`SELECT
EXTRACT(YEAR FROM ts),
EXTRACT(MONTH FROM ts),
EXTRACT(DAY FROM ts),
EXTRACT(HOUR FROM ts),
EXTRACT(MINUTE FROM ts),
EXTRACT(SECOND FROM ts)
FROM events
ORDER BY ts
`,
`SELECT * FROM (
VALUES
(1999, 12, 31, 23, 59, 59),
(2021, 07, 04, 14, 45, 30)
)`,
)
})

}

func TestJSON(t *testing.T) {
opts := store.DefaultOptions().WithMultiIndexing(true)
opts.WithIndexOptions(opts.IndexOpts.WithMaxActiveSnapshots(1))
Expand Down
82 changes: 56 additions & 26 deletions embedded/sql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (

//go:generate go run golang.org/x/tools/cmd/goyacc -l -o sql_parser.go sql_grammar.y

var reservedWords = map[string]int{
var keywords = map[string]int{
"CREATE": CREATE,
"DROP": DROP,
"USE": USE,
Expand Down Expand Up @@ -118,6 +118,21 @@ var reservedWords = map[string]int{
"THEN": THEN,
"ELSE": ELSE,
"END": END,
"EXTRACT": EXTRACT,
"INTEGER": INTEGER_TYPE,
"BOOLEAN": BOOLEAN_TYPE,
"VARCHAR": VARCHAR_TYPE,
"TIMESTAMP": TIMESTAMP_TYPE,
"FLOAT": FLOAT_TYPE,
"BLOB": BLOB_TYPE,
"UUID": UUID_TYPE,
"JSON": JSON_TYPE,
"YEAR": YEAR,
"MONTH": MONTH,
"DAY": DAY,
"HOUR": HOUR,
"MINUTE": MINUTE,
"SECOND": SECOND,
}

var joinTypes = map[string]JoinType{
Expand All @@ -126,17 +141,6 @@ var joinTypes = map[string]JoinType{
"RIGHT": RightJoin,
}

var types = map[string]SQLValueType{
"INTEGER": IntegerType,
"BOOLEAN": BooleanType,
"VARCHAR": VarcharType,
"UUID": UUIDType,
"BLOB": BLOBType,
"TIMESTAMP": TimestampType,
"FLOAT": Float64Type,
"JSON": JSONType,
}

var aggregateFns = map[string]AggregateFn{
"COUNT": COUNT,
"SUM": SUM,
Expand Down Expand Up @@ -321,7 +325,7 @@ func (l *lexer) Lex(lval *yySymType) int {
}

lval.blob = val
return BLOB
return BLOB_LIT
}

if isLetter(ch) {
Expand All @@ -334,16 +338,10 @@ func (l *lexer) Lex(lval *yySymType) int {
w := fmt.Sprintf("%c%s", ch, tail)
tid := strings.ToUpper(w)

sqlType, ok := types[tid]
if ok {
lval.sqlType = sqlType
return TYPE
}

val, ok := boolValues[tid]
if ok {
lval.boolean = val
return BOOLEAN
return BOOLEAN_LIT
}

afn, ok := aggregateFns[tid]
Expand All @@ -358,13 +356,13 @@ func (l *lexer) Lex(lval *yySymType) int {
return JOINTYPE
}

tkn, ok := reservedWords[tid]
tkn, ok := keywords[tid]
if ok {
lval.keyword = w
return tkn
}

lval.id = strings.ToLower(w)

return IDENTIFIER
}

Expand Down Expand Up @@ -409,7 +407,7 @@ func (l *lexer) Lex(lval *yySymType) int {
}

lval.float = val
return FLOAT
return FLOAT_LIT
}

val, err := strconv.ParseUint(fmt.Sprintf("%c%s", ch, tail), 10, 64)
Expand All @@ -419,7 +417,7 @@ func (l *lexer) Lex(lval *yySymType) int {
}

lval.integer = val
return INTEGER
return INTEGER_LIT
}

if isComparison(ch) {
Expand Down Expand Up @@ -452,7 +450,7 @@ func (l *lexer) Lex(lval *yySymType) int {
}

lval.str = tail
return VARCHAR
return VARCHAR_LIT
}

if ch == ':' {
Expand Down Expand Up @@ -566,7 +564,7 @@ func (l *lexer) Lex(lval *yySymType) int {
return ERROR
}
lval.float = val
return FLOAT
return FLOAT_LIT
}
return DOT
}
Expand Down Expand Up @@ -681,3 +679,35 @@ func isDoubleQuote(ch byte) bool {
func isDot(ch byte) bool {
return ch == '.'
}

func newCreateTableStmt(
name string,
elems []TableElem,
ifNotExists bool,
) *CreateTableStmt {
colsSpecs := make([]*ColSpec, 0, 5)
var checks []CheckConstraint

var pk PrimaryKeyConstraint
for _, e := range elems {
switch c := e.(type) {
case *ColSpec:
colsSpecs = append(colsSpecs, c)
case PrimaryKeyConstraint:
pk = c
case CheckConstraint:
if checks == nil {
checks = make([]CheckConstraint, 0, 5)
}
checks = append(checks, c)
}
}

return &CreateTableStmt{
ifNotExists: ifNotExists,
table: name,
colsSpec: colsSpecs,
pkColNames: pk,
checks: checks,
}
}
Loading
Loading