Skip to content

Commit

Permalink
stream: clone stream before execution
Browse files Browse the repository at this point in the history
  • Loading branch information
asdine committed Feb 17, 2024
1 parent bac26ce commit 71146bc
Show file tree
Hide file tree
Showing 37 changed files with 464 additions and 13 deletions.
6 changes: 6 additions & 0 deletions internal/expr/arithmeric.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ type arithmeticOperator struct {
*simpleOperator
}

func (op *arithmeticOperator) Clone() Expr {
return &arithmeticOperator{
simpleOperator: op.simpleOperator.Clone(),
}
}

func (op *arithmeticOperator) Eval(env *environment.Environment) (types.Value, error) {
return op.simpleOperator.eval(env, func(va, vb types.Value) (types.Value, error) {
a, ok := va.(types.Numeric)
Expand Down
47 changes: 42 additions & 5 deletions internal/expr/comparison.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ func (op *cmpOp) compare(l, r types.Value) (bool, error) {
}
}

func (op *cmpOp) Clone() Expr {
return &cmpOp{op.simpleOperator.Clone()}
}

// Eq creates an expression that returns true if a equals b.
func Eq(a, b Expr) Expr {
return newCmpOp(a, b, scanner.EQ)
Expand Down Expand Up @@ -102,6 +106,13 @@ func Between(a Expr) func(x, b Expr) Expr {
}
}

func (op *BetweenOperator) Clone() Expr {
return &BetweenOperator{
op.simpleOperator.Clone(),
Clone(op.X),
}
}

func (op *BetweenOperator) Eval(env *environment.Environment) (types.Value, error) {
x, err := op.X.Eval(env)
if err != nil {
Expand Down Expand Up @@ -152,15 +163,23 @@ func In(a Expr, b Expr) Expr {
return &InOperator{a, b, scanner.IN}
}

func (op InOperator) Precedence() int {
func (op *InOperator) Clone() Expr {
return &InOperator{
Clone(op.a),
Clone(op.b),
op.op,
}
}

func (op *InOperator) Precedence() int {
return op.op.Precedence()
}

func (op InOperator) LeftHand() Expr {
func (op *InOperator) LeftHand() Expr {
return op.a
}

func (op InOperator) RightHand() Expr {
func (op *InOperator) RightHand() Expr {
return op.b
}

Expand Down Expand Up @@ -242,12 +261,18 @@ func (op *InOperator) validateRightExpression(b Expr) (LiteralExprList, error) {
}

type NotInOperator struct {
InOperator
*InOperator
}

// NotIn creates an expression that evaluates to the result of a NOT IN b.
func NotIn(a Expr, b Expr) Expr {
return &NotInOperator{InOperator{a, b, scanner.NIN}}
return &NotInOperator{&InOperator{a, b, scanner.NIN}}
}

func (op *NotInOperator) Clone() Expr {
return &NotInOperator{
op.InOperator.Clone().(*InOperator),
}
}

func (op *NotInOperator) Eval(env *environment.Environment) (types.Value, error) {
Expand All @@ -267,6 +292,12 @@ func Is(a, b Expr) Expr {
return &IsOperator{&simpleOperator{a, b, scanner.IN}}
}

func (op *IsOperator) Clone() Expr {
return &IsOperator{
op.simpleOperator.Clone(),
}
}

func (op *IsOperator) Eval(env *environment.Environment) (types.Value, error) {
return op.simpleOperator.eval(env, func(a, b types.Value) (types.Value, error) {
ok, err := a.EQ(b)
Expand All @@ -290,6 +321,12 @@ func IsNot(a, b Expr) Expr {
return &IsNotOperator{&simpleOperator{a, b, scanner.ISN}}
}

func (op *IsNotOperator) Clone() Expr {
return &IsNotOperator{
op.simpleOperator.Clone(),
}
}

func (op *IsNotOperator) Eval(env *environment.Environment) (types.Value, error) {
return op.simpleOperator.eval(env, func(a, b types.Value) (types.Value, error) {
eq, err := a.EQ(b)
Expand Down
37 changes: 37 additions & 0 deletions internal/expr/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type Function interface {

// Params returns the list of parameters this function has received.
Params() []Expr
Clone() Expr
}

// An Aggregator is an expression that aggregates objects into one result.
Expand Down Expand Up @@ -238,3 +239,39 @@ func (n NextValueFor) String() string {

// return types.TypeNull, fmt.Errorf("unexpected expression type: %T", e)
// }

func Clone(e Expr) Expr {
if e == nil {
return nil
}

switch e := e.(type) {
case cloner:
return e.Clone()
case Parentheses:
return Parentheses{E: Clone(e.E)}
case *NamedExpr:
return &NamedExpr{
Expr: Clone(e.Expr),
ExprName: e.ExprName,
}
case *Cast:
return &Cast{
Expr: Clone(e.Expr),
CastAs: e.CastAs,
}
case LiteralValue,
Column,
NamedParam,
PositionalParam,
NextValueFor,
Wildcard:
return e
}

panic(fmt.Sprintf("clone: unexpected expression type: %T", e))
}

type cloner interface {
Clone() Expr
}
58 changes: 58 additions & 0 deletions internal/expr/functions/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ type TypeOf struct {
Expr expr.Expr
}

func (t *TypeOf) Clone() expr.Expr {
return &TypeOf{
Expr: expr.Clone(t.Expr),
}
}

func (t *TypeOf) Eval(env *environment.Environment) (types.Value, error) {
v, err := t.Expr.Eval(env)
if err != nil {
Expand Down Expand Up @@ -175,6 +181,14 @@ func NewCount(e expr.Expr) *Count {
}
}

func (t *Count) Clone() expr.Expr {
return &Count{
Expr: expr.Clone(t.Expr),
wildcard: t.wildcard,
Count: t.Count,
}
}

func (c *Count) Eval(env *environment.Environment) (types.Value, error) {
d, ok := env.GetRow()
if !ok {
Expand Down Expand Up @@ -250,6 +264,12 @@ type Min struct {
Expr expr.Expr
}

func (t *Min) Clone() expr.Expr {
return &Min{
Expr: expr.Clone(t.Expr),
}
}

// Eval extracts the min value from the given object and returns it.
func (m *Min) Eval(env *environment.Environment) (types.Value, error) {
r, ok := env.GetRow()
Expand Down Expand Up @@ -354,6 +374,12 @@ type Max struct {
Expr expr.Expr
}

func (t *Max) Clone() expr.Expr {
return &Max{
Expr: expr.Clone(t.Expr),
}
}

// Eval extracts the max value from the given object and returns it.
func (m *Max) Eval(env *environment.Environment) (types.Value, error) {
r, ok := env.GetRow()
Expand Down Expand Up @@ -453,6 +479,12 @@ type Sum struct {
Expr expr.Expr
}

func (t *Sum) Clone() expr.Expr {
return &Sum{
Expr: expr.Clone(t.Expr),
}
}

// Eval extracts the sum value from the given object and returns it.
func (s *Sum) Eval(env *environment.Environment) (types.Value, error) {
r, ok := env.GetRow()
Expand Down Expand Up @@ -564,6 +596,12 @@ type Avg struct {
Expr expr.Expr
}

func (t *Avg) Clone() expr.Expr {
return &Avg{
Expr: expr.Clone(t.Expr),
}
}

// Eval extracts the average value from the given object and returns it.
func (s *Avg) Eval(env *environment.Environment) (types.Value, error) {
r, ok := env.GetRow()
Expand Down Expand Up @@ -651,6 +689,12 @@ type Len struct {
Expr expr.Expr
}

func (t *Len) Clone() expr.Expr {
return &Len{
Expr: expr.Clone(t.Expr),
}
}

// Eval extracts the average value from the given object and returns it.
func (s *Len) Eval(env *environment.Environment) (types.Value, error) {
val, err := s.Expr.Eval(env)
Expand Down Expand Up @@ -694,6 +738,16 @@ type Coalesce struct {
Exprs []expr.Expr
}

func (c *Coalesce) Clone() expr.Expr {
var clone Coalesce
clone.Exprs = make([]expr.Expr, 0, len(c.Exprs))
for _, e := range c.Exprs {
clone.Exprs = append(clone.Exprs, expr.Clone(e))
}

return &clone
}

func (c *Coalesce) Eval(e *environment.Environment) (types.Value, error) {
for _, exp := range c.Exprs {
v, err := exp.Eval(e)
Expand All @@ -717,6 +771,10 @@ func (c *Coalesce) Params() []expr.Expr {

type Now struct{}

func (n *Now) Clone() expr.Expr {
return &Now{}
}

func (n *Now) Eval(env *environment.Environment) (types.Value, error) {
tx := env.GetTx()
if tx == nil {
Expand Down
12 changes: 12 additions & 0 deletions internal/expr/functions/scalar_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ type ScalarFunction struct {
params []expr.Expr
}

func (sf *ScalarFunction) Clone() expr.Expr {
exprs := make([]expr.Expr, 0, len(sf.params))
for _, e := range sf.params {
exprs = append(exprs, expr.Clone(e))
}

return &ScalarFunction{
def: sf.def,
params: exprs,
}
}

// Eval returns a row.Value based on the given environment and the underlying function
// definition.
func (sf *ScalarFunction) Eval(env *environment.Environment) (types.Value, error) {
Expand Down
24 changes: 24 additions & 0 deletions internal/expr/functions/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ type Lower struct {
Expr expr.Expr
}

func (s *Lower) Clone() expr.Expr {
return &Lower{
Expr: expr.Clone(s.Expr),
}
}

func (s *Lower) Eval(env *environment.Environment) (types.Value, error) {
val, err := s.Expr.Eval(env)
if err != nil {
Expand Down Expand Up @@ -55,6 +61,12 @@ type Upper struct {
Expr expr.Expr
}

func (s *Upper) Clone() expr.Expr {
return &Upper{
Expr: expr.Clone(s.Expr),
}
}

func (s *Upper) Eval(env *environment.Environment) (types.Value, error) {
val, err := s.Expr.Eval(env)
if err != nil {
Expand Down Expand Up @@ -101,6 +113,18 @@ type Trim struct {

type TrimFunc func(string, string) string

func (s *Trim) Clone() expr.Expr {
exprs := make([]expr.Expr, len(s.Expr))
for i := range s.Expr {
exprs[i] = expr.Clone(s.Expr[i])
}
return &Trim{
Expr: exprs,
TrimFunc: s.TrimFunc,
Name: s.Name,
}
}

func (s *Trim) Eval(env *environment.Environment) (types.Value, error) {
if len(s.Expr) > 2 {
return nil, fmt.Errorf("misuse of string function %v()", s.Name)
Expand Down
16 changes: 16 additions & 0 deletions internal/expr/like.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ func Like(a, b Expr) Expr {
return &LikeOperator{&simpleOperator{a, b, scanner.LIKE}}
}

func (op *LikeOperator) Clone() Expr {
return &LikeOperator{
simpleOperator: op.simpleOperator.Clone(),
}
}

func (op *LikeOperator) Eval(env *environment.Environment) (types.Value, error) {
return op.simpleOperator.eval(env, func(a, b types.Value) (types.Value, error) {
if a.Type() != types.TypeText || b.Type() != types.TypeText {
Expand All @@ -36,6 +42,10 @@ func (op *LikeOperator) Eval(env *environment.Environment) (types.Value, error)
})
}

func (op *LikeOperator) String() string {
return fmt.Sprintf("%v LIKE %v", op.a, op.b)
}

type NotLikeOperator struct {
*LikeOperator
}
Expand All @@ -45,6 +55,12 @@ func NotLike(a, b Expr) Expr {
return &NotLikeOperator{&LikeOperator{&simpleOperator{a, b, scanner.NLIKE}}}
}

func (op *NotLikeOperator) Clone() Expr {
return &NotLikeOperator{
LikeOperator: op.LikeOperator.Clone().(*LikeOperator),
}
}

func (op *NotLikeOperator) Eval(env *environment.Environment) (types.Value, error) {
return invertBoolResult(op.LikeOperator.Eval)(env)
}
Expand Down
8 changes: 8 additions & 0 deletions internal/expr/literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ func (v LiteralValue) Eval(*environment.Environment) (types.Value, error) {
// LiteralExprList is a list of expressions.
type LiteralExprList []Expr

func (l LiteralExprList) Clone() Expr {
exprs := make(LiteralExprList, len(l))
for i, e := range l {
exprs[i] = Clone(e)
}
return exprs
}

// IsEqual compares this expression with the other expression and returns
// true if they are equal.
func (l LiteralExprList) IsEqual(o LiteralExprList) bool {
Expand Down
Loading

0 comments on commit 71146bc

Please sign in to comment.