func TestParser_ParseStatement(t *testing.T) {
	now := time.Now()
	var tests = []struct {
		skip   bool
		s      string
		params map[string]interface{}
		stmt   influxql.Statement
		err    string
	}{
		{
			s: `SELECT * FROM myseries`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.Wildcard{}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: `SELECT * FROM myseries GROUP BY *`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.Wildcard{}},
				},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Wildcard{}}},
			},
		},
		{
			s: `SELECT field1, * FROM myseries GROUP BY *`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.VarRef{Val: "field1"}},
					{Expr: &influxql.Wildcard{}},
				},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Wildcard{}}},
			},
		},
		{
			s: `SELECT *, field1 FROM myseries GROUP BY *`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.Wildcard{}},
					{Expr: &influxql.VarRef{Val: "field1"}},
				},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Wildcard{}}},
			},
		},
		{
			s: fmt.Sprintf(`SELECT mean(field1), sum(field2), count(field3) AS field_x FROM myseries WHERE host = 'hosta.influxdb.org' and time > '%s' GROUP BY time(10h) ORDER BY DESC LIMIT 20 OFFSET 10;`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "mean", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}}}},
					{Expr: &influxql.Call{Name: "sum", Args: []influxql.Expr{&influxql.VarRef{Val: "field2"}}}},
					{Expr: &influxql.Call{Name: "count", Args: []influxql.Expr{&influxql.VarRef{Val: "field3"}}}, Alias: "field_x"},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Condition: &influxql.BinaryExpr{
					Op: influxql.AND,
					LHS: &influxql.BinaryExpr{
						Op:  influxql.EQ,
						LHS: &influxql.VarRef{Val: "host"},
						RHS: &influxql.StringLiteral{Val: "hosta.influxdb.org"},
					},
					RHS: &influxql.BinaryExpr{
						Op:  influxql.GT,
						LHS: &influxql.VarRef{Val: "time"},
						RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
					},
				},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 10 * time.Hour}}}}},
				SortFields: []*influxql.SortField{
					{Ascending: false},
				},
				Limit:  20,
				Offset: 10,
			},
		},
		{
			s: `SELECT "foo.bar.baz" AS foo FROM myseries`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.VarRef{Val: "foo.bar.baz"}, Alias: "foo"},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: `SELECT "foo.bar.baz" AS foo FROM foo`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.VarRef{Val: "foo.bar.baz"}, Alias: "foo"},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "foo"}},
			},
		},
		{
			s: `SELECT sample(field1, 100) FROM myseries;`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "sample", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.IntegerLiteral{Val: 100}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: `SELECT derivative(field1, 1h) FROM myseries;`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "derivative", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.DurationLiteral{Val: time.Hour}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: fmt.Sprintf(`SELECT derivative(field1, 1h) FROM myseries WHERE time > '%s'`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "derivative", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.DurationLiteral{Val: time.Hour}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: `SELECT derivative(field1, 1h) / derivative(field2, 1h) FROM myseries`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{
						Expr: &influxql.BinaryExpr{
							LHS: &influxql.Call{
								Name: "derivative",
								Args: []influxql.Expr{
									&influxql.VarRef{Val: "field1"},
									&influxql.DurationLiteral{Val: time.Hour},
								},
							},
							RHS: &influxql.Call{
								Name: "derivative",
								Args: []influxql.Expr{
									&influxql.VarRef{Val: "field2"},
									&influxql.DurationLiteral{Val: time.Hour},
								},
							},
							Op: influxql.DIV,
						},
					},
				},
				Sources: []influxql.Source{
					&influxql.Measurement{Name: "myseries"},
				},
			},
		},
		{
			s: `SELECT difference(field1) FROM myseries;`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "difference", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: fmt.Sprintf(`SELECT difference(max(field1)) FROM myseries WHERE time > '%s' GROUP BY time(1m)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{
						Expr: &influxql.Call{
							Name: "difference",
							Args: []influxql.Expr{
								&influxql.Call{
									Name: "max",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "field1"},
									},
								},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: time.Minute},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: `SELECT non_negative_difference(field1) FROM myseries;`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "non_negative_difference", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: fmt.Sprintf(`SELECT non_negative_difference(max(field1)) FROM myseries WHERE time > '%s' GROUP BY time(1m)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{
						Expr: &influxql.Call{
							Name: "non_negative_difference",
							Args: []influxql.Expr{
								&influxql.Call{
									Name: "max",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "field1"},
									},
								},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: time.Minute},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: `SELECT moving_average(field1, 3) FROM myseries;`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "moving_average", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.IntegerLiteral{Val: 3}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: fmt.Sprintf(`SELECT moving_average(max(field1), 3) FROM myseries WHERE time > '%s' GROUP BY time(1m)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{
						Expr: &influxql.Call{
							Name: "moving_average",
							Args: []influxql.Expr{
								&influxql.Call{
									Name: "max",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "field1"},
									},
								},
								&influxql.IntegerLiteral{Val: 3},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: time.Minute},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: fmt.Sprintf(`SELECT cumulative_sum(field1) FROM myseries WHERE time > '%s'`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{
					{
						Expr: &influxql.Call{
							Name: "cumulative_sum",
							Args: []influxql.Expr{
								&influxql.VarRef{Val: "field1"},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: fmt.Sprintf(`SELECT cumulative_sum(mean(field1)) FROM myseries WHERE time > '%s' GROUP BY time(1m)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{
					{
						Expr: &influxql.Call{
							Name: "cumulative_sum",
							Args: []influxql.Expr{
								&influxql.Call{
									Name: "mean",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "field1"},
									},
								},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: time.Minute},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: fmt.Sprintf(`SELECT holt_winters(first(field1), 3, 1) FROM myseries WHERE time > '%s' GROUP BY time(1h);`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{
						Name: "holt_winters",
						Args: []influxql.Expr{
							&influxql.Call{
								Name: "first",
								Args: []influxql.Expr{
									&influxql.VarRef{Val: "field1"},
								},
							},
							&influxql.IntegerLiteral{Val: 3},
							&influxql.IntegerLiteral{Val: 1},
						},
					}},
				},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: 1 * time.Hour},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: fmt.Sprintf(`SELECT holt_winters_with_fit(first(field1), 3, 1) FROM myseries WHERE time > '%s' GROUP BY time(1h);`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{
						Name: "holt_winters_with_fit",
						Args: []influxql.Expr{
							&influxql.Call{
								Name: "first",
								Args: []influxql.Expr{
									&influxql.VarRef{Val: "field1"},
								},
							},
							&influxql.IntegerLiteral{Val: 3},
							&influxql.IntegerLiteral{Val: 1},
						}}},
				},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: 1 * time.Hour},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: fmt.Sprintf(`SELECT holt_winters(max(field1), 4, 5) FROM myseries WHERE time > '%s' GROUP BY time(1m)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{
						Expr: &influxql.Call{
							Name: "holt_winters",
							Args: []influxql.Expr{
								&influxql.Call{
									Name: "max",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "field1"},
									},
								},
								&influxql.IntegerLiteral{Val: 4},
								&influxql.IntegerLiteral{Val: 5},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: time.Minute},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: fmt.Sprintf(`SELECT holt_winters_with_fit(max(field1), 4, 5) FROM myseries WHERE time > '%s' GROUP BY time(1m)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{
						Expr: &influxql.Call{
							Name: "holt_winters_with_fit",
							Args: []influxql.Expr{
								&influxql.Call{
									Name: "max",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "field1"},
									},
								},
								&influxql.IntegerLiteral{Val: 4},
								&influxql.IntegerLiteral{Val: 5},
							},
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				Dimensions: []*influxql.Dimension{
					{
						Expr: &influxql.Call{
							Name: "time",
							Args: []influxql.Expr{
								&influxql.DurationLiteral{Val: time.Minute},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: `select my_field from myseries`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.VarRef{Val: "my_field"}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			s: `select 'my_field' from myseries`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.StringLiteral{Val: "my_field"}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "myseries"}},
			},
		},
		{
			skip: true,
			s:    `SELECT field1 FROM myseries ORDER BY ASC, field1, field2 DESC LIMIT 10`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.VarRef{Val: "field1"}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				SortFields: []*influxql.SortField{
					{Ascending: true},
					{Name: "field1"},
					{Name: "field2"},
				},
				Limit: 10,
			},
		},
		{
			s: `SELECT field1 FROM myseries SLIMIT 10 SOFFSET 5`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.VarRef{Val: "field1"}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "myseries"}},
				SLimit:     10,
				SOffset:    5,
			},
		},
		{
			s: `SELECT * FROM cpu WHERE host = 'serverC' AND region =~ /.*west.*/`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op: influxql.AND,
					LHS: &influxql.BinaryExpr{
						Op:  influxql.EQ,
						LHS: &influxql.VarRef{Val: "host"},
						RHS: &influxql.StringLiteral{Val: "serverC"},
					},
					RHS: &influxql.BinaryExpr{
						Op:  influxql.EQREGEX,
						LHS: &influxql.VarRef{Val: "region"},
						RHS: &influxql.RegexLiteral{Val: regexp.MustCompile(".*west.*")},
					},
				},
			},
		},
		{
			s: `select percentile("field1", 2.0) from cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "percentile", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2.0}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `select percentile("field1", 2.0), field2 from cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "percentile", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2.0}}}},
					{Expr: &influxql.VarRef{Val: "field2"}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `select top("field1", 2) from cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.IntegerLiteral{Val: 2}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `select top(field1, 2) from cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.IntegerLiteral{Val: 2}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `select top(field1, 2), tag1 from cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.IntegerLiteral{Val: 2}}}},
					{Expr: &influxql.VarRef{Val: "tag1"}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `select top(field1, tag1, 2), tag1 from cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "tag1"}, &influxql.IntegerLiteral{Val: 2}}}},
					{Expr: &influxql.VarRef{Val: "tag1"}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `select distinct(field1) from cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "distinct", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `select distinct field2 from network`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.Distinct{Val: "field2"}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "network"}},
			},
		},
		{
			s: `select count(distinct field3) from metrics`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "count", Args: []influxql.Expr{&influxql.Distinct{Val: "field3"}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "metrics"}},
			},
		},
		{
			s: `select count(distinct field3), sum(field4) from metrics`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "count", Args: []influxql.Expr{&influxql.Distinct{Val: "field3"}}}},
					{Expr: &influxql.Call{Name: "sum", Args: []influxql.Expr{&influxql.VarRef{Val: "field4"}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "metrics"}},
			},
		},
		{
			s: `select count(distinct(field3)), sum(field4) from metrics`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "count", Args: []influxql.Expr{&influxql.Call{Name: "distinct", Args: []influxql.Expr{&influxql.VarRef{Val: "field3"}}}}}},
					{Expr: &influxql.Call{Name: "sum", Args: []influxql.Expr{&influxql.VarRef{Val: "field4"}}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "metrics"}},
			},
		},
		{
			s: fmt.Sprintf(`SELECT * FROM cpu WHERE time > '%s'`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
			},
		},
		{
			s: `SELECT * FROM cpu WHERE load > 100`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "load"},
					RHS: &influxql.IntegerLiteral{Val: 100},
				},
			},
		},
		{
			s: `SELECT * FROM cpu WHERE load >= 100`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GTE,
					LHS: &influxql.VarRef{Val: "load"},
					RHS: &influxql.IntegerLiteral{Val: 100},
				},
			},
		},
		{
			s: `SELECT * FROM cpu WHERE load = 100`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.EQ,
					LHS: &influxql.VarRef{Val: "load"},
					RHS: &influxql.IntegerLiteral{Val: 100},
				},
			},
		},
		{
			s: `SELECT * FROM cpu WHERE load <= 100`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.LTE,
					LHS: &influxql.VarRef{Val: "load"},
					RHS: &influxql.IntegerLiteral{Val: 100},
				},
			},
		},
		{
			s: `SELECT * FROM cpu WHERE load < 100`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.LT,
					LHS: &influxql.VarRef{Val: "load"},
					RHS: &influxql.IntegerLiteral{Val: 100},
				},
			},
		},
		{
			s: `SELECT * FROM cpu WHERE load != 100`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.NEQ,
					LHS: &influxql.VarRef{Val: "load"},
					RHS: &influxql.IntegerLiteral{Val: 100},
				},
			},
		},
		{
			s: `SELECT * FROM /cpu.*/`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources: []influxql.Source{&influxql.Measurement{
					Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
				},
			},
		},
		{
			s: `SELECT * FROM "db"."rp"./cpu.*/`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources: []influxql.Source{&influxql.Measurement{
					Database:        `db`,
					RetentionPolicy: `rp`,
					Regex:           &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
				},
			},
		},
		{
			s: `SELECT * FROM "db"../cpu.*/`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources: []influxql.Source{&influxql.Measurement{
					Database: `db`,
					Regex:    &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
				},
			},
		},
		{
			s: `SELECT * FROM "rp"./cpu.*/`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields:     []*influxql.Field{{Expr: &influxql.Wildcard{}}},
				Sources: []influxql.Source{&influxql.Measurement{
					RetentionPolicy: `rp`,
					Regex:           &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
				},
			},
		},
		{
			s: `SELECT sum(value) FROM "kbps" WHERE time > now() - 120s AND deliveryservice='steam-dns' and cachegroup = 'total' GROUP BY time(60s)`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: false,
				Fields: []*influxql.Field{
					{Expr: &influxql.Call{Name: "sum", Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}},
				},
				Sources:    []influxql.Source{&influxql.Measurement{Name: "kbps"}},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 60 * time.Second}}}}},
				Condition: &influxql.BinaryExpr{  
					Op: influxql.AND,
					LHS: &influxql.BinaryExpr{  
						Op: influxql.AND,
						LHS: &influxql.BinaryExpr{  
							Op:  influxql.GT,
							LHS: &influxql.VarRef{Val: "time"},
							RHS: &influxql.BinaryExpr{
								Op:  influxql.SUB,
								LHS: &influxql.Call{Name: "now"},
								RHS: &influxql.DurationLiteral{Val: mustParseDuration("120s")},
							},
						},
						RHS: &influxql.BinaryExpr{
							Op:  influxql.EQ,
							LHS: &influxql.VarRef{Val: "deliveryservice"},
							RHS: &influxql.StringLiteral{Val: "steam-dns"},
						},
					},
					RHS: &influxql.BinaryExpr{
						Op:  influxql.EQ,
						LHS: &influxql.VarRef{Val: "cachegroup"},
						RHS: &influxql.StringLiteral{Val: "total"},
					},
				},
			},
		},
		{
			s: fmt.Sprintf(`SELECT count(value) FROM cpu where time < '%s' group by time(500ms)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "count",
						Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.LT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 500 * time.Millisecond}}}}},
			},
		},
		{
			s: fmt.Sprintf(`SELECT mean(value) FROM cpu where time < '%s' GROUP BY time(5m) fill(1)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.LT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 5 * time.Minute}}}}},
				Fill:       influxql.NumberFill,
				FillValue:  int64(1),
			},
		},
		{
			s: fmt.Sprintf(`SELECT mean(value) FROM cpu where time < '%s' GROUP BY time(5m) FILL(none)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.LT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 5 * time.Minute}}}}},
				Fill:       influxql.NoFill,
			},
		},
		{
			s: fmt.Sprintf(`SELECT mean(value) FROM cpu where time < '%s' GROUP BY time(5m) FILL(previous)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.LT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 5 * time.Minute}}}}},
				Fill:       influxql.PreviousFill,
			},
		},
		{
			s: fmt.Sprintf(`SELECT mean(value) FROM cpu where time < '%s' GROUP BY time(5m) FILL(linear)`, now.UTC().Format(time.RFC3339Nano)),
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.LT,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.StringLiteral{Val: now.UTC().Format(time.RFC3339Nano)},
				},
				Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 5 * time.Minute}}}}},
				Fill:       influxql.LinearFill,
			},
		},
		{
			s: `SELECT field1::float, field2::integer, field6::unsigned, field3::string, field4::boolean, field5::field, tag1::tag FROM cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{
						Expr: &influxql.VarRef{
							Val:  "field1",
							Type: influxql.Float,
						},
					},
					{
						Expr: &influxql.VarRef{
							Val:  "field2",
							Type: influxql.Integer,
						},
					},
					{
						Expr: &influxql.VarRef{
							Val:  "field6",
							Type: influxql.Unsigned,
						},
					},
					{
						Expr: &influxql.VarRef{
							Val:  "field3",
							Type: influxql.String,
						},
					},
					{
						Expr: &influxql.VarRef{
							Val:  "field4",
							Type: influxql.Boolean,
						},
					},
					{
						Expr: &influxql.VarRef{
							Val:  "field5",
							Type: influxql.AnyField,
						},
					},
					{
						Expr: &influxql.VarRef{
							Val:  "tag1",
							Type: influxql.Tag,
						},
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT value FROM cpu WHERE value > $value`,
			params: map[string]interface{}{
				"value": int64(2),
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.VarRef{Val: "value"}}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "value"},
					RHS: &influxql.IntegerLiteral{Val: 2},
				},
			},
		},
		{
			s: `SELECT value FROM cpu WHERE value > $"multi-word value"`,
			params: map[string]interface{}{
				"multi-word value": int64(2),
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.VarRef{Val: "value"}}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GT,
					LHS: &influxql.VarRef{Val: "value"},
					RHS: &influxql.IntegerLiteral{Val: 2},
				},
			},
		},
		{
			s: `SELECT mean($field) FROM cpu`,
			params: map[string]interface{}{
				"field": map[string]interface{}{"identifier": "value"},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "value"},
						}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT $fn(value) FROM cpu`,
			params: map[string]interface{}{
				"fn": map[string]interface{}{"identifier": "mean"},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "value"},
						}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT mean(value) FROM cpu WHERE host =~ $host`,
			params: map[string]interface{}{
				"host": map[string]interface{}{"regex": "^server.*"},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "value"},
						}}},
				},
				Condition: &influxql.BinaryExpr{
					Op: influxql.EQREGEX,
					LHS: &influxql.VarRef{
						Val: "host",
					},
					RHS: &influxql.RegexLiteral{
						Val: regexp.MustCompile(`^server.*`),
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT $field::$type FROM cpu`,
			params: map[string]interface{}{
				"field": map[string]interface{}{"identifier": "value"},
				"type":  map[string]interface{}{"identifier": "integer"},
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.VarRef{
						Val:  "value",
						Type: influxql.Integer,
					}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT value FROM cpu WHERE value > $f`,
			params: map[string]interface{}{
				"f": map[string]interface{}{"float": 2.0},
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.VarRef{
						Val: "value",
					}},
				},
				Condition: &influxql.BinaryExpr{
					Op: influxql.GT,
					LHS: &influxql.VarRef{
						Val: "value",
					},
					RHS: &influxql.NumberLiteral{
						Val: 2,
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT value FROM cpu WHERE value > $f`,
			params: map[string]interface{}{
				"f": map[string]interface{}{"float": int64(2)},
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.VarRef{
						Val: "value",
					}},
				},
				Condition: &influxql.BinaryExpr{
					Op: influxql.GT,
					LHS: &influxql.VarRef{
						Val: "value",
					},
					RHS: &influxql.NumberLiteral{
						Val: 2,
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT value FROM cpu WHERE value > $i`,
			params: map[string]interface{}{
				"i": map[string]interface{}{"integer": int64(2)},
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.VarRef{
						Val: "value",
					}},
				},
				Condition: &influxql.BinaryExpr{
					Op: influxql.GT,
					LHS: &influxql.VarRef{
						Val: "value",
					},
					RHS: &influxql.IntegerLiteral{
						Val: 2,
					},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT mean(value) FROM cpu GROUP BY time($interval)`,
			params: map[string]interface{}{
				"interval": map[string]interface{}{"duration": "10s"},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "value"},
						},
					}},
				},
				Dimensions: []*influxql.Dimension{{
					Expr: &influxql.Call{
						Name: "time",
						Args: []influxql.Expr{
							&influxql.DurationLiteral{Val: 10 * time.Second},
						},
					},
				}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT mean(value) FROM cpu GROUP BY time($interval)`,
			params: map[string]interface{}{
				"interval": map[string]interface{}{"duration": int64(10 * time.Second)},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "value"},
						},
					}},
				},
				Dimensions: []*influxql.Dimension{{
					Expr: &influxql.Call{
						Name: "time",
						Args: []influxql.Expr{
							&influxql.DurationLiteral{Val: 10 * time.Second},
						},
					},
				}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT mean(value) FROM cpu GROUP BY time($interval)`,
			params: map[string]interface{}{
				"interval": map[string]interface{}{"duration": int64(10)},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "value"},
						},
					}},
				},
				Dimensions: []*influxql.Dimension{{
					Expr: &influxql.Call{
						Name: "time",
						Args: []influxql.Expr{
							&influxql.DurationLiteral{Val: 10},
						},
					},
				}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT mean(value) FROM cpu GROUP BY time($interval)`,
			params: map[string]interface{}{
				"interval": map[string]interface{}{"duration": json.Number("10")},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "mean",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "value"},
						},
					}},
				},
				Dimensions: []*influxql.Dimension{{
					Expr: &influxql.Call{
						Name: "time",
						Args: []influxql.Expr{
							&influxql.DurationLiteral{Val: 10},
						},
					},
				}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT sum(derivative) FROM (SELECT derivative(value) FROM cpu GROUP BY host) WHERE time >= now() - 1d GROUP BY time(1h)`,
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "sum",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "derivative"},
						}},
				}},
				Dimensions: []*influxql.Dimension{{
					Expr: &influxql.Call{
						Name: "time",
						Args: []influxql.Expr{
							&influxql.DurationLiteral{Val: time.Hour},
						},
					},
				}},
				Sources: []influxql.Source{
					&influxql.SubQuery{
						Statement: &influxql.SelectStatement{
							Fields: []*influxql.Field{{
								Expr: &influxql.Call{
									Name: "derivative",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "value"},
									},
								},
							}},
							Dimensions: []*influxql.Dimension{{
								Expr: &influxql.VarRef{Val: "host"},
							}},
							Sources: []influxql.Source{
								&influxql.Measurement{Name: "cpu"},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GTE,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.BinaryExpr{
						Op:  influxql.SUB,
						LHS: &influxql.Call{Name: "now"},
						RHS: &influxql.DurationLiteral{Val: 24 * time.Hour},
					},
				},
			},
		},
		{
			s: `SELECT sum(mean) FROM (SELECT mean(value) FROM cpu GROUP BY time(1h)) WHERE time >= now() - 1d`,
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "sum",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "mean"},
						}},
				}},
				Sources: []influxql.Source{
					&influxql.SubQuery{
						Statement: &influxql.SelectStatement{
							Fields: []*influxql.Field{{
								Expr: &influxql.Call{
									Name: "mean",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "value"},
									},
								},
							}},
							Dimensions: []*influxql.Dimension{{
								Expr: &influxql.Call{
									Name: "time",
									Args: []influxql.Expr{
										&influxql.DurationLiteral{Val: time.Hour},
									},
								},
							}},
							Sources: []influxql.Source{
								&influxql.Measurement{Name: "cpu"},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GTE,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.BinaryExpr{
						Op:  influxql.SUB,
						LHS: &influxql.Call{Name: "now"},
						RHS: &influxql.DurationLiteral{Val: 24 * time.Hour},
					},
				},
			},
		},
		{
			s: `SELECT sum(mean) FROM (SELECT mean(value) FROM cpu WHERE time >= now() - 1d GROUP BY time(1h))`,
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "sum",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "mean"},
						}},
				}},
				Sources: []influxql.Source{
					&influxql.SubQuery{
						Statement: &influxql.SelectStatement{
							Fields: []*influxql.Field{{
								Expr: &influxql.Call{
									Name: "mean",
									Args: []influxql.Expr{
										&influxql.VarRef{Val: "value"},
									},
								},
							}},
							Dimensions: []*influxql.Dimension{{
								Expr: &influxql.Call{
									Name: "time",
									Args: []influxql.Expr{
										&influxql.DurationLiteral{Val: time.Hour},
									},
								},
							}},
							Condition: &influxql.BinaryExpr{
								Op:  influxql.GTE,
								LHS: &influxql.VarRef{Val: "time"},
								RHS: &influxql.BinaryExpr{
									Op:  influxql.SUB,
									LHS: &influxql.Call{Name: "now"},
									RHS: &influxql.DurationLiteral{Val: 24 * time.Hour},
								},
							},
							Sources: []influxql.Source{
								&influxql.Measurement{Name: "cpu"},
							},
						},
					},
				},
			},
		},
		{
			s: `SELECT sum(derivative) FROM (SELECT derivative(mean(value)) FROM cpu GROUP BY host) WHERE time >= now() - 1d GROUP BY time(1h)`,
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "sum",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "derivative"},
						}},
				}},
				Dimensions: []*influxql.Dimension{{
					Expr: &influxql.Call{
						Name: "time",
						Args: []influxql.Expr{
							&influxql.DurationLiteral{Val: time.Hour},
						},
					},
				}},
				Sources: []influxql.Source{
					&influxql.SubQuery{
						Statement: &influxql.SelectStatement{
							Fields: []*influxql.Field{{
								Expr: &influxql.Call{
									Name: "derivative",
									Args: []influxql.Expr{
										&influxql.Call{
											Name: "mean",
											Args: []influxql.Expr{
												&influxql.VarRef{Val: "value"},
											},
										},
									},
								},
							}},
							Dimensions: []*influxql.Dimension{{
								Expr: &influxql.VarRef{Val: "host"},
							}},
							Sources: []influxql.Source{
								&influxql.Measurement{Name: "cpu"},
							},
						},
					},
				},
				Condition: &influxql.BinaryExpr{
					Op:  influxql.GTE,
					LHS: &influxql.VarRef{Val: "time"},
					RHS: &influxql.BinaryExpr{
						Op:  influxql.SUB,
						LHS: &influxql.Call{Name: "now"},
						RHS: &influxql.DurationLiteral{Val: 24 * time.Hour},
					},
				},
			},
		},
		{
			s: `SELECT "user"   FROM cpu`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.VarRef{Val: "user"}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
			},
		},
		{
			s: `SELECT /foo\  WHERE x = 1`,
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{
					{Expr: &influxql.RegexLiteral{Val: regexp.MustCompile(`foo  GROUP BY time(1m) END`,
			stmt: &influxql.CreateContinuousQueryStatement{
				Name:     "myquery",
				Database: "testdb",
				Source: &influxql.SelectStatement{
					Fields: []*influxql.Field{{Expr: &influxql.Call{Name: "mean", Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}}},
					Target: &influxql.Target{
						Measurement: &influxql.Measurement{RetentionPolicy: "policy1", IsTarget: true},
					},
					Sources: []influxql.Source{&influxql.Measurement{Regex: &influxql.RegexLiteral{Val: regexp.MustCompile(`^[a-z]+.*`)}}},
					Dimensions: []*influxql.Dimension{
						{
							Expr: &influxql.Call{
								Name: "time",
								Args: []influxql.Expr{
									&influxql.DurationLiteral{Val: 1 * time.Minute},
								},
							},
						},
					},
				},
			},
		},
		{
			s: `CREATE DATABASE testdb`,
			stmt: &influxql.CreateDatabaseStatement{
				Name:                  "testdb",
				RetentionPolicyCreate: false,
			},
		},
		{
			s: `CREATE DATABASE testdb WITH DURATION 24h`,
			stmt: &influxql.CreateDatabaseStatement{
				Name:                    "testdb",
				RetentionPolicyCreate:   true,
				RetentionPolicyDuration: duration(24 * time.Hour),
			},
		},
		{
			s: `CREATE DATABASE testdb WITH SHARD DURATION 30m`,
			stmt: &influxql.CreateDatabaseStatement{
				Name:                              "testdb",
				RetentionPolicyCreate:             true,
				RetentionPolicyShardGroupDuration: 30 * time.Minute,
			},
		},
		{
			s: `CREATE DATABASE testdb WITH REPLICATION 2`,
			stmt: &influxql.CreateDatabaseStatement{
				Name:                       "testdb",
				RetentionPolicyCreate:      true,
				RetentionPolicyReplication: intptr(2),
			},
		},
		{
			s: `CREATE DATABASE testdb WITH NAME test_name`,
			stmt: &influxql.CreateDatabaseStatement{
				Name:                  "testdb",
				RetentionPolicyCreate: true,
				RetentionPolicyName:   "test_name",
			},
		},
		{
			s: `CREATE DATABASE testdb WITH DURATION 24h REPLICATION 2 NAME test_name`,
			stmt: &influxql.CreateDatabaseStatement{
				Name:                       "testdb",
				RetentionPolicyCreate:      true,
				RetentionPolicyDuration:    duration(24 * time.Hour),
				RetentionPolicyReplication: intptr(2),
				RetentionPolicyName:        "test_name",
			},
		},
		{
			s: `CREATE DATABASE testdb WITH DURATION 24h REPLICATION 2 SHARD DURATION 10m NAME test_name `,
			stmt: &influxql.CreateDatabaseStatement{
				Name:                              "testdb",
				RetentionPolicyCreate:             true,
				RetentionPolicyDuration:           duration(24 * time.Hour),
				RetentionPolicyReplication:        intptr(2),
				RetentionPolicyName:               "test_name",
				RetentionPolicyShardGroupDuration: 10 * time.Minute,
			},
		},
		{
			s: `CREATE USER testuser WITH PASSWORD 'pwd1337'`,
			stmt: &influxql.CreateUserStatement{
				Name:     "testuser",
				Password: "pwd1337",
			},
		},
		{
			s: `CREATE USER testuser WITH PASSWORD 'pwd1337' WITH ALL PRIVILEGES`,
			stmt: &influxql.CreateUserStatement{
				Name:     "testuser",
				Password: "pwd1337",
				Admin:    true,
			},
		},
		{
			s: `SET PASSWORD FOR testuser = 'pwd1337'`,
			stmt: &influxql.SetPasswordUserStatement{
				Name:     "testuser",
				Password: "pwd1337",
			},
		},
		{
			s:    `DROP CONTINUOUS QUERY myquery ON foo`,
			stmt: &influxql.DropContinuousQueryStatement{Name: "myquery", Database: "foo"},
		},
		{
			s: `DROP DATABASE testdb`,
			stmt: &influxql.DropDatabaseStatement{
				Name: "testdb",
			},
		},
		{
			s:    `DROP MEASUREMENT cpu`,
			stmt: &influxql.DropMeasurementStatement{Name: "cpu"},
		},
		{
			s: `DROP RETENTION POLICY "1h.cpu" ON mydb`,
			stmt: &influxql.DropRetentionPolicyStatement{
				Name:     `1h.cpu`,
				Database: `mydb`,
			},
		},
		{
			s:    `DROP USER jdoe`,
			stmt: &influxql.DropUserStatement{Name: "jdoe"},
		},
		{
			s: `GRANT READ ON testdb TO jdoe`,
			stmt: &influxql.GrantStatement{
				Privilege: influxql.ReadPrivilege,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `GRANT WRITE ON testdb TO jdoe`,
			stmt: &influxql.GrantStatement{
				Privilege: influxql.WritePrivilege,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `GRANT ALL ON testdb TO jdoe`,
			stmt: &influxql.GrantStatement{
				Privilege: influxql.AllPrivileges,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `GRANT ALL PRIVILEGES ON testdb TO jdoe`,
			stmt: &influxql.GrantStatement{
				Privilege: influxql.AllPrivileges,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `GRANT ALL TO jdoe`,
			stmt: &influxql.GrantAdminStatement{
				User: "jdoe",
			},
		},
		{
			s: `GRANT ALL PRIVILEGES TO jdoe`,
			stmt: &influxql.GrantAdminStatement{
				User: "jdoe",
			},
		},
		{
			s: `REVOKE READ on testdb FROM jdoe`,
			stmt: &influxql.RevokeStatement{
				Privilege: influxql.ReadPrivilege,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `REVOKE WRITE ON testdb FROM jdoe`,
			stmt: &influxql.RevokeStatement{
				Privilege: influxql.WritePrivilege,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `REVOKE ALL ON testdb FROM jdoe`,
			stmt: &influxql.RevokeStatement{
				Privilege: influxql.AllPrivileges,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `REVOKE ALL PRIVILEGES ON testdb FROM jdoe`,
			stmt: &influxql.RevokeStatement{
				Privilege: influxql.AllPrivileges,
				On:        "testdb",
				User:      "jdoe",
			},
		},
		{
			s: `REVOKE ALL FROM jdoe`,
			stmt: &influxql.RevokeAdminStatement{
				User: "jdoe",
			},
		},
		{
			s: `REVOKE ALL PRIVILEGES FROM jdoe`,
			stmt: &influxql.RevokeAdminStatement{
				User: "jdoe",
			},
		},
		{
			s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION 2`,
			stmt: &influxql.CreateRetentionPolicyStatement{
				Name:        "policy1",
				Database:    "testdb",
				Duration:    time.Hour,
				Replication: 2,
			},
		},
		{
			s: `CREATE RETENTION POLICY policy1 ON testdb DURATION INF REPLICATION 2`,
			stmt: &influxql.CreateRetentionPolicyStatement{
				Name:        "policy1",
				Database:    "testdb",
				Duration:    0,
				Replication: 2,
			},
		},
		{
			s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 2m REPLICATION 4 DEFAULT`,
			stmt: &influxql.CreateRetentionPolicyStatement{
				Name:        "policy1",
				Database:    "testdb",
				Duration:    2 * time.Minute,
				Replication: 4,
				Default:     true,
			},
		},
		{
			s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION 2 SHARD DURATION 30m`,
			stmt: &influxql.CreateRetentionPolicyStatement{
				Name:               "policy1",
				Database:           "testdb",
				Duration:           time.Hour,
				Replication:        2,
				ShardGroupDuration: 30 * time.Minute,
			},
		},
		{
			s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION 2 SHARD DURATION 0s`,
			stmt: &influxql.CreateRetentionPolicyStatement{
				Name:               "policy1",
				Database:           "testdb",
				Duration:           time.Hour,
				Replication:        2,
				ShardGroupDuration: 0,
			},
		},
		{
			s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION 2 SHARD DURATION 1s`,
			stmt: &influxql.CreateRetentionPolicyStatement{
				Name:               "policy1",
				Database:           "testdb",
				Duration:           time.Hour,
				Replication:        2,
				ShardGroupDuration: time.Second,
			},
		},
		{
			s:    `ALTER RETENTION POLICY policy1 ON testdb DURATION 1m REPLICATION 4 DEFAULT`,
			stmt: newAlterRetentionPolicyStatement("policy1", "testdb", time.Minute, -1, 4, true),
		},
		{
			s:    `ALTER RETENTION POLICY policy1 ON testdb DEFAULT REPLICATION 4 DURATION 1m`,
			stmt: newAlterRetentionPolicyStatement("policy1", "testdb", time.Minute, -1, 4, true),
		},
		{
			s:    `ALTER RETENTION POLICY policy1 ON testdb DEFAULT REPLICATION 4 DURATION INF`,
			stmt: newAlterRetentionPolicyStatement("policy1", "testdb", 0, -1, 4, true),
		},
		{
			s:    `ALTER RETENTION POLICY policy1 ON testdb DEFAULT REPLICATION 4`,
			stmt: newAlterRetentionPolicyStatement("policy1", "testdb", -1, -1, 4, true),
		},
		{
			s:    `ALTER RETENTION POLICY policy1 ON testdb DEFAULT`,
			stmt: newAlterRetentionPolicyStatement("policy1", "testdb", -1, -1, -1, true),
		},
		{
			s:    `ALTER RETENTION POLICY policy1 ON testdb REPLICATION 4`,
			stmt: newAlterRetentionPolicyStatement("policy1", "testdb", -1, -1, 4, false),
		},
		{
			s:    `ALTER RETENTION POLICY default ON testdb REPLICATION 4`,
			stmt: newAlterRetentionPolicyStatement("default", "testdb", -1, -1, 4, false),
		},
		{
			s:    `ALTER RETENTION POLICY policy1 ON testdb REPLICATION 4 SHARD DURATION 10m`,
			stmt: newAlterRetentionPolicyStatement("policy1", "testdb", -1, 10*time.Minute, 4, false),
		},
		{
			s:    `ALTER RETENTION POLICY default ON testdb DURATION 0s REPLICATION 4 SHARD DURATION 10m DEFAULT`,
			stmt: newAlterRetentionPolicyStatement("default", "testdb", time.Duration(0), 10*time.Minute, 4, true),
		},
		{
			s:    `ALTER RETENTION POLICY default ON testdb DURATION 0s REPLICATION 1 SHARD DURATION 0s`,
			stmt: newAlterRetentionPolicyStatement("default", "testdb", time.Duration(0), 0, 1, false),
		},
		{
			s: `SHOW STATS`,
			stmt: &influxql.ShowStatsStatement{
				Module: "",
			},
		},
		{
			s: `SHOW STATS FOR 'cluster'`,
			stmt: &influxql.ShowStatsStatement{
				Module: "cluster",
			},
		},
		{
			s:    `SHOW SHARD GROUPS`,
			stmt: &influxql.ShowShardGroupsStatement{},
		},
		{
			s:    `SHOW SHARDS`,
			stmt: &influxql.ShowShardsStatement{},
		},
		{
			s:    `SHOW DIAGNOSTICS`,
			stmt: &influxql.ShowDiagnosticsStatement{},
		},
		{
			s: `SHOW DIAGNOSTICS FOR 'build'`,
			stmt: &influxql.ShowDiagnosticsStatement{
				Module: "build",
			},
		},
		{
			s: `CREATE SUBSCRIPTION "name" ON "db"."rp" DESTINATIONS ANY 'udp://host1:9093', 'udp://host2:9093'`,
			stmt: &influxql.CreateSubscriptionStatement{
				Name:            "name",
				Database:        "db",
				RetentionPolicy: "rp",
				Destinations:    []string{"udp://host1:9093", "udp://host2:9093"},
				Mode:            "ANY",
			},
		},
		{
			s: `DROP SUBSCRIPTION "name" ON "db"."rp"`,
			stmt: &influxql.DropSubscriptionStatement{
				Name:            "name",
				Database:        "db",
				RetentionPolicy: "rp",
			},
		},
		{
			s:    `SHOW SUBSCRIPTIONS`,
			stmt: &influxql.ShowSubscriptionsStatement{},
		},
		{s: ``, err: `found EOF, expected SELECT, DELETE, SHOW, CREATE, DROP, EXPLAIN, GRANT, REVOKE, ALTER, SET, KILL at line 1, char 1`},
		{s: `SELECT`, err: `found EOF, expected identifier, string, number, bool at line 1, char 8`},
		{s: `blah blah`, err: `found blah, expected SELECT, DELETE, SHOW, CREATE, DROP, EXPLAIN, GRANT, REVOKE, ALTER, SET, KILL at line 1, char 1`},
		{s: `SELECT field1 X`, err: `found X, expected FROM at line 1, char 15`},
		{s: `SELECT field1 FROM "series" WHERE X +;`, err: `found ;, expected identifier, string, number, bool at line 1, char 38`},
		{s: `SELECT field1 FROM myseries GROUP`, err: `found EOF, expected BY at line 1, char 35`},
		{s: `SELECT field1 FROM myseries LIMIT`, err: `found EOF, expected integer at line 1, char 35`},
		{s: `SELECT field1 FROM myseries LIMIT 10.5`, err: `found 10.5, expected integer at line 1, char 35`},
		{s: `SELECT field1 FROM myseries OFFSET`, err: `found EOF, expected integer at line 1, char 36`},
		{s: `SELECT field1 FROM myseries OFFSET 10.5`, err: `found 10.5, expected integer at line 1, char 36`},
		{s: `SELECT field1 FROM myseries ORDER`, err: `found EOF, expected BY at line 1, char 35`},
		{s: `SELECT field1 FROM myseries ORDER BY`, err: `found EOF, expected identifier, ASC, DESC at line 1, char 38`},
		{s: `SELECT field1 FROM myseries ORDER BY /`, err: `found /, expected identifier, ASC, DESC at line 1, char 38`},
		{s: `SELECT field1 FROM myseries ORDER BY 1`, err: `found 1, expected identifier, ASC, DESC at line 1, char 38`},
		{s: `SELECT field1 FROM myseries ORDER BY time ASC,`, err: `found EOF, expected identifier at line 1, char 47`},
		{s: `SELECT field1 FROM myseries ORDER BY time, field1`, err: `only ORDER BY time supported at this time`},
		{s: `SELECT field1 AS`, err: `found EOF, expected identifier at line 1, char 18`},
		{s: `SELECT field1 FROM 12`, err: `found 12, expected identifier at line 1, char 20`},
		{s: `SELECT 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 FROM myseries`, err: `unable to parse integer at line 1, char 8`},
		{s: `SELECT 10.5h FROM myseries`, err: `found h, expected FROM at line 1, char 12`},
		{s: `SELECT distinct FROM myseries`, err: `found FROM, expected identifier at line 1, char 17`},
		{s: `SELECT count(distinct) FROM myseries`, err: `found ), expected (, identifier at line 1, char 22`},
		{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: `SELECT mean(value) FROM cpu FILL + value`, err: `fill must be a function call`},
		{s: `DELETE`, err: `found EOF, expected FROM, WHERE at line 1, char 8`},
		{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 "foo".myseries`, err: `retention policy not supported at line 1, char 1`},
		{s: `DELETE FROM foo..myseries`, err: `database not supported at line 1, char 1`},
		{s: `DROP MEASUREMENT`, err: `found EOF, expected identifier at line 1, char 18`},
		{s: `DROP SERIES`, err: `found EOF, expected FROM, WHERE at line 1, char 13`},
		{s: `DROP SERIES FROM`, err: `found EOF, expected identifier at line 1, char 18`},
		{s: `DROP SERIES FROM src WHERE`, err: `found EOF, expected identifier, string, number, bool at line 1, char 28`},
		{s: `DROP SERIES FROM "foo".myseries`, err: `retention policy not supported at line 1, char 1`},
		{s: `DROP SERIES FROM foo..myseries`, err: `database not supported at line 1, char 1`},
		{s: `SHOW CONTINUOUS`, err: `found EOF, expected QUERIES at line 1, char 17`},
		{s: `SHOW RETENTION`, err: `found EOF, expected POLICIES at line 1, char 16`},
		{s: `SHOW RETENTION ON`, err: `found ON, expected POLICIES at line 1, char 16`},
		{s: `SHOW RETENTION POLICIES ON`, err: `found EOF, expected identifier at line 1, char 28`},
		{s: `SHOW SHARD`, err: `found EOF, expected GROUPS at line 1, char 12`},
		{s: `SHOW FOO`, err: `found FOO, expected CONTINUOUS, DATABASES, DIAGNOSTICS, FIELD, GRANTS, MEASUREMENT, MEASUREMENTS, QUERIES, RETENTION, SERIES, SHARD, SHARDS, STATS, SUBSCRIPTIONS, TAG, USERS at line 1, char 6`},
		{s: `SHOW STATS FOR`, err: `found EOF, expected string at line 1, char 16`},
		{s: `SHOW DIAGNOSTICS FOR`, err: `found EOF, expected string at line 1, char 22`},
		{s: `SHOW GRANTS`, err: `found EOF, expected FOR at line 1, char 13`},
		{s: `SHOW GRANTS FOR`, err: `found EOF, expected identifier at line 1, char 17`},
		{s: `DROP CONTINUOUS`, err: `found EOF, expected QUERY at line 1, char 17`},
		{s: `DROP CONTINUOUS QUERY`, err: `found EOF, expected identifier at line 1, char 23`},
		{s: `DROP CONTINUOUS QUERY myquery`, err: `found EOF, expected ON at line 1, char 31`},
		{s: `DROP CONTINUOUS QUERY myquery ON`, err: `found EOF, expected identifier at line 1, char 34`},
		{s: `CREATE CONTINUOUS`, err: `found EOF, expected QUERY at line 1, char 19`},
		{s: `CREATE CONTINUOUS QUERY`, err: `found EOF, expected identifier at line 1, char 25`},
		{s: `CREATE CONTINUOUS QUERY cq ON db RESAMPLE FOR 5s BEGIN SELECT mean(value) INTO cpu_mean FROM cpu GROUP BY time(10s) END`, err: `FOR duration must be >= GROUP BY time duration: must be a minimum of 10s, got 5s`},
		{s: `CREATE CONTINUOUS QUERY cq ON db RESAMPLE EVERY 10s FOR 5s BEGIN SELECT mean(value) INTO cpu_mean FROM cpu GROUP BY time(5s) END`, err: `FOR duration must be >= GROUP BY time duration: must be a minimum of 10s, got 5s`},
		{s: `DROP FOO`, err: `found FOO, expected CONTINUOUS, DATABASE, MEASUREMENT, RETENTION, SERIES, SHARD, SUBSCRIPTION, USER at line 1, char 6`},
		{s: `CREATE FOO`, err: `found FOO, expected CONTINUOUS, DATABASE, USER, RETENTION, SUBSCRIPTION at line 1, char 8`},
		{s: `CREATE DATABASE`, err: `found EOF, expected identifier at line 1, char 17`},
		{s: `CREATE DATABASE "testdb" WITH`, err: `found EOF, expected DURATION, NAME, REPLICATION, SHARD at line 1, char 31`},
		{s: `CREATE DATABASE "testdb" WITH DURATION`, err: `found EOF, expected duration at line 1, char 40`},
		{s: `CREATE DATABASE "testdb" WITH REPLICATION`, err: `found EOF, expected integer at line 1, char 43`},
		{s: `CREATE DATABASE "testdb" WITH NAME`, err: `found EOF, expected identifier at line 1, char 36`},
		{s: `CREATE DATABASE "testdb" WITH SHARD`, err: `found EOF, expected DURATION at line 1, char 37`},
		{s: `DROP DATABASE`, err: `found EOF, expected identifier at line 1, char 15`},
		{s: `DROP RETENTION`, err: `found EOF, expected POLICY at line 1, char 16`},
		{s: `DROP RETENTION POLICY`, err: `found EOF, expected identifier at line 1, char 23`},
		{s: `DROP RETENTION POLICY "1h.cpu"`, err: `found EOF, expected ON at line 1, char 31`},
		{s: `DROP RETENTION POLICY "1h.cpu" ON`, err: `found EOF, expected identifier at line 1, char 35`},
		{s: `DROP USER`, err: `found EOF, expected identifier at line 1, char 11`},
		{s: `DROP SUBSCRIPTION`, err: `found EOF, expected identifier at line 1, char 19`},
		{s: `DROP SUBSCRIPTION "name"`, err: `found EOF, expected ON at line 1, char 25`},
		{s: `DROP SUBSCRIPTION "name" ON `, err: `found EOF, expected identifier at line 1, char 30`},
		{s: `DROP SUBSCRIPTION "name" ON "db"`, err: `found EOF, expected . at line 1, char 33`},
		{s: `DROP SUBSCRIPTION "name" ON "db".`, err: `found EOF, expected identifier at line 1, char 34`},
		{s: `CREATE USER testuser`, err: `found EOF, expected WITH at line 1, char 22`},
		{s: `CREATE USER testuser WITH`, err: `found EOF, expected PASSWORD at line 1, char 27`},
		{s: `CREATE USER testuser WITH PASSWORD`, err: `found EOF, expected string at line 1, char 36`},
		{s: `CREATE USER testuser WITH PASSWORD 'pwd' WITH`, err: `found EOF, expected ALL at line 1, char 47`},
		{s: `CREATE USER testuser WITH PASSWORD 'pwd' WITH ALL`, err: `found EOF, expected PRIVILEGES at line 1, char 51`},
		{s: `CREATE SUBSCRIPTION`, err: `found EOF, expected identifier at line 1, char 21`},
		{s: `CREATE SUBSCRIPTION "name"`, err: `found EOF, expected ON at line 1, char 27`},
		{s: `CREATE SUBSCRIPTION "name" ON `, err: `found EOF, expected identifier at line 1, char 32`},
		{s: `CREATE SUBSCRIPTION "name" ON "db"`, err: `found EOF, expected . at line 1, char 35`},
		{s: `CREATE SUBSCRIPTION "name" ON "db".`, err: `found EOF, expected identifier at line 1, char 36`},
		{s: `CREATE SUBSCRIPTION "name" ON "db"."rp"`, err: `found EOF, expected DESTINATIONS at line 1, char 40`},
		{s: `CREATE SUBSCRIPTION "name" ON "db"."rp" DESTINATIONS`, err: `found EOF, expected ALL, ANY at line 1, char 54`},
		{s: `CREATE SUBSCRIPTION "name" ON "db"."rp" DESTINATIONS ALL `, err: `found EOF, expected string at line 1, char 59`},
		{s: `GRANT`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
		{s: `GRANT BOGUS`, err: `found BOGUS, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
		{s: `GRANT READ`, err: `found EOF, expected ON at line 1, char 12`},
		{s: `GRANT READ FROM`, err: `found FROM, expected ON at line 1, char 12`},
		{s: `GRANT READ ON`, err: `found EOF, expected identifier at line 1, char 15`},
		{s: `GRANT READ ON TO`, err: `found TO, expected identifier at line 1, char 15`},
		{s: `GRANT READ ON testdb`, err: `found EOF, expected TO at line 1, char 22`},
		{s: `GRANT READ ON testdb TO`, err: `found EOF, expected identifier at line 1, char 25`},
		{s: `GRANT READ TO`, err: `found TO, expected ON at line 1, char 12`},
		{s: `GRANT WRITE`, err: `found EOF, expected ON at line 1, char 13`},
		{s: `GRANT WRITE FROM`, err: `found FROM, expected ON at line 1, char 13`},
		{s: `GRANT WRITE ON`, err: `found EOF, expected identifier at line 1, char 16`},
		{s: `GRANT WRITE ON TO`, err: `found TO, expected identifier at line 1, char 16`},
		{s: `GRANT WRITE ON testdb`, err: `found EOF, expected TO at line 1, char 23`},
		{s: `GRANT WRITE ON testdb TO`, err: `found EOF, expected identifier at line 1, char 26`},
		{s: `GRANT WRITE TO`, err: `found TO, expected ON at line 1, char 13`},
		{s: `GRANT ALL`, err: `found EOF, expected ON, TO at line 1, char 11`},
		{s: `GRANT ALL PRIVILEGES`, err: `found EOF, expected ON, TO at line 1, char 22`},
		{s: `GRANT ALL FROM`, err: `found FROM, expected ON, TO at line 1, char 11`},
		{s: `GRANT ALL PRIVILEGES FROM`, err: `found FROM, expected ON, TO at line 1, char 22`},
		{s: `GRANT ALL ON`, err: `found EOF, expected identifier at line 1, char 14`},
		{s: `GRANT ALL PRIVILEGES ON`, err: `found EOF, expected identifier at line 1, char 25`},
		{s: `GRANT ALL ON TO`, err: `found TO, expected identifier at line 1, char 14`},
		{s: `GRANT ALL PRIVILEGES ON TO`, err: `found TO, expected identifier at line 1, char 25`},
		{s: `GRANT ALL ON testdb`, err: `found EOF, expected TO at line 1, char 21`},
		{s: `GRANT ALL PRIVILEGES ON testdb`, err: `found EOF, expected TO at line 1, char 32`},
		{s: `GRANT ALL ON testdb FROM`, err: `found FROM, expected TO at line 1, char 21`},
		{s: `GRANT ALL PRIVILEGES ON testdb FROM`, err: `found FROM, expected TO at line 1, char 32`},
		{s: `GRANT ALL ON testdb TO`, err: `found EOF, expected identifier at line 1, char 24`},
		{s: `GRANT ALL PRIVILEGES ON testdb TO`, err: `found EOF, expected identifier at line 1, char 35`},
		{s: `GRANT ALL TO`, err: `found EOF, expected identifier at line 1, char 14`},
		{s: `GRANT ALL PRIVILEGES TO`, err: `found EOF, expected identifier at line 1, char 25`},
		{s: `KILL`, err: `found EOF, expected QUERY at line 1, char 6`},
		{s: `KILL QUERY 10s`, err: `found 10s, expected integer at line 1, char 12`},
		{s: `KILL QUERY 4 ON 'host'`, err: `found host, expected identifier at line 1, char 16`},
		{s: `REVOKE`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 8`},
		{s: `REVOKE BOGUS`, err: `found BOGUS, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 8`},
		{s: `REVOKE READ`, err: `found EOF, expected ON at line 1, char 13`},
		{s: `REVOKE READ TO`, err: `found TO, expected ON at line 1, char 13`},
		{s: `REVOKE READ ON`, err: `found EOF, expected identifier at line 1, char 16`},
		{s: `REVOKE READ ON FROM`, err: `found FROM, expected identifier at line 1, char 16`},
		{s: `REVOKE READ ON testdb`, err: `found EOF, expected FROM at line 1, char 23`},
		{s: `REVOKE READ ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 28`},
		{s: `REVOKE READ FROM`, err: `found FROM, expected ON at line 1, char 13`},
		{s: `REVOKE WRITE`, err: `found EOF, expected ON at line 1, char 14`},
		{s: `REVOKE WRITE TO`, err: `found TO, expected ON at line 1, char 14`},
		{s: `REVOKE WRITE ON`, err: `found EOF, expected identifier at line 1, char 17`},
		{s: `REVOKE WRITE ON FROM`, err: `found FROM, expected identifier at line 1, char 17`},
		{s: `REVOKE WRITE ON testdb`, err: `found EOF, expected FROM at line 1, char 24`},
		{s: `REVOKE WRITE ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 29`},
		{s: `REVOKE WRITE FROM`, err: `found FROM, expected ON at line 1, char 14`},
		{s: `REVOKE ALL`, err: `found EOF, expected ON, FROM at line 1, char 12`},
		{s: `REVOKE ALL PRIVILEGES`, err: `found EOF, expected ON, FROM at line 1, char 23`},
		{s: `REVOKE ALL TO`, err: `found TO, expected ON, FROM at line 1, char 12`},
		{s: `REVOKE ALL PRIVILEGES TO`, err: `found TO, expected ON, FROM at line 1, char 23`},
		{s: `REVOKE ALL ON`, err: `found EOF, expected identifier at line 1, char 15`},
		{s: `REVOKE ALL PRIVILEGES ON`, err: `found EOF, expected identifier at line 1, char 26`},
		{s: `REVOKE ALL ON FROM`, err: `found FROM, expected identifier at line 1, char 15`},
		{s: `REVOKE ALL PRIVILEGES ON FROM`, err: `found FROM, expected identifier at line 1, char 26`},
		{s: `REVOKE ALL ON testdb`, err: `found EOF, expected FROM at line 1, char 22`},
		{s: `REVOKE ALL PRIVILEGES ON testdb`, err: `found EOF, expected FROM at line 1, char 33`},
		{s: `REVOKE ALL ON testdb TO`, err: `found TO, expected FROM at line 1, char 22`},
		{s: `REVOKE ALL PRIVILEGES ON testdb TO`, err: `found TO, expected FROM at line 1, char 33`},
		{s: `REVOKE ALL ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 27`},
		{s: `REVOKE ALL PRIVILEGES ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 38`},
		{s: `REVOKE ALL FROM`, err: `found EOF, expected identifier at line 1, char 17`},
		{s: `REVOKE ALL PRIVILEGES FROM`, err: `found EOF, expected identifier at line 1, char 28`},
		{s: `CREATE RETENTION`, err: `found EOF, expected POLICY at line 1, char 18`},
		{s: `CREATE RETENTION POLICY`, err: `found EOF, expected identifier at line 1, char 25`},
		{s: `CREATE RETENTION POLICY policy1`, err: `found EOF, expected ON at line 1, char 33`},
		{s: `CREATE RETENTION POLICY policy1 ON`, err: `found EOF, expected identifier at line 1, char 36`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb`, err: `found EOF, expected DURATION at line 1, char 43`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION`, err: `found EOF, expected duration at line 1, char 52`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION bad`, err: `found bad, expected duration at line 1, char 52`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h`, err: `found EOF, expected REPLICATION at line 1, char 54`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION`, err: `found EOF, expected integer at line 1, char 67`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION 3.14`, err: `found 3.14, expected integer at line 1, char 67`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION 0`, err: `invalid value 0: must be 1 <= n <= 2147483647 at line 1, char 67`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION bad`, err: `found bad, expected integer at line 1, char 67`},
		{s: `CREATE RETENTION POLICY policy1 ON testdb DURATION 1h REPLICATION 2 SHARD DURATION INF`, err: `invalid duration INF for shard duration at line 1, char 84`},
		{s: `ALTER`, err: `found EOF, expected RETENTION at line 1, char 7`},
		{s: `ALTER RETENTION`, err: `found EOF, expected POLICY at line 1, char 17`},
		{s: `ALTER RETENTION POLICY`, err: `found EOF, expected identifier at line 1, char 24`},
		{s: `ALTER RETENTION POLICY policy1`, err: `found EOF, expected ON at line 1, char 32`}, {s: `ALTER RETENTION POLICY policy1 ON`, err: `found EOF, expected identifier at line 1, char 35`},
		{s: `ALTER RETENTION POLICY policy1 ON testdb`, err: `found EOF, expected DURATION, REPLICATION, SHARD, DEFAULT at line 1, char 42`},
		{s: `ALTER RETENTION POLICY policy1 ON testdb REPLICATION 1 REPLICATION 2`, err: `found duplicate REPLICATION option at line 1, char 56`},
		{s: `ALTER RETENTION POLICY policy1 ON testdb DURATION 15251w`, err: `overflowed duration 15251w: choose a smaller duration or INF at line 1, char 51`},
		{s: `ALTER RETENTION POLICY policy1 ON testdb DURATION INF SHARD DURATION INF`, err: `invalid duration INF for shard duration at line 1, char 70`},
		{s: `SET`, err: `found EOF, expected PASSWORD at line 1, char 5`},
		{s: `SET PASSWORD`, err: `found EOF, expected FOR at line 1, char 14`},
		{s: `SET PASSWORD something`, err: `found something, expected FOR at line 1, char 14`},
		{s: `SET PASSWORD FOR`, err: `found EOF, expected identifier at line 1, char 18`},
		{s: `SET PASSWORD FOR dejan`, err: `found EOF, expected = at line 1, char 24`},
		{s: `SET PASSWORD FOR dejan =`, err: `found EOF, expected string at line 1, char 25`},
		{s: `SET PASSWORD FOR dejan = bla`, err: `found bla, expected string at line 1, char 26`},
		{s: `$SHOW$DATABASES`, err: `found $SHOW, expected SELECT, DELETE, SHOW, CREATE, DROP, EXPLAIN, GRANT, REVOKE, ALTER, SET, KILL at line 1, char 1`},
		{s: `SELECT * FROM cpu WHERE "tagkey" = $$`, err: `empty bound parameter`},
		{
			s: `CREATE DATABASE $db`,
			params: map[string]interface{}{
				"db": map[string]interface{}{"identifier": "mydb"},
			},
			stmt: &influxql.CreateDatabaseStatement{
				Name: "mydb",
			},
		},
		{
			s: `SELECT count($value) FROM $m`,
			params: map[string]interface{}{
				"value": map[string]interface{}{"identifier": "my_value"},
				"m":     map[string]interface{}{"identifier": "my_measurement"},
			},
			stmt: &influxql.SelectStatement{
				Fields: []*influxql.Field{{
					Expr: &influxql.Call{
						Name: "count",
						Args: []influxql.Expr{
							&influxql.VarRef{Val: "my_value"},
						}}},
				},
				Sources: []influxql.Source{&influxql.Measurement{Name: "my_measurement"}},
			},
		},
		{
			s: `SELECT * FROM $m LIMIT $limit`,
			params: map[string]interface{}{
				"m":     map[string]interface{}{"identifier": "shapes"},
				"limit": int64(10),
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.Wildcard{},
				}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "shapes"}},
				Limit:   10,
			},
		},
		{
			s: `SELECT * FROM $m LIMIT $limit`,
			params: map[string]interface{}{
				"m":     map[string]interface{}{"identifier": "shapes"},
				"limit": map[string]interface{}{"integer": json.Number("10")},
			},
			stmt: &influxql.SelectStatement{
				IsRawQuery: true,
				Fields: []*influxql.Field{{
					Expr: &influxql.Wildcard{},
				}},
				Sources: []influxql.Source{&influxql.Measurement{Name: "shapes"}},
				Limit:   10,
			},
		},
	}
	for i, tt := range tests {
		if tt.skip {
			continue
		}
		p := influxql.NewParser(strings.NewReader(tt.s))
		if tt.params != nil {
			p.SetParams(tt.params)
		}
		stmt, err := p.ParseStatement()
		if st, ok := stmt.(*influxql.CreateContinuousQueryStatement); ok {
			if st != nil && st.Source != nil {
				tt.stmt.(*influxql.CreateContinuousQueryStatement).Source.GroupByInterval()
			}
		}
		if !reflect.DeepEqual(tt.err, errstring(err)) {
			t.Errorf("%d. %q: error mismatch:\n  exp=%s\n  got=%s\n\n", i, tt.s, tt.err, err)
		} else if tt.err == "" {
			if !reflect.DeepEqual(tt.stmt, stmt) {
				t.Logf("\n# %s\nexp=%s\ngot=%s\n", tt.s, mustMarshalJSON(tt.stmt), mustMarshalJSON(stmt))
				t.Logf("\nSQL exp=%s\nSQL got=%s\n", tt.stmt.String(), stmt.String())
				t.Errorf("%d. %q\n\nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.stmt, stmt)
			} else {
				switch stmt.(type) {
				case *influxql.CreateUserStatement, *influxql.SetPasswordUserStatement:
					continue
				}
				stmt2, err := influxql.ParseStatement(stmt.String())
				if err != nil {
					t.Errorf("%d. %q: unable to parse statement string: %s", i, stmt.String(), err)
				} else if !reflect.DeepEqual(tt.stmt, stmt2) {
					t.Logf("\n# %s\nexp=%s\ngot=%s\n", tt.s, mustMarshalJSON(tt.stmt), mustMarshalJSON(stmt2))
					t.Logf("\nSQL exp=%s\nSQL got=%s\n", tt.stmt.String(), stmt2.String())
					t.Errorf("%d. %q\n\nstmt reparse mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.stmt, stmt2)
				}
			}
		}
	}
}
Ensure the parser can parse strings into Statement ASTs.
package influxql_test
import (
	"encoding/json"
	"fmt"
	"reflect"
	"regexp"
	"strings"
	"testing"
	"time"
	"github.com/influxdata/influxql"
)
func TestParser_ParseQuery(t *testing.T) {
	s := `SELECT a FROM b; SELECT c FROM d`
	q, err := influxql.NewParser(strings.NewReader(s)).ParseQuery()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	} else if len(q.Statements) != 2 {
		t.Fatalf("unexpected statement count: %d", len(q.Statements))
	}
}
func TestParser_ParseQuery_TrailingSemicolon(t *testing.T) {
	s := `SELECT value FROM cpu;`
	q, err := influxql.NewParser(strings.NewReader(s)).ParseQuery()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	} else if len(q.Statements) != 1 {
		t.Fatalf("unexpected statement count: %d", len(q.Statements))
	}
}
func TestParser_ParseQuery_Empty(t *testing.T) {
	q, err := influxql.NewParser(strings.NewReader(``)).ParseQuery()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	} else if len(q.Statements) != 0 {
		t.Fatalf("unexpected statement count: %d", len(q.Statements))
	}
}
func TestParser_ParseQuery_SkipComments(t *testing.T) {
	q, err := influxql.ParseQuery(`SELECT * FROM cpu; -- read from cpu database
CREATE CONTINUOUS QUERY cq0 ON db0 BEGIN
	SELECT mean(*) INTO db1..:MEASUREMENT FROM cpu GROUP BY time(5m)
END;
-- should ignore the trailing multiline comment /*
SELECT mean(value) FROM gpu;
-- trailing comment at the end`)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	} else if len(q.Statements) != 3 {
		t.Fatalf("unexpected statement count: %d", len(q.Statements))
	}
}
func TestParser_ParseQuery_ParseError(t *testing.T) {
	_, err := influxql.NewParser(strings.NewReader(`SELECT`)).ParseQuery()
	if err == nil || err.Error() != `found EOF, expected identifier, string, number, bool at line 1, char 8` {
		t.Fatalf("unexpected error: %s", err)
	}
}
func TestParser_ParseQuery_NoSemicolon(t *testing.T) {
	_, err := influxql.NewParser(strings.NewReader(`CREATE DATABASE foo CREATE DATABASE bar`)).ParseQuery()
	if err == nil || err.Error() != `found CREATE, expected ; at line 1, char 21` {
		t.Fatalf("unexpected error: %s", err)
	}
}