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
34 changes: 34 additions & 0 deletions fixtures/multi_vql_queries.golden
Original file line number Diff line number Diff line change
Expand Up @@ -1431,5 +1431,39 @@
{
"Total": 3
}
],
"092/000 Negative: LET X \u003c= 1 + -2": null,
"092/001 Negative: SELECT X FROM scope()": [
{
"X": -1
}
],
"093/000 Negative index: LET X \u003c= 2": null,
"093/001 Negative index: LET Bar(X) = X + 3": null,
"093/002 Negative index: LET Foo \u003c= (1, 2 + X, 3, 4 + -5)": null,
"093/003 Negative index: LET Float \u003c= 12.232": null,
"093/004 Negative index: LET StoredQuery = SELECT * FROM info()": null,
"093/005 Negative index: SELECT Foo[-2], Foo[-X], -X, -`X`, -Bar(X=3), -Float, -StoredQuery, Foo[-2:], Foo[-X:], Foo[-Bar(X=-1):] FROM scope()": [
{
"Foo[-2]": 3,
"Foo[-X]": 3,
"-X": -2,
"-`X`": -2,
"-Bar(X=3)": -6,
"-Float": -12.232,
"-StoredQuery": null,
"Foo[-2:]": [
3,
-1
],
"Foo[-X:]": [
3,
-1
],
"Foo[-Bar(X=-1):]": [
3,
-1
]
}
]
}
119 changes: 87 additions & 32 deletions vfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,14 @@ var (
`|(?ims)(?P<ORDERBY>\bORDER\s+BY\b)` +
`|(?ims)(?P<BOOL>\bTRUE\b|\bFALSE\b)` +
`|(?ims)(?P<LET>\bLET\b)` +
`|(?P<Number>-?(0x[0-9a-f]+|\d*\.?\d+([eE][-+]?\d+)?))` +
"|(?P<Ident>[a-zA-Z_][a-zA-Z0-9_]*|`[^`]+`)" +
"|(?P<SymbolIdent>-[a-zA-Z_][a-zA-Z0-9_]*|-`[^`]+`)" +
`|(?P<Operators><>|!=|<=|>=|=>|=~|[-]|[+]|[:*/%,.()=<>{}\[\]])` +
`|''(?P<MultilineString>'.*?')''` +
`|(?P<String>'([^'\\]*(\\.[^'\\]*)*)'|"([^"\\]*(\\.[^"\\]*)*)")` +
`|(?P<Number>[-+]?(0x[0-9a-f]+|\d*\.?\d+([eE][-+]?\d+)?))` +
`|(?P<Operators><>|!=|<=|>=|=>|=~|[-:+*/%,.()=<>{}\[\]])`,

"",
))

vqlParser = participle.MustBuild(
Expand Down Expand Up @@ -404,15 +407,24 @@ func (self *VQL) Eval(ctx context.Context, scope types.Scope) <-chan Row {
// LET is for stored query: LET X = SELECT ...
switch self.LetOperator {
case "=":
stored_query := NewStoredQuery(self.StoredQuery, name)
stored_query.parameters, stored_query.defaults = self.getParameters()
if self.StoredQuery == nil {
scope.AppendVars(ordereddict.NewDict().Set(name, Null{}))
} else {
stored_query := NewStoredQuery(self.StoredQuery, name)
stored_query.parameters, stored_query.defaults = self.getParameters()

scope.AppendVars(ordereddict.NewDict().Set(name, stored_query))
scope.AppendVars(ordereddict.NewDict().Set(name, stored_query))
}
case "<=":
// Delegate to the scope's materializer to actually
// materialize this query.
scope.AppendVars(ordereddict.NewDict().Set(
name, scope.Materialize(ctx, name, self.StoredQuery)))
if self.StoredQuery == nil {
scope.AppendVars(ordereddict.NewDict().Set(name, Null{}))
} else {

// Delegate to the scope's materializer to actually
// materialize this query.
scope.AppendVars(ordereddict.NewDict().Set(
name, scope.Materialize(ctx, name, self.StoredQuery)))
}
}

close(output_chan)
Expand All @@ -427,6 +439,10 @@ func (self *VQL) Eval(ctx context.Context, scope types.Scope) <-chan Row {
defer close(output_chan)
defer subscope.Close()

if self.Query == nil {
return
}

row_chan := self.Query.Eval(ctx, subscope)
for {
select {
Expand Down Expand Up @@ -584,9 +600,14 @@ func (self *_Select) Eval(ctx context.Context, scope types.Scope) <-chan Row {
// be relayed. NOTE: We need to transform the row first in
// order to assign aliases.
go func() {
defer close(output_chan)

if self.From == nil {
return
}

from_chan := self.From.Eval(ctx, scope)

defer close(output_chan)
for {
select {
// Are we cancelled?
Expand Down Expand Up @@ -815,11 +836,6 @@ type _OpMembershipTerm struct {
Term *string ` "." @Ident )`
}

type _SliceRange struct {
X *string `( { @Number} ":" `
RangeRightStr *string ` { @Number } )`
}

// ---------------------------------------

// The Top level precedence expression. Precedence table:
Expand Down Expand Up @@ -892,9 +908,10 @@ type _Term struct {

type _SymbolRef struct {
Comments []*_Comment ` [ @@ ] `
Symbol string `@Ident { @"." @Ident }`
Called bool `{ @"(" `
Parameters []*_Args ` [ @@ { "," @@ } ] ")" } `
Negated bool
Symbol string `(@SymbolIdent | @Ident) { @"." @Ident }`
Called bool `{ @"(" `
Parameters []*_Args ` [ @@ { "," @@ } ] ")" } `

mu sync.Mutex
function FunctionInterface
Expand All @@ -903,7 +920,6 @@ type _SymbolRef struct {

type _Value struct {
Comments []*_Comment ` [ @@ ] `
Negated bool `[ "-" | "+" ]`
SymbolRef *_SymbolRef `( @@ `
Subexpression *_CommaExpression `| "(" @@ ")"`

Expand Down Expand Up @@ -1608,21 +1624,25 @@ func (self *_SymbolRef) IsAggregate(scope types.Scope) bool {
return value.Info(scope, types.NewTypeMap()).IsAggregate
}

func (self *_SymbolRef) getFunction(scope types.Scope) (types.Any, bool) {
func (self *_SymbolRef) getFunction(scope types.Scope) (res types.Any, negated, pres bool) {

self.mu.Lock()
components := self.split_symbol
if components == nil {
components = utils.SplitIdent(self.Symbol)
if len(components) > 0 && strings.HasPrefix(components[0], "-") {
negated = true
components[0] = strings.TrimPrefix(components[0], "-")
}
self.split_symbol = components
}
self.mu.Unlock()

// Single item reference and called - call built in function.
if len(components) == 1 && self.Called {
res, pres := scope.GetFunction(self.Symbol)
res, pres := scope.GetFunction(components[0])
if pres {
return res, pres
return res, negated, pres
}
}

Expand All @@ -1645,21 +1665,54 @@ func (self *_SymbolRef) getFunction(scope types.Scope) (types.Any, bool) {
}
}

return nil, false
return nil, negated, false
}

result = subcomponent
}

return result, true
return result, negated, true
}

func (self *_SymbolRef) maybeNegate(
ctx context.Context, scope types.Scope,
negate bool, value Any) Any {
if !negate {
return value
}

switch t := value.(type) {
case StoredExpression:
return self.maybeNegate(ctx, scope, negate, t.Reduce(ctx, scope))

case LazyExpr:
return self.maybeNegate(ctx, scope, negate, t.ReduceWithScope(ctx, scope))

case bool:
return !t

case float64:
return -t

case float32:
return -t

default:
i, ok := utils.ToInt64(value)
if ok {
return -i
}
}

return Null{}
}

func (self *_SymbolRef) Reduce(ctx context.Context, scope types.Scope) Any {

// The symbol is just a constant in the scope. It may be a
// stored expression, a function or a stored query or just a
// plain value.
value, pres := self.getFunction(scope)
value, negated, pres := self.getFunction(scope)
if value != nil && pres {
switch t := value.(type) {
case FunctionInterface:
Expand All @@ -1670,7 +1723,8 @@ func (self *_SymbolRef) Reduce(ctx context.Context, scope types.Scope) Any {
}

// The symbol is a function and this is a call site, e.g. Symbol(...)
return self.callFunction(ctx, scope, t)
return self.maybeNegate(ctx, scope, negated,
self.callFunction(ctx, scope, t))

// If the symbol is a stored expression we evaluated
// it.
Expand All @@ -1694,7 +1748,7 @@ func (self *_SymbolRef) Reduce(ctx context.Context, scope types.Scope) Any {

scope.GetStats().IncFunctionsCalled()

return t.Reduce(ctx, subscope)
return self.maybeNegate(ctx, scope, negated, t.Reduce(ctx, subscope))

case StoredQuery:
// If the call site specifies parameters then
Expand Down Expand Up @@ -1724,10 +1778,11 @@ func (self *_SymbolRef) Reduce(ctx context.Context, scope types.Scope) Any {
scope.GetStats().IncFunctionsCalled()

// Wrap the query with the captured scope.
return &StoredQueryCallSite{
query: t,
scope: subscope,
}
return self.maybeNegate(ctx, scope, negated,
&StoredQueryCallSite{
query: t,
scope: subscope,
})
}
}

Expand All @@ -1738,7 +1793,7 @@ func (self *_SymbolRef) Reduce(ctx context.Context, scope types.Scope) Any {
}

// Every thing else is taken literally.
return value
return self.maybeNegate(ctx, scope, negated, value)
}

return Null{}
Expand Down
19 changes: 18 additions & 1 deletion vfilter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,23 @@ LET F(X = 2, Y ) =
FROM scope()

SELECT * FROM F(Y=1)
`},
{"Negative",
"LET X <= 1 + -2 SELECT X FROM scope()"},
{"Negative index",
`
LET X <= 2
LET Bar(X) = X + 3
LET Foo <= (1, 2+X, 3, 4+ -5)
LET Float <= 12.232
LET StoredQuery = SELECT * FROM info()

SELECT Foo[ -2 ], Foo[ -X ], -X, ` + "-`X`, " + `
-Bar(X=3), -Float, -StoredQuery,
Foo[-2:],
Foo[-X:],
Foo[-Bar(X=-1):]
FROM scope()
`},
}

Expand Down Expand Up @@ -1563,7 +1580,7 @@ func TestMultiVQLQueries(t *testing.T) {
// Store the result in ordered dict so we have a consistent golden file.
result := ordereddict.NewDict()
for i, testCase := range multiVQLTest {
if false && i != 66 {
if false && i != 93 {
continue
}
scope := makeTestScope()
Expand Down
13 changes: 2 additions & 11 deletions visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,11 +681,6 @@ func (self *Visitor) visitValue(node *_Value) {
self.Visit(node.Comments)
node.maybeParseStrNumber(self.scope)

factor := 1.0
if node.Negated {
factor = -1.0
}

symbolref := node.SymbolRef
if symbolref != nil {
node.mu.Unlock()
Expand All @@ -712,18 +707,14 @@ func (self *Visitor) visitValue(node *_Value) {
}

if node.Int != nil {
factor := int64(1)
if node.Negated {
factor = -1
}
self.push(strconv.FormatInt(factor**node.Int, 10))
self.push(strconv.FormatInt(*node.Int, 10))
node.mu.Unlock()
return

}

if node.Float != nil {
result := strconv.FormatFloat(factor**node.Float, 'f', -1, 64)
result := strconv.FormatFloat(*node.Float, 'f', -1, 64)
if !strings.Contains(result, ".") {
result = result + ".0"
}
Expand Down
Loading