fix #1799: change regex delim to '/' & RHS only
parent
08796bd6af
commit
9d6d36f2e9
|
@ -1913,7 +1913,7 @@ func TestHandler_serveShowSeries(t *testing.T) {
|
|||
|
||||
// SHOW SERIES WHERE =~ regex
|
||||
{
|
||||
q: "SHOW SERIES WHERE region =~ `ca.*`",
|
||||
q: `SHOW SERIES WHERE region =~ /ca.*/`,
|
||||
r: &influxdb.Results{
|
||||
Results: []*influxdb.Result{
|
||||
{
|
||||
|
@ -1933,7 +1933,7 @@ func TestHandler_serveShowSeries(t *testing.T) {
|
|||
|
||||
// SHOW SERIES WHERE !~ regex
|
||||
{
|
||||
q: "SHOW SERIES WHERE host !~ `server0[12]`",
|
||||
q: `SHOW SERIES WHERE host !~ /server0[12]/`,
|
||||
r: &influxdb.Results{
|
||||
Results: []*influxdb.Result{
|
||||
{
|
||||
|
@ -2046,13 +2046,13 @@ func TestHandler_serveShowMeasurements(t *testing.T) {
|
|||
|
||||
// SHOW MEASUREMENTS WHERE =~ regex
|
||||
{
|
||||
q: "SHOW MEASUREMENTS WHERE region =~ `ca.*`",
|
||||
q: `SHOW MEASUREMENTS WHERE region =~ /ca.*/`,
|
||||
r: `{"results":[{"series":[{"name":"measurements","columns":["name"],"values":[["gpu"],["other"]]}]}]}`,
|
||||
},
|
||||
|
||||
// SHOW MEASUREMENTS WHERE !~ regex
|
||||
{
|
||||
q: "SHOW MEASUREMENTS WHERE region !~ `ca.*`",
|
||||
q: `SHOW MEASUREMENTS WHERE region !~ /ca.*/`,
|
||||
r: `{"results":[{"series":[{"name":"measurements","columns":["name"],"values":[["cpu"]]}]}]}`,
|
||||
},
|
||||
}
|
||||
|
@ -2302,7 +2302,7 @@ func TestHandler_serveShowTagValues(t *testing.T) {
|
|||
},
|
||||
// SHOW TAG VALUES FROM ... WHERE =~ regex
|
||||
{
|
||||
q: "SHOW TAG VALUES WITH KEY = host WHERE region =~ `ca.*`",
|
||||
q: `SHOW TAG VALUES WITH KEY = host WHERE region =~ /ca.*/`,
|
||||
r: &influxdb.Results{
|
||||
Results: []*influxdb.Result{
|
||||
{
|
||||
|
@ -2321,7 +2321,7 @@ func TestHandler_serveShowTagValues(t *testing.T) {
|
|||
},
|
||||
// SHOW TAG VALUES FROM ... WHERE !~ regex
|
||||
{
|
||||
q: "SHOW TAG VALUES WITH KEY = region WHERE host !~ `server0[12]`",
|
||||
q: `SHOW TAG VALUES WITH KEY = region WHERE host !~ /server0[12]/`,
|
||||
r: &influxdb.Results{
|
||||
Results: []*influxdb.Result{
|
||||
{
|
||||
|
|
|
@ -1456,6 +1456,8 @@ func (p *Parser) parseSortField() (*SortField, error) {
|
|||
|
||||
// ParseExpr parses an expression.
|
||||
func (p *Parser) ParseExpr() (Expr, error) {
|
||||
var err error
|
||||
|
||||
// Parse a non-binary expression type to start.
|
||||
// This variable will always be the root of the expression tree.
|
||||
expr, err := p.parseUnaryExpr()
|
||||
|
@ -1472,10 +1474,18 @@ func (p *Parser) ParseExpr() (Expr, error) {
|
|||
return expr, nil
|
||||
}
|
||||
|
||||
// Otherwise parse the next unary expression.
|
||||
rhs, err := p.parseUnaryExpr()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Otherwise parse the next expression.
|
||||
var rhs Expr
|
||||
if IsRegexOp(op) {
|
||||
// RHS of a regex operator must be a regular expression.
|
||||
p.consumeWhitespace()
|
||||
if rhs, err = p.parseRegex(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if rhs, err = p.parseUnaryExpr(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Assign the new root based on the precendence of the LHS and RHS operators.
|
||||
|
@ -1565,6 +1575,28 @@ func (p *Parser) parseUnaryExpr() (Expr, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// parseRegex parses a regular expression.
|
||||
func (p *Parser) parseRegex() (Expr, error) {
|
||||
tok, pos, lit := p.s.s.ScanRegex()
|
||||
|
||||
if tok == BADESCAPE {
|
||||
msg := fmt.Sprintf("bad escape: %s", lit)
|
||||
return nil, &ParseError{Message: msg, Pos: pos}
|
||||
} else if tok == BADREGEX {
|
||||
msg := fmt.Sprintf("bad regex: %s", lit)
|
||||
return nil, &ParseError{Message: msg, Pos: pos}
|
||||
} else if tok != REGEX {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"regex"}, pos)
|
||||
}
|
||||
|
||||
re, err := regexp.Compile(lit)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Message: err.Error(), Pos: pos}
|
||||
}
|
||||
|
||||
return &RegexLiteral{Val: re}, nil
|
||||
}
|
||||
|
||||
// parseCall parses a function call.
|
||||
// This function assumes the function name and LPAREN have been consumed.
|
||||
func (p *Parser) parseCall(name string) (*Call, error) {
|
||||
|
|
|
@ -136,9 +136,9 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// SELECT * FROM cpu WHERE host = 'serverC' AND region =~ `.*west.*`
|
||||
// SELECT * FROM cpu WHERE host = 'serverC' AND region =~ /.*west.*/
|
||||
{
|
||||
s: "SELECT * FROM cpu WHERE host = 'serverC' AND region =~ `.*west.*`",
|
||||
s: `SELECT * FROM cpu WHERE host = 'serverC' AND region =~ /.*west.*/`,
|
||||
stmt: &influxql.SelectStatement{
|
||||
Fields: []*influxql.Field{{Expr: &influxql.Wildcard{}}},
|
||||
Source: &influxql.Measurement{Name: "cpu"},
|
||||
|
@ -861,9 +861,9 @@ func TestParser_ParseExpr(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// Binary expression with regex on right.
|
||||
// Binary expression with regex.
|
||||
{
|
||||
s: "region =~ `us.*`",
|
||||
s: "region =~ /us.*/",
|
||||
expr: &influxql.BinaryExpr{
|
||||
Op: influxql.EQREGEX,
|
||||
LHS: &influxql.VarRef{Val: "region"},
|
||||
|
@ -871,16 +871,6 @@ func TestParser_ParseExpr(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// Binary expression with NEQ regex on left.
|
||||
{
|
||||
s: "`us.*` !~ region",
|
||||
expr: &influxql.BinaryExpr{
|
||||
Op: influxql.NEQREGEX,
|
||||
RHS: &influxql.VarRef{Val: "region"},
|
||||
LHS: &influxql.RegexLiteral{Val: regexp.MustCompile(`us.*`)},
|
||||
},
|
||||
},
|
||||
|
||||
// Complex binary expression.
|
||||
{
|
||||
s: `value + 3 < 30 AND 1 + 2 OR true`,
|
||||
|
|
|
@ -95,8 +95,6 @@ func (s *Scanner) Scan() (tok Token, pos Pos, lit string) {
|
|||
return COMMA, pos, ""
|
||||
case ';':
|
||||
return SEMICOLON, pos, ""
|
||||
case '`':
|
||||
return s.scanRegex()
|
||||
}
|
||||
|
||||
return ILLEGAL, pos, string(ch0)
|
||||
|
@ -181,14 +179,13 @@ func (s *Scanner) scanString() (tok Token, pos Pos, lit string) {
|
|||
return STRING, pos, lit
|
||||
}
|
||||
|
||||
func (s *Scanner) scanRegex() (tok Token, pos Pos, lit string) {
|
||||
s.r.unread()
|
||||
func (s *Scanner) ScanRegex() (tok Token, pos Pos, lit string) {
|
||||
_, pos = s.r.curr()
|
||||
|
||||
// Start & end sentinels.
|
||||
start, end := '`', '`'
|
||||
start, end := '/', '/'
|
||||
// Valid escape chars.
|
||||
escapes := map[rune]rune{'`': '`'}
|
||||
escapes := map[rune]rune{'/': '/'}
|
||||
|
||||
b, err := ScanDelimited(s.r, start, end, escapes)
|
||||
|
||||
|
@ -322,6 +319,16 @@ func newBufScanner(r io.Reader) *bufScanner {
|
|||
|
||||
// Scan reads the next token from the scanner.
|
||||
func (s *bufScanner) Scan() (tok Token, pos Pos, lit string) {
|
||||
return s.scanFunc(s.s.Scan)
|
||||
}
|
||||
|
||||
// ScanRegex reads a regex token from the scanner.
|
||||
func (s *bufScanner) ScanRegex() (tok Token, pos Pos, lit string) {
|
||||
return s.scanFunc(s.s.ScanRegex)
|
||||
}
|
||||
|
||||
// scanFunc uses the provided function to scan the next token.
|
||||
func (s *bufScanner) scanFunc(scan func() (Token, Pos, string)) (tok Token, pos Pos, lit string) {
|
||||
// If we have unread tokens then read them off the buffer first.
|
||||
if s.n > 0 {
|
||||
s.n--
|
||||
|
@ -331,7 +338,7 @@ func (s *bufScanner) Scan() (tok Token, pos Pos, lit string) {
|
|||
// Move buffer position forward and save the token.
|
||||
s.i = (s.i + 1) % len(s.buf)
|
||||
buf := &s.buf[s.i]
|
||||
buf.tok, buf.pos, buf.lit = s.s.Scan()
|
||||
buf.tok, buf.pos, buf.lit = scan()
|
||||
|
||||
return s.curr()
|
||||
}
|
||||
|
@ -442,7 +449,7 @@ func ScanDelimited(r io.RuneScanner, start, end rune, escapes map[rune]rune) ([]
|
|||
if ch, _, err := r.ReadRune(); err != nil {
|
||||
return nil, err
|
||||
} else if ch != start {
|
||||
return nil, fmt.Errorf("expected %s; found %s", string(ch), string(start))
|
||||
return nil, fmt.Errorf("expected %s; found %s", string(start), string(ch))
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
|
|
@ -102,10 +102,6 @@ func TestScanner_Scan(t *testing.T) {
|
|||
{s: `10w`, tok: influxql.DURATION_VAL, lit: `10w`},
|
||||
{s: `10x`, tok: influxql.NUMBER, lit: `10`}, // non-duration unit
|
||||
|
||||
// Regular expressions
|
||||
{s: "`.*`", tok: influxql.REGEX, lit: ".*"},
|
||||
{s: "`.*\\``", tok: influxql.REGEX, lit: ".*`"},
|
||||
|
||||
// Keywords
|
||||
{s: `ALL`, tok: influxql.ALL},
|
||||
{s: `ALTER`, tok: influxql.ALTER},
|
||||
|
|
Loading…
Reference in New Issue