Merge pull request #3541 from DanielMorsing/validateFields
check if fields are valid during parse.pull/3560/head
commit
affd0b1ca2
|
@ -14,6 +14,7 @@
|
||||||
- [#3420](https://github.com/influxdb/influxdb/pull/3420): Catch opentsdb malformed tags. Thanks @nathanielc.
|
- [#3420](https://github.com/influxdb/influxdb/pull/3420): Catch opentsdb malformed tags. Thanks @nathanielc.
|
||||||
- [#3404](https://github.com/influxdb/influxdb/pull/3404): Added support for escaped single quotes in query string. Thanks @jhorwit2
|
- [#3404](https://github.com/influxdb/influxdb/pull/3404): Added support for escaped single quotes in query string. Thanks @jhorwit2
|
||||||
- [#3414](https://github.com/influxdb/influxdb/issues/3414): Shard mappers perform query re-writing
|
- [#3414](https://github.com/influxdb/influxdb/issues/3414): Shard mappers perform query re-writing
|
||||||
|
- [#3525](https://github.com/influxdb/influxdb/pull/3525): check if fields are valid during parse time.
|
||||||
|
|
||||||
## v0.9.2 [2015-07-24]
|
## v0.9.2 [2015-07-24]
|
||||||
|
|
||||||
|
|
|
@ -1471,11 +1471,18 @@ func (p *Parser) parseFields() (Fields, error) {
|
||||||
func (p *Parser) parseField() (*Field, error) {
|
func (p *Parser) parseField() (*Field, error) {
|
||||||
f := &Field{}
|
f := &Field{}
|
||||||
|
|
||||||
|
_, pos, _ := p.scanIgnoreWhitespace()
|
||||||
|
p.unscan()
|
||||||
// Parse the expression first.
|
// Parse the expression first.
|
||||||
expr, err := p.ParseExpr()
|
expr, err := p.ParseExpr()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var c validateField
|
||||||
|
Walk(&c, expr)
|
||||||
|
if c.foundInvalid {
|
||||||
|
return nil, fmt.Errorf("invalid operator %s in SELECT clause at line %d, char %d; operator is intended for WHERE clause", c.badToken, pos.Line+1, pos.Char+1)
|
||||||
|
}
|
||||||
f.Expr = expr
|
f.Expr = expr
|
||||||
|
|
||||||
// Parse the alias if the current and next tokens are "WS AS".
|
// Parse the alias if the current and next tokens are "WS AS".
|
||||||
|
@ -1491,6 +1498,30 @@ func (p *Parser) parseField() (*Field, error) {
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateField checks if the Expr is a valid field. We disallow all binary expression
|
||||||
|
// that return a boolean
|
||||||
|
type validateField struct {
|
||||||
|
foundInvalid bool
|
||||||
|
badToken Token
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *validateField) Visit(n Node) Visitor {
|
||||||
|
e, ok := n.(*BinaryExpr)
|
||||||
|
if !ok {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Op {
|
||||||
|
case EQ, NEQ, EQREGEX,
|
||||||
|
NEQREGEX, LT, LTE, GT, GTE,
|
||||||
|
AND, OR:
|
||||||
|
c.foundInvalid = true
|
||||||
|
c.badToken = e.Op
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// parseAlias parses the "AS (IDENT|STRING)" alias for fields and dimensions.
|
// parseAlias parses the "AS (IDENT|STRING)" alias for fields and dimensions.
|
||||||
func (p *Parser) parseAlias() (string, error) {
|
func (p *Parser) parseAlias() (string, error) {
|
||||||
// Check if the next token is "AS". If not, then unscan and exit.
|
// Check if the next token is "AS". If not, then unscan and exit.
|
||||||
|
|
|
@ -1244,6 +1244,9 @@ func TestParser_ParseStatement(t *testing.T) {
|
||||||
{s: `select derivative() from myseries`, err: `invalid number of arguments for derivative, expected at least 1 but no more than 2, got 0`},
|
{s: `select derivative() from myseries`, err: `invalid number of arguments for derivative, expected at least 1 but no more than 2, got 0`},
|
||||||
{s: `select derivative(mean(value), 1h, 3) from myseries`, err: `invalid number of arguments for derivative, expected at least 1 but no more than 2, got 3`},
|
{s: `select derivative(mean(value), 1h, 3) from myseries`, err: `invalid number of arguments for derivative, expected at least 1 but no more than 2, got 3`},
|
||||||
{s: `SELECT field1 from myseries WHERE host =~ 'asd' LIMIT 1`, err: `found asd, expected regex at line 1, char 42`},
|
{s: `SELECT field1 from myseries WHERE host =~ 'asd' LIMIT 1`, err: `found asd, expected regex at line 1, char 42`},
|
||||||
|
{s: `SELECT value > 2 FROM cpu`, err: `invalid operator > in SELECT clause at line 1, char 8; operator is intended for WHERE clause`},
|
||||||
|
{s: `SELECT value = 2 FROM cpu`, err: `invalid operator = in SELECT clause at line 1, char 8; operator is intended for WHERE clause`},
|
||||||
|
{s: `SELECT s =~ /foo/ FROM cpu`, err: `invalid operator =~ in SELECT clause at line 1, char 8; operator is intended for WHERE clause`},
|
||||||
{s: `DELETE`, err: `found EOF, expected FROM at line 1, char 8`},
|
{s: `DELETE`, err: `found EOF, expected FROM at line 1, char 8`},
|
||||||
{s: `DELETE FROM`, err: `found EOF, expected identifier at line 1, char 13`},
|
{s: `DELETE FROM`, err: `found EOF, expected identifier at line 1, char 13`},
|
||||||
{s: `DELETE FROM myseries WHERE`, err: `found EOF, expected identifier, string, number, bool at line 1, char 28`},
|
{s: `DELETE FROM myseries WHERE`, err: `found EOF, expected identifier, string, number, bool at line 1, char 28`},
|
||||||
|
|
Loading…
Reference in New Issue