Skip to content

Commit

Permalink
Sql parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
cube2222 committed Mar 10, 2019
1 parent e8d6ba8 commit e9c3c9f
Show file tree
Hide file tree
Showing 15 changed files with 464 additions and 61 deletions.
90 changes: 56 additions & 34 deletions cmd/octosql/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,40 @@ import (
"context"
"fmt"
"log"
"os"
"strings"

"github.com/bradleyjkemp/memviz"
"github.com/cube2222/octosql/execution"
"github.com/cube2222/octosql/logical"
"github.com/cube2222/octosql/parser"
"github.com/cube2222/octosql/physical"
"github.com/cube2222/octosql/storage/json"
"github.com/xwb1989/sqlparser"
)

func main() {
/*stmt, err := sqlparser.Parse("SELECT prefix(name, 3), age FROM (SELECT * FROM users) g")
stmt, err := sqlparser.Parse(`
SELECT p3.name, (SELECT p1.city FROM people p1 WHERE p3.name = 'Kuba' AND p1.name = 'adam') as city
FROM (Select * from people p4) p3
WHERE (SELECT p2.age FROM people p2 WHERE p2.name = 'wojtek') > p3.age`)
if err != nil {
log.Println(err)
}

log.Println(stmt)
if typed, ok := stmt.(*sqlparser.Select); ok {
log.Println(typed)
log.Println(typed)
}*/
parsed, err := parser.ParseSelect(typed)
if err != nil {
log.Fatal(err)
}

f, err := os.Create("diag")
if err != nil {
log.Fatal(err)
}
defer f.Close()
memmap.Map(f, parsed)
}

/*client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Expand Down Expand Up @@ -71,6 +85,10 @@ func main() {
if err != nil {
log.Fatal(err)
}*/

}

func hello() {
var record *execution.Record
ctx := context.Background()

Expand All @@ -84,7 +102,7 @@ func main() {

// SELECT name, city FROM people WHERE age > 3
logicalPlan := logical.NewMap(
[]logical.Expression{
[]logical.NamedExpression{
logical.NewVariable("people.name"),
logical.NewVariable("people.surname"),
logical.NewVariable("people.city"),
Expand Down Expand Up @@ -134,45 +152,49 @@ func main() {
// WHERE (SELECT p2.age FROM people p2 WHERE p2.name = 'wojtek') > p3.age

logicalPlan2 := logical.NewMap(
[]logical.Expression{
[]logical.NamedExpression{
logical.NewVariable("p3.name"),
logical.NewNodeExpression(
logical.NewAliasedExpression(
"city",
logical.NewMap(
[]logical.Expression{logical.NewVariable("p1.city")},
logical.NewFilter(
logical.NewInfixOperator(
logical.NewPredicate(
logical.NewVariable("p3.name"),
logical.NewRelation("="),
logical.NewConstant("Kuba"),
),
logical.NewPredicate(
logical.NewVariable("p1.name"),
logical.NewRelation("="),
logical.NewConstant("adam"),
logical.NewNodeExpression(
logical.NewMap(
[]logical.NamedExpression{logical.NewVariable("p1.city")},
logical.NewFilter(
logical.NewInfixOperator(
logical.NewPredicate(
logical.NewVariable("p3.name"),
logical.NewRelation("="),
logical.NewConstant("Kuba"),
),
logical.NewPredicate(
logical.NewVariable("p1.name"),
logical.NewRelation("="),
logical.NewConstant("adam"),
),
"AND",
),
"AND",
),

logical.NewDataSource("people", "p1"),
logical.NewDataSource("people", "p1"),
),
),
),
),
},
logical.NewFilter(
logical.NewPredicate(
logical.NewNodeExpression(
logical.NewAliasedExpression(
"wojtek_age",
logical.NewMap(
[]logical.Expression{logical.NewVariable("p2.age")},
logical.NewFilter(
logical.NewPredicate(
logical.NewVariable("p2.name"),
logical.NewRelation("="),
logical.NewConstant("wojtek"),
logical.NewNodeExpression(
logical.NewMap(
[]logical.NamedExpression{logical.NewVariable("p2.age")},
logical.NewFilter(
logical.NewPredicate(
logical.NewVariable("p2.name"),
logical.NewRelation("="),
logical.NewConstant("wojtek"),
),
logical.NewDataSource("people", "p2"),
),
logical.NewDataSource("people", "p2"),
),
),
),
Expand Down
26 changes: 21 additions & 5 deletions execution/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ type Node interface {

type Expression interface {
ExpressionValue(variables octosql.Variables) (interface{}, error)
}

type NamedExpression interface {
Expression
Name() octosql.VariableName
}

Expand All @@ -35,12 +39,11 @@ func (v *Variable) Name() octosql.VariableName {
}

type NodeExpression struct {
name octosql.VariableName
node Node
}

func NewNodeExpression(name octosql.VariableName, node Node) *NodeExpression {
return &NodeExpression{name: name, node: node}
func NewNodeExpression(node Node) *NodeExpression {
return &NodeExpression{node: node}
}

func (ne *NodeExpression) ExpressionValue(variables octosql.Variables) (interface{}, error) {
Expand Down Expand Up @@ -79,6 +82,19 @@ func (ne *NodeExpression) ExpressionValue(variables octosql.Variables) (interfac
return record.Value(record.Fields()[0].Name), nil
}

func (ne *NodeExpression) Name() octosql.VariableName {
return ne.name
type AliasedExpression struct {
name octosql.VariableName
expr Expression
}

func NewAliasedExpression(name octosql.VariableName, expr Expression) *AliasedExpression {
return &AliasedExpression{name: name, expr: expr}
}

func (alExpr *AliasedExpression) ExpressionValue(variables octosql.Variables) (interface{}, error) {
return alExpr.expr.ExpressionValue(variables)
}

func (alExpr *AliasedExpression) Name() octosql.VariableName {
return alExpr.name
}
6 changes: 3 additions & 3 deletions execution/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
)

type Map struct {
expressions []Expression
expressions []NamedExpression
source Node
}

func NewMap(expressions []Expression, child Node) *Map {
func NewMap(expressions []NamedExpression, child Node) *Map {
return &Map{expressions: expressions, source: child}
}

Expand All @@ -28,7 +28,7 @@ func (node *Map) Get(variables octosql.Variables) (RecordStream, error) {
}

type MappedStream struct {
expressions []Expression
expressions []NamedExpression
variables octosql.Variables
source RecordStream
}
Expand Down
69 changes: 69 additions & 0 deletions execution/requalifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package execution

import (
"fmt"
"regexp"
"strings"

"github.com/cube2222/octosql"
"github.com/pkg/errors"
)

type Requalifier struct {
qualifier string
source Node
}

func NewRequalifier(qualifier string, child Node) *Requalifier {
return &Requalifier{qualifier: qualifier, source: child}
}

func (node *Requalifier) Get(variables octosql.Variables) (RecordStream, error) {
recordStream, err := node.source.Get(variables)
if err != nil {
return nil, errors.Wrap(err, "couldn't get record stream")
}

return &RequalifiedStream{
qualifier: node.qualifier,
variables: variables,
source: recordStream,
}, nil
}

type RequalifiedStream struct {
qualifier string
variables octosql.Variables
source RecordStream
}

// TODO: Do table name validation on logical -> physical plan transformation
var simpleQualifierMatcher = regexp.MustCompile("[a-zA-Z0-9-_]")

func (stream *RequalifiedStream) Next() (*Record, error) {
record, err := stream.source.Next()
if err != nil {
if err == ErrEndOfStream {
return nil, ErrEndOfStream
}
return nil, errors.Wrap(err, "couldn't get source record")
}
oldFields := record.Fields()

fields := make([]octosql.VariableName, len(record.Fields()))
values := make(map[octosql.VariableName]interface{})
for i := range oldFields {
name := string(oldFields[i].Name)
if dotIndex := strings.Index(name, "."); dotIndex != -1 {
if simpleQualifierMatcher.MatchString(name[:dotIndex]) {
name = name[dotIndex+1:]
}
}
qualifiedName := octosql.VariableName(fmt.Sprintf("%s.%s", stream.qualifier, name))

fields = append(fields, qualifiedName)
values[qualifiedName] = record.Value(oldFields[i].Name)
}

return NewRecord(fields, values), nil
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
module github.com/cube2222/octosql

require (
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible // indirect
github.com/bradleyjkemp/memmap v0.2.2 // indirect
github.com/bradleyjkemp/memviz v0.2.2
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pkg/errors v0.8.1
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnLTKNzo+bdmT/oH34c2Y=
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible/go.mod h1:Au1Xw1sgaJ5iSFktEhYsS0dbQiS1B0/XMXl+42y9Ilk=
github.com/bradleyjkemp/memmap v0.2.2 h1:K1MRR3CePpyv5fCF92VVRQa0YTCF1lBeHYUe1YQKPt8=
github.com/bradleyjkemp/memmap v0.2.2/go.mod h1:hk93kmTK3wk+ezO+gS/h/W7ZXi5CRoB3sXCajzC2PMU=
github.com/bradleyjkemp/memviz v0.2.2 h1:4401FLjMkfcpjrCJNSorhiPSkjiq8QBS++fsppQSk1s=
github.com/bradleyjkemp/memviz v0.2.2/go.mod h1:O8KbRC1I+XiOeTs6+KcaCuME1yAAEc54zsQrlv6nkKg=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ=
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
4 changes: 2 additions & 2 deletions logical/logic.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ type PrefixOperator struct {
Operator string
}

func NewPrefixOperator(operator string) *PrefixOperator {
return &PrefixOperator{Operator: operator}
func NewPrefixOperator(child Formula, operator string) *PrefixOperator {
return &PrefixOperator{Child: child, Operator: operator}
}

func (f *PrefixOperator) Physical(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.Formula, octosql.Variables, error) {
Expand Down
37 changes: 33 additions & 4 deletions logical/logical.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ type Expression interface {
Physical(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.Expression, octosql.Variables, error)
}

type NamedExpression interface {
Expression
PhysicalNamed(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.NamedExpression, octosql.Variables, error)
}

type Variable struct {
name octosql.VariableName
}
Expand All @@ -61,6 +66,10 @@ func NewVariable(name octosql.VariableName) *Variable {
}

func (v *Variable) Physical(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.Expression, octosql.Variables, error) {
return v.PhysicalNamed(ctx, physicalCreator)
}

func (v *Variable) PhysicalNamed(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.NamedExpression, octosql.Variables, error) {
return physical.NewVariable(v.name), octosql.NoVariables(), nil
}

Expand All @@ -80,18 +89,38 @@ func (v *Constant) Physical(ctx context.Context, physicalCreator *PhysicalPlanCr
}

type NodeExpression struct {
name octosql.VariableName
node Node
}

func NewNodeExpression(name octosql.VariableName, node Node) *NodeExpression {
return &NodeExpression{name: name, node: node}
func NewNodeExpression(node Node) *NodeExpression {
return &NodeExpression{node: node}
}

func (ne *NodeExpression) Physical(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.Expression, octosql.Variables, error) {
physicalNode, variables, err := ne.node.Physical(ctx, physicalCreator)
if err != nil {
return nil, nil, errors.Wrap(err, "couldn't get physical plan for node expression")
}
return physical.NewNodeExpression(ne.name, physicalNode), variables, nil
return physical.NewNodeExpression(physicalNode), variables, nil
}

type AliasedExpression struct {
name octosql.VariableName
expr Expression
}

func NewAliasedExpression(name octosql.VariableName, expr Expression) NamedExpression {
return &AliasedExpression{name: name, expr: expr}
}

func (alExpr *AliasedExpression) Physical(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.Expression, octosql.Variables, error) {
return alExpr.PhysicalNamed(ctx, physicalCreator)
}

func (alExpr *AliasedExpression) PhysicalNamed(ctx context.Context, physicalCreator *PhysicalPlanCreator) (physical.NamedExpression, octosql.Variables, error) {
physicalNode, variables, err := alExpr.expr.Physical(ctx, physicalCreator)
if err != nil {
return nil, nil, errors.Wrap(err, "couldn't get physical plan for aliased expression")
}
return physical.NewAliasedExpression(alExpr.name, physicalNode), variables, nil
}
Loading

0 comments on commit e9c3c9f

Please sign in to comment.