influxdb/influxql/ast.go

3756 lines
101 KiB
Go
Raw Normal View History

2014-11-15 19:04:30 +00:00
package influxql
import (
"bytes"
2015-01-23 09:44:56 +00:00
"errors"
"fmt"
"regexp"
2015-12-23 18:05:05 +00:00
"sort"
"strconv"
"strings"
2014-11-15 19:04:30 +00:00
"time"
"github.com/influxdata/influxdb/pkg/slices"
2014-11-15 19:04:30 +00:00
)
// DataType represents the primitive data types available in InfluxQL.
type DataType int
2014-11-15 19:04:30 +00:00
const (
2015-02-01 18:47:48 +00:00
// Unknown primitive data type.
2015-06-10 20:09:23 +00:00
Unknown DataType = 0
2015-04-13 04:36:00 +00:00
// Float means the data type is a float
2015-06-10 20:09:23 +00:00
Float = 1
2015-04-13 04:36:00 +00:00
// Integer means the data type is a integer
2015-06-10 20:09:23 +00:00
Integer = 2
2015-02-01 18:47:48 +00:00
// String means the data type is a string of text.
String = 3
// Boolean means the data type is a boolean.
Boolean = 4
2015-02-01 18:47:48 +00:00
// Time means the data type is a time.
2015-06-10 20:09:23 +00:00
Time = 5
2015-02-01 18:47:48 +00:00
// Duration means the data type is a duration of time.
2015-06-10 20:09:23 +00:00
Duration = 6
2014-11-15 19:04:30 +00:00
)
2014-12-09 15:45:29 +00:00
// InspectDataType returns the data type of a given value.
func InspectDataType(v interface{}) DataType {
switch v.(type) {
case float64:
2015-04-13 04:36:00 +00:00
return Float
case int64, int32, int:
return Integer
2014-12-09 15:45:29 +00:00
case string:
return String
case bool:
return Boolean
2014-12-09 15:45:29 +00:00
case time.Time:
return Time
case time.Duration:
return Duration
default:
return Unknown
}
}
func InspectDataTypes(a []interface{}) []DataType {
dta := make([]DataType, len(a))
for i, v := range a {
dta[i] = InspectDataType(v)
}
return dta
}
func (d DataType) String() string {
switch d {
case Float:
return "float"
case Integer:
return "integer"
case String:
return "string"
case Boolean:
return "boolean"
case Time:
return "time"
case Duration:
return "duration"
}
return "unknown"
}
2014-11-15 19:04:30 +00:00
// Node represents a node in the InfluxDB abstract syntax tree.
type Node interface {
node()
String() string
2014-11-15 19:04:30 +00:00
}
2015-02-01 18:47:48 +00:00
func (*Query) node() {}
func (Statements) node() {}
func (*AlterRetentionPolicyStatement) node() {}
func (*CreateContinuousQueryStatement) node() {}
func (*CreateDatabaseStatement) node() {}
func (*CreateRetentionPolicyStatement) node() {}
func (*CreateSubscriptionStatement) node() {}
2015-02-01 18:47:48 +00:00
func (*CreateUserStatement) node() {}
func (*Distinct) node() {}
2015-02-01 18:47:48 +00:00
func (*DeleteStatement) node() {}
func (*DropContinuousQueryStatement) node() {}
func (*DropDatabaseStatement) node() {}
2015-02-23 20:51:52 +00:00
func (*DropMeasurementStatement) node() {}
2015-02-01 18:47:48 +00:00
func (*DropRetentionPolicyStatement) node() {}
func (*DropSeriesStatement) node() {}
2015-10-03 02:49:11 +00:00
func (*DropServerStatement) node() {}
func (*DropSubscriptionStatement) node() {}
2015-02-01 18:47:48 +00:00
func (*DropUserStatement) node() {}
func (*GrantStatement) node() {}
func (*GrantAdminStatement) node() {}
2015-06-26 19:30:00 +00:00
func (*RevokeStatement) node() {}
func (*RevokeAdminStatement) node() {}
2015-06-26 19:30:00 +00:00
func (*SelectStatement) node() {}
func (*SetPasswordUserStatement) node() {}
2015-02-01 18:47:48 +00:00
func (*ShowContinuousQueriesStatement) node() {}
func (*ShowGrantsForUserStatement) node() {}
2015-03-10 19:46:05 +00:00
func (*ShowServersStatement) node() {}
2015-02-01 18:47:48 +00:00
func (*ShowDatabasesStatement) node() {}
func (*ShowFieldKeysStatement) node() {}
func (*ShowRetentionPoliciesStatement) node() {}
func (*ShowMeasurementsStatement) node() {}
func (*ShowSeriesStatement) node() {}
2015-11-13 23:26:30 +00:00
func (*ShowShardGroupsStatement) node() {}
func (*ShowShardsStatement) node() {}
2015-03-12 23:07:41 +00:00
func (*ShowStatsStatement) node() {}
func (*ShowSubscriptionsStatement) node() {}
2015-03-24 03:13:54 +00:00
func (*ShowDiagnosticsStatement) node() {}
2015-02-01 18:47:48 +00:00
func (*ShowTagKeysStatement) node() {}
func (*ShowTagValuesStatement) node() {}
func (*ShowUsersStatement) node() {}
func (*BinaryExpr) node() {}
func (*BooleanLiteral) node() {}
func (*Call) node() {}
func (*Dimension) node() {}
func (Dimensions) node() {}
func (*DurationLiteral) node() {}
func (*Field) node() {}
func (Fields) node() {}
func (*Measurement) node() {}
func (Measurements) node() {}
func (*nilLiteral) node() {}
func (*NumberLiteral) node() {}
func (*ParenExpr) node() {}
func (*RegexLiteral) node() {}
2015-02-01 18:47:48 +00:00
func (*SortField) node() {}
func (SortFields) node() {}
2015-03-06 13:52:25 +00:00
func (Sources) node() {}
2015-02-01 18:47:48 +00:00
func (*StringLiteral) node() {}
func (*Target) node() {}
func (*TimeLiteral) node() {}
func (*VarRef) node() {}
func (*Wildcard) node() {}
2014-11-15 19:04:30 +00:00
// Query represents a collection of ordered statements.
2014-11-22 04:12:48 +00:00
type Query struct {
Statements Statements
2014-11-15 19:04:30 +00:00
}
// String returns a string representation of the query.
func (q *Query) String() string { return q.Statements.String() }
2014-11-22 04:12:48 +00:00
// Statements represents a list of statements.
type Statements []Statement
// String returns a string representation of the statements.
func (a Statements) String() string {
var str []string
for _, stmt := range a {
str = append(str, stmt.String())
}
return strings.Join(str, ";\n")
}
2014-11-22 04:12:48 +00:00
// Statement represents a single command in InfluxQL.
type Statement interface {
Node
stmt()
2015-01-19 20:12:48 +00:00
RequiredPrivileges() ExecutionPrivileges
2014-11-22 04:12:48 +00:00
}
// HasDefaultDatabase provides an interface to get the default database from a Statement.
type HasDefaultDatabase interface {
Node
stmt()
DefaultDatabase() string
}
2015-01-19 20:12:48 +00:00
// ExecutionPrivilege is a privilege required for a user to execute
// a statement on a database or resource.
type ExecutionPrivilege struct {
// Admin privilege required.
Admin bool
// Name of the database.
2015-01-19 20:12:48 +00:00
Name string
// Database privilege required.
2015-01-19 20:12:48 +00:00
Privilege Privilege
}
// ExecutionPrivileges is a list of privileges required to execute a statement.
type ExecutionPrivileges []ExecutionPrivilege
2015-02-01 18:47:48 +00:00
func (*AlterRetentionPolicyStatement) stmt() {}
func (*CreateContinuousQueryStatement) stmt() {}
func (*CreateDatabaseStatement) stmt() {}
func (*CreateRetentionPolicyStatement) stmt() {}
func (*CreateSubscriptionStatement) stmt() {}
2015-02-01 18:47:48 +00:00
func (*CreateUserStatement) stmt() {}
func (*DeleteStatement) stmt() {}
func (*DropContinuousQueryStatement) stmt() {}
func (*DropDatabaseStatement) stmt() {}
2015-02-23 20:51:52 +00:00
func (*DropMeasurementStatement) stmt() {}
2015-02-01 18:47:48 +00:00
func (*DropRetentionPolicyStatement) stmt() {}
func (*DropSeriesStatement) stmt() {}
2015-10-03 02:49:11 +00:00
func (*DropServerStatement) stmt() {}
func (*DropSubscriptionStatement) stmt() {}
2015-02-01 18:47:48 +00:00
func (*DropUserStatement) stmt() {}
func (*GrantStatement) stmt() {}
func (*GrantAdminStatement) stmt() {}
2015-02-01 18:47:48 +00:00
func (*ShowContinuousQueriesStatement) stmt() {}
func (*ShowGrantsForUserStatement) stmt() {}
2015-03-10 19:46:05 +00:00
func (*ShowServersStatement) stmt() {}
2015-02-01 18:47:48 +00:00
func (*ShowDatabasesStatement) stmt() {}
func (*ShowFieldKeysStatement) stmt() {}
func (*ShowMeasurementsStatement) stmt() {}
func (*ShowRetentionPoliciesStatement) stmt() {}
func (*ShowSeriesStatement) stmt() {}
2015-11-13 23:26:30 +00:00
func (*ShowShardGroupsStatement) stmt() {}
func (*ShowShardsStatement) stmt() {}
2015-03-12 23:07:41 +00:00
func (*ShowStatsStatement) stmt() {}
func (*ShowSubscriptionsStatement) stmt() {}
2015-03-24 03:13:54 +00:00
func (*ShowDiagnosticsStatement) stmt() {}
2015-02-01 18:47:48 +00:00
func (*ShowTagKeysStatement) stmt() {}
func (*ShowTagValuesStatement) stmt() {}
func (*ShowUsersStatement) stmt() {}
func (*RevokeStatement) stmt() {}
func (*RevokeAdminStatement) stmt() {}
2015-02-01 18:47:48 +00:00
func (*SelectStatement) stmt() {}
func (*SetPasswordUserStatement) stmt() {}
2014-11-15 19:04:30 +00:00
// Expr represents an expression that can be evaluated to a value.
type Expr interface {
Node
expr()
}
2015-02-01 18:47:48 +00:00
func (*BinaryExpr) expr() {}
func (*BooleanLiteral) expr() {}
func (*Call) expr() {}
func (*Distinct) expr() {}
2015-02-01 18:47:48 +00:00
func (*DurationLiteral) expr() {}
func (*nilLiteral) expr() {}
func (*NumberLiteral) expr() {}
func (*ParenExpr) expr() {}
func (*RegexLiteral) expr() {}
2015-02-01 18:47:48 +00:00
func (*StringLiteral) expr() {}
func (*TimeLiteral) expr() {}
func (*VarRef) expr() {}
func (*Wildcard) expr() {}
2014-11-15 19:04:30 +00:00
2015-11-04 21:06:06 +00:00
// Literal represents a static literal.
type Literal interface {
Expr
literal()
}
func (*BooleanLiteral) literal() {}
func (*DurationLiteral) literal() {}
func (*nilLiteral) literal() {}
func (*NumberLiteral) literal() {}
func (*RegexLiteral) literal() {}
func (*StringLiteral) literal() {}
func (*TimeLiteral) literal() {}
2014-11-22 04:12:48 +00:00
// Source represents a source of data for a statement.
type Source interface {
2014-11-15 19:04:30 +00:00
Node
2014-11-22 04:12:48 +00:00
source()
2014-11-15 19:04:30 +00:00
}
func (*Measurement) source() {}
2015-03-06 13:52:25 +00:00
// Sources represents a list of sources.
type Sources []Source
2015-11-04 21:06:06 +00:00
// Names returns a list of source names.
func (a Sources) Names() []string {
names := make([]string, 0, len(a))
for _, s := range a {
switch s := s.(type) {
case *Measurement:
names = append(names, s.Name)
}
}
return names
}
2016-02-04 15:12:52 +00:00
// HasSystemSource returns true if any of the sources are internal, system sources.
func (a Sources) HasSystemSource() bool {
for _, s := range a {
switch s := s.(type) {
case *Measurement:
if IsSystemName(s.Name) {
return true
}
}
}
return false
}
2015-03-06 13:52:25 +00:00
// String returns a string representation of a Sources array.
func (a Sources) String() string {
var buf bytes.Buffer
ubound := len(a) - 1
for i, src := range a {
_, _ = buf.WriteString(src.String())
if i < ubound {
_, _ = buf.WriteString(", ")
}
}
return buf.String()
}
2014-11-15 19:04:30 +00:00
2016-02-04 15:12:52 +00:00
// IsSystemName returns true if name is an internal system name.
// System names are prefixed with an underscore.
func IsSystemName(name string) bool { return strings.HasPrefix(name, "_") }
2015-01-21 13:28:24 +00:00
// SortField represents a field to sort results by.
type SortField struct {
// Name of the field
Name string
// Sort order.
Ascending bool
}
// String returns a string representation of a sort field
func (field *SortField) String() string {
var buf bytes.Buffer
2015-08-27 17:52:22 +00:00
if field.Name != "" {
_, _ = buf.WriteString(field.Name)
_, _ = buf.WriteString(" ")
}
if field.Ascending {
_, _ = buf.WriteString("ASC")
} else {
_, _ = buf.WriteString("DESC")
}
return buf.String()
}
// SortFields represents an ordered list of ORDER BY fields
type SortFields []*SortField
// String returns a string representation of sort fields
func (a SortFields) String() string {
fields := make([]string, 0, len(a))
for _, field := range a {
fields = append(fields, field.String())
}
return strings.Join(fields, ", ")
}
2014-12-31 13:47:21 +00:00
// CreateDatabaseStatement represents a command for creating a new database.
type CreateDatabaseStatement struct {
// Name of the database to be created.
Name string
// IfNotExists indicates whether to return without error if the database
// already exists.
IfNotExists bool
// RetentionPolicyCreate indicates whether the user explicitly wants to create a retention policy
RetentionPolicyCreate bool
// RetentionPolicyDuration indicates retention duration for the new database
RetentionPolicyDuration time.Duration
// RetentionPolicyReplication indicates retention replication for the new database
RetentionPolicyReplication int
// RetentionPolicyName indicates retention name for the new database
RetentionPolicyName string
2014-12-31 13:47:21 +00:00
}
// String returns a string representation of the create database statement.
func (s *CreateDatabaseStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("CREATE DATABASE ")
if s.IfNotExists {
_, _ = buf.WriteString("IF NOT EXISTS ")
}
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.Name))
if s.RetentionPolicyCreate {
_, _ = buf.WriteString(" WITH DURATION ")
_, _ = buf.WriteString(s.RetentionPolicyDuration.String())
_, _ = buf.WriteString(" REPLICATION ")
_, _ = buf.WriteString(strconv.Itoa(s.RetentionPolicyReplication))
_, _ = buf.WriteString(" NAME ")
_, _ = buf.WriteString(QuoteIdent(s.RetentionPolicyName))
}
2014-12-31 13:47:21 +00:00
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a CreateDatabaseStatement.
2015-01-19 20:12:48 +00:00
func (s *CreateDatabaseStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
2015-01-05 03:32:49 +00:00
// DropDatabaseStatement represents a command to drop a database.
type DropDatabaseStatement struct {
// Name of the database to be dropped.
Name string
// IfExists indicates whether to return without error if the database
// does not exists.
IfExists bool
2015-01-05 03:32:49 +00:00
}
// String returns a string representation of the drop database statement.
func (s *DropDatabaseStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("DROP DATABASE ")
if s.IfExists {
_, _ = buf.WriteString("IF EXISTS ")
}
_, _ = buf.WriteString(QuoteIdent(s.Name))
2015-01-05 03:32:49 +00:00
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a DropDatabaseStatement.
2015-01-19 20:12:48 +00:00
func (s *DropDatabaseStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
// DropRetentionPolicyStatement represents a command to drop a retention policy from a database.
type DropRetentionPolicyStatement struct {
// Name of the policy to drop.
Name string
// Name of the database to drop the policy from.
Database string
}
// String returns a string representation of the drop retention policy statement.
func (s *DropRetentionPolicyStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("DROP RETENTION POLICY ")
_, _ = buf.WriteString(QuoteIdent(s.Name))
_, _ = buf.WriteString(" ON ")
_, _ = buf.WriteString(QuoteIdent(s.Database))
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a DropRetentionPolicyStatement.
2015-01-19 20:12:48 +00:00
func (s *DropRetentionPolicyStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: s.Database, Privilege: WritePrivilege}}
2015-01-19 20:12:48 +00:00
}
2014-12-31 16:22:07 +00:00
// CreateUserStatement represents a command for creating a new user.
type CreateUserStatement struct {
// Name of the user to be created.
Name string
// User's password.
2014-12-31 16:22:07 +00:00
Password string
// User's admin privilege.
Admin bool
2014-12-31 16:22:07 +00:00
}
// String returns a string representation of the create user statement.
func (s *CreateUserStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("CREATE USER ")
_, _ = buf.WriteString(QuoteIdent(s.Name))
2014-12-31 16:22:07 +00:00
_, _ = buf.WriteString(" WITH PASSWORD ")
_, _ = buf.WriteString("[REDACTED]")
if s.Admin {
_, _ = buf.WriteString(" WITH ALL PRIVILEGES")
}
2014-12-31 16:22:07 +00:00
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a CreateUserStatement.
2015-01-19 20:12:48 +00:00
func (s *CreateUserStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
2015-01-05 03:56:25 +00:00
// DropUserStatement represents a command for dropping a user.
type DropUserStatement struct {
// Name of the user to drop.
Name string
}
// String returns a string representation of the drop user statement.
func (s *DropUserStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("DROP USER ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.Name))
2015-01-05 03:56:25 +00:00
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a DropUserStatement.
2015-01-19 20:12:48 +00:00
func (s *DropUserStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
2015-01-03 03:56:26 +00:00
// Privilege is a type of action a user can be granted the right to use.
type Privilege int
const (
2015-02-01 18:47:48 +00:00
// NoPrivileges means no privileges required / granted / revoked.
2015-01-19 20:12:48 +00:00
NoPrivileges Privilege = iota
2015-02-01 18:47:48 +00:00
// ReadPrivilege means read privilege required / granted / revoked.
2015-01-19 20:12:48 +00:00
ReadPrivilege
2015-02-01 18:47:48 +00:00
// WritePrivilege means write privilege required / granted / revoked.
2015-01-03 03:56:26 +00:00
WritePrivilege
2015-02-01 18:47:48 +00:00
// AllPrivileges means all privileges required / granted / revoked.
2015-01-03 03:56:26 +00:00
AllPrivileges
)
// NewPrivilege returns an initialized *Privilege.
func NewPrivilege(p Privilege) *Privilege { return &p }
2015-01-03 03:56:26 +00:00
// String returns a string representation of a Privilege.
func (p Privilege) String() string {
switch p {
2015-01-19 20:12:48 +00:00
case NoPrivileges:
return "NO PRIVILEGES"
2015-01-03 03:56:26 +00:00
case ReadPrivilege:
return "READ"
case WritePrivilege:
return "WRITE"
case AllPrivileges:
return "ALL PRIVILEGES"
}
return ""
}
// GrantStatement represents a command for granting a privilege.
type GrantStatement struct {
// The privilege to be granted.
Privilege Privilege
// Database to grant the privilege to.
2015-01-03 03:56:26 +00:00
On string
// Who to grant the privilege to.
User string
}
// String returns a string representation of the grant statement.
func (s *GrantStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("GRANT ")
_, _ = buf.WriteString(s.Privilege.String())
_, _ = buf.WriteString(" ON ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.On))
2015-01-03 03:56:26 +00:00
_, _ = buf.WriteString(" TO ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.User))
2015-01-03 03:56:26 +00:00
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a GrantStatement.
2015-01-19 20:12:48 +00:00
func (s *GrantStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
// GrantAdminStatement represents a command for granting admin privilege.
type GrantAdminStatement struct {
// Who to grant the privilege to.
User string
}
// String returns a string representation of the grant admin statement.
func (s *GrantAdminStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("GRANT ALL PRIVILEGES TO ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.User))
return buf.String()
}
// RequiredPrivileges returns the privilege required to execute a GrantAdminStatement.
func (s *GrantAdminStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
// SetPasswordUserStatement represents a command for changing user password.
type SetPasswordUserStatement struct {
// Plain Password
Password string
// Who to grant the privilege to.
Name string
}
// String returns a string representation of the set password statement.
func (s *SetPasswordUserStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("SET PASSWORD FOR ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.Name))
_, _ = buf.WriteString(" = ")
_, _ = buf.WriteString("[REDACTED]")
return buf.String()
}
// RequiredPrivileges returns the privilege required to execute a SetPasswordUserStatement.
func (s *SetPasswordUserStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
2015-01-03 07:06:18 +00:00
// RevokeStatement represents a command to revoke a privilege from a user.
type RevokeStatement struct {
// The privilege to be revoked.
2015-01-03 07:06:18 +00:00
Privilege Privilege
// Database to revoke the privilege from.
2015-01-03 07:06:18 +00:00
On string
// Who to revoke privilege from.
User string
}
// String returns a string representation of the revoke statement.
func (s *RevokeStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("REVOKE ")
_, _ = buf.WriteString(s.Privilege.String())
_, _ = buf.WriteString(" ON ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.On))
2015-01-03 07:06:18 +00:00
_, _ = buf.WriteString(" FROM ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.User))
2015-01-03 07:06:18 +00:00
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a RevokeStatement.
2015-01-19 20:12:48 +00:00
func (s *RevokeStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
// RevokeAdminStatement represents a command to revoke admin privilege from a user.
type RevokeAdminStatement struct {
// Who to revoke admin privilege from.
User string
}
// String returns a string representation of the revoke admin statement.
func (s *RevokeAdminStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("REVOKE ALL PRIVILEGES FROM ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.User))
return buf.String()
}
// RequiredPrivileges returns the privilege required to execute a RevokeAdminStatement.
func (s *RevokeAdminStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
// CreateRetentionPolicyStatement represents a command to create a retention policy.
type CreateRetentionPolicyStatement struct {
// Name of policy to create.
Name string
// Name of database this policy belongs to.
Database string
// Duration data written to this policy will be retained.
Duration time.Duration
// Replication factor for data written to this policy.
Replication int
// Should this policy be set as default for the database?
Default bool
}
// String returns a string representation of the create retention policy.
func (s *CreateRetentionPolicyStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("CREATE RETENTION POLICY ")
_, _ = buf.WriteString(QuoteIdent(s.Name))
_, _ = buf.WriteString(" ON ")
_, _ = buf.WriteString(QuoteIdent(s.Database))
_, _ = buf.WriteString(" DURATION ")
_, _ = buf.WriteString(FormatDuration(s.Duration))
_, _ = buf.WriteString(" REPLICATION ")
_, _ = buf.WriteString(strconv.Itoa(s.Replication))
if s.Default {
_, _ = buf.WriteString(" DEFAULT")
}
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a CreateRetentionPolicyStatement.
2015-01-19 20:12:48 +00:00
func (s *CreateRetentionPolicyStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
// AlterRetentionPolicyStatement represents a command to alter an existing retention policy.
type AlterRetentionPolicyStatement struct {
// Name of policy to alter.
Name string
// Name of the database this policy belongs to.
Database string
// Duration data written to this policy will be retained.
Duration *time.Duration
// Replication factor for data written to this policy.
Replication *int
// Should this policy be set as defalut for the database?
Default bool
}
// String returns a string representation of the alter retention policy statement.
func (s *AlterRetentionPolicyStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("ALTER RETENTION POLICY ")
_, _ = buf.WriteString(QuoteIdent(s.Name))
_, _ = buf.WriteString(" ON ")
_, _ = buf.WriteString(QuoteIdent(s.Database))
if s.Duration != nil {
_, _ = buf.WriteString(" DURATION ")
_, _ = buf.WriteString(FormatDuration(*s.Duration))
}
if s.Replication != nil {
_, _ = buf.WriteString(" REPLICATION ")
_, _ = buf.WriteString(strconv.Itoa(*s.Replication))
}
if s.Default {
_, _ = buf.WriteString(" DEFAULT")
}
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute an AlterRetentionPolicyStatement.
2015-01-19 20:12:48 +00:00
func (s *AlterRetentionPolicyStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
type FillOption int
const (
// NullFill means that empty aggregate windows will just have null values.
NullFill FillOption = iota
// NoFill means that empty aggregate windows will be purged from the result.
NoFill
2015-03-12 01:20:20 +00:00
// NumberFill means that empty aggregate windows will be filled with the given number
NumberFill
// PreviousFill means that empty aggregate windows will be filled with whatever the previous aggregate window had
PreviousFill
)
2014-11-22 04:12:48 +00:00
// SelectStatement represents a command for extracting data from the database.
type SelectStatement struct {
2014-11-15 19:04:30 +00:00
// Expressions returned from the selection.
Fields Fields
// Target (destination) for the result of the select.
Target *Target
2014-11-15 19:04:30 +00:00
// Expressions used for grouping the selection.
Dimensions Dimensions
2015-03-06 13:52:25 +00:00
// Data sources that fields are extracted from.
Sources Sources
2014-11-15 19:04:30 +00:00
// An expression evaluated on data point.
Condition Expr
// Fields to sort results by
SortFields SortFields
// Maximum number of rows to be returned. Unlimited if zero.
2014-11-15 19:04:30 +00:00
Limit int
2015-01-25 20:34:49 +00:00
// Returns rows starting at an offset from the first row.
Offset int
// Maxiumum number of series to be returned. Unlimited if zero.
SLimit int
// Returns series starting at an offset from the first one.
SOffset int
// memoize the group by interval
groupByInterval time.Duration
// if it's a query for raw data values (i.e. not an aggregate)
IsRawQuery bool
// What fill option the select statement uses, if any
Fill FillOption
// The value to fill empty aggregate buckets with, if any
FillValue interface{}
2016-02-04 15:12:52 +00:00
// Removes the "time" column from the output.
OmitTime bool
2016-02-05 17:23:35 +00:00
// Removes duplicate rows from raw queries.
Dedupe bool
2014-11-15 19:04:30 +00:00
}
2015-05-14 20:53:17 +00:00
// HasDerivative returns true if one of the function calls in the statement is a
// derivative aggregate
func (s *SelectStatement) HasDerivative() bool {
2015-05-14 20:53:17 +00:00
for _, f := range s.FunctionCalls() {
if f.Name == "derivative" || f.Name == "non_negative_derivative" {
return true
}
}
return false
}
2015-05-14 20:53:17 +00:00
// IsSimpleDerivative return true if one of the function call is a derivative function with a
// variable ref as the first arg
func (s *SelectStatement) IsSimpleDerivative() bool {
2015-05-14 20:53:17 +00:00
for _, f := range s.FunctionCalls() {
if f.Name == "derivative" || f.Name == "non_negative_derivative" {
2015-05-14 20:53:17 +00:00
// it's nested if the first argument is an aggregate function
if _, ok := f.Args[0].(*VarRef); ok {
return true
}
}
}
return false
}
// HasSimpleCount return true if one of the function calls is a count function with a
// variable ref as the first arg
func (s *SelectStatement) HasSimpleCount() bool {
// recursively check for a simple count(varref) function
var hasCount func(f *Call) bool
hasCount = func(f *Call) bool {
if f.Name == "count" {
// it's nested if the first argument is an aggregate function
if _, ok := f.Args[0].(*VarRef); ok {
return true
}
} else {
for _, arg := range f.Args {
if child, ok := arg.(*Call); ok {
return hasCount(child)
}
}
}
return false
}
for _, f := range s.FunctionCalls() {
if hasCount(f) {
return true
}
}
return false
}
2015-09-16 20:17:58 +00:00
// TimeAscending returns true if the time field is sorted in chronological order.
func (s *SelectStatement) TimeAscending() bool {
return len(s.SortFields) == 0 || s.SortFields[0].Ascending
}
2015-01-26 12:19:35 +00:00
// Clone returns a deep copy of the statement.
2015-02-01 18:47:48 +00:00
func (s *SelectStatement) Clone() *SelectStatement {
2015-03-06 13:52:25 +00:00
clone := &SelectStatement{
Fields: make(Fields, 0, len(s.Fields)),
Dimensions: make(Dimensions, 0, len(s.Dimensions)),
Sources: cloneSources(s.Sources),
SortFields: make(SortFields, 0, len(s.SortFields)),
2015-02-01 18:47:48 +00:00
Condition: CloneExpr(s.Condition),
Limit: s.Limit,
Offset: s.Offset,
SLimit: s.SLimit,
SOffset: s.SOffset,
Fill: s.Fill,
FillValue: s.FillValue,
IsRawQuery: s.IsRawQuery,
2015-01-26 12:19:35 +00:00
}
2015-02-01 18:47:48 +00:00
if s.Target != nil {
clone.Target = &Target{
Measurement: &Measurement{
Database: s.Target.Measurement.Database,
RetentionPolicy: s.Target.Measurement.RetentionPolicy,
Name: s.Target.Measurement.Name,
Regex: CloneRegexLiteral(s.Target.Measurement.Regex),
},
}
2015-01-26 12:19:35 +00:00
}
2015-03-06 13:52:25 +00:00
for _, f := range s.Fields {
clone.Fields = append(clone.Fields, &Field{Expr: CloneExpr(f.Expr), Alias: f.Alias})
2015-01-26 12:19:35 +00:00
}
2015-03-06 13:52:25 +00:00
for _, d := range s.Dimensions {
clone.Dimensions = append(clone.Dimensions, &Dimension{Expr: CloneExpr(d.Expr)})
2015-01-26 12:19:35 +00:00
}
2015-03-06 13:52:25 +00:00
for _, f := range s.SortFields {
clone.SortFields = append(clone.SortFields, &SortField{Name: f.Name, Ascending: f.Ascending})
2015-01-26 12:19:35 +00:00
}
2015-03-06 13:52:25 +00:00
return clone
}
func cloneSources(sources Sources) Sources {
clone := make(Sources, 0, len(sources))
for _, s := range sources {
clone = append(clone, cloneSource(s))
}
return clone
2015-01-26 12:19:35 +00:00
}
func cloneSource(s Source) Source {
if s == nil {
return nil
}
switch s := s.(type) {
case *Measurement:
m := &Measurement{Database: s.Database, RetentionPolicy: s.RetentionPolicy, Name: s.Name}
2015-03-06 13:52:25 +00:00
if s.Regex != nil {
m.Regex = &RegexLiteral{Val: regexp.MustCompile(s.Regex.Val.String())}
2015-01-26 12:19:35 +00:00
}
2015-03-06 13:52:25 +00:00
return m
2015-01-26 12:19:35 +00:00
default:
panic("unreachable")
}
}
// RewriteWildcards returns the re-written form of the select statement. Any wildcard query
// fields are replaced with the supplied fields, and any wildcard GROUP BY fields are replaced
// with the supplied dimensions.
2015-11-04 21:06:06 +00:00
func (s *SelectStatement) RewriteWildcards(ic IteratorCreator) (*SelectStatement, error) {
// Ignore if there are no wildcards.
hasFieldWildcard := s.HasFieldWildcard()
hasDimensionWildcard := s.HasDimensionWildcard()
if !hasFieldWildcard && !hasDimensionWildcard {
return s, nil
}
// Retrieve a list of unqiue field and dimensions.
fieldSet, dimensionSet, err := ic.FieldDimensions(s.Sources)
if err != nil {
return s, err
}
// If there are no dimension wildcards then merge dimensions to fields.
if !hasDimensionWildcard {
for k := range dimensionSet {
fieldSet[k] = struct{}{}
}
dimensionSet = nil
}
fields := stringSetSlice(fieldSet)
dimensions := stringSetSlice(dimensionSet)
other := s.Clone()
// Rewrite all wildcard query fields
rwFields := make(Fields, 0, len(s.Fields))
for _, f := range s.Fields {
switch f.Expr.(type) {
case *Wildcard:
2015-11-04 21:06:06 +00:00
for _, name := range fields {
rwFields = append(rwFields, &Field{Expr: &VarRef{Val: name}})
}
default:
rwFields = append(rwFields, f)
}
}
other.Fields = rwFields
// Rewrite all wildcard GROUP BY fields
rwDimensions := make(Dimensions, 0, len(s.Dimensions))
for _, d := range s.Dimensions {
switch d.Expr.(type) {
case *Wildcard:
2015-11-04 21:06:06 +00:00
for _, name := range dimensions {
rwDimensions = append(rwDimensions, &Dimension{Expr: &VarRef{Val: name}})
}
default:
rwDimensions = append(rwDimensions, d)
}
}
2015-05-22 20:38:28 +00:00
2015-11-04 21:06:06 +00:00
if hasFieldWildcard && !hasDimensionWildcard {
for _, name := range dimensions {
rwDimensions = append(rwDimensions, &Dimension{Expr: &VarRef{Val: name}})
}
2015-05-22 20:38:28 +00:00
}
other.Dimensions = rwDimensions
2015-11-04 21:06:06 +00:00
return other, nil
}
// RewriteDistinct rewrites the expression to be a call for map/reduce to work correctly
// This method assumes all validation has passed
func (s *SelectStatement) RewriteDistinct() {
2015-11-04 21:06:06 +00:00
WalkFunc(s.Fields, func(n Node) {
switch n := n.(type) {
case *Field:
if expr, ok := n.Expr.(*Distinct); ok {
n.Expr = expr.NewCall()
s.IsRawQuery = false
}
case *Call:
for i, arg := range n.Args {
if arg, ok := arg.(*Distinct); ok {
n.Args[i] = arg.NewCall()
}
}
}
})
}
// RewriteTimeFields removes any "time" field references.
func (s *SelectStatement) RewriteTimeFields() {
for i := 0; i < len(s.Fields); i++ {
switch expr := s.Fields[i].Expr.(type) {
case *VarRef:
if expr.Val == "time" {
s.Fields = append(s.Fields[:i], s.Fields[i+1:]...)
}
}
}
}
2015-09-02 17:26:40 +00:00
// ColumnNames will walk all fields and functions and return the appropriate field names for the select statement
2015-09-04 18:41:46 +00:00
// while maintaining order of the field names
2015-09-02 17:26:40 +00:00
func (s *SelectStatement) ColumnNames() []string {
2016-02-04 15:12:52 +00:00
columnNames := []string{}
if !s.OmitTime {
columnNames = append(columnNames, "time")
}
2015-09-02 17:26:40 +00:00
// First walk each field
for _, field := range s.Fields {
switch f := field.Expr.(type) {
case *Call:
if f.Name == "top" || f.Name == "bottom" {
if len(f.Args) == 2 {
columnNames = append(columnNames, f.Name)
continue
}
// We have a special case now where we have to add the column names for the fields TOP or BOTTOM asked for as well
columnNames = slices.Union(columnNames, f.Fields(), true)
continue
2015-09-02 17:26:40 +00:00
}
columnNames = append(columnNames, field.Name())
default:
2015-09-04 12:48:57 +00:00
// time is always first, and we already added it, so ignore it if they asked for it anywhere else.
2015-09-02 17:26:40 +00:00
if field.Name() != "time" {
columnNames = append(columnNames, field.Name())
}
}
}
return columnNames
}
// HasTimeFieldSpecified will walk all fields and determine if the user explicitly asked for time
// This is needed to determine re-write behaviors for functions like TOP and BOTTOM
func (s *SelectStatement) HasTimeFieldSpecified() bool {
for _, f := range s.Fields {
if f.Name() == "time" {
return true
}
}
return false
}
// String returns a string representation of the select statement.
func (s *SelectStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("SELECT ")
_, _ = buf.WriteString(s.Fields.String())
if s.Target != nil {
_, _ = buf.WriteString(" ")
_, _ = buf.WriteString(s.Target.String())
}
2015-03-06 13:52:25 +00:00
if len(s.Sources) > 0 {
_, _ = buf.WriteString(" FROM ")
_, _ = buf.WriteString(s.Sources.String())
}
if s.Condition != nil {
_, _ = buf.WriteString(" WHERE ")
_, _ = buf.WriteString(s.Condition.String())
}
if len(s.Dimensions) > 0 {
_, _ = buf.WriteString(" GROUP BY ")
_, _ = buf.WriteString(s.Dimensions.String())
}
switch s.Fill {
case NoFill:
_, _ = buf.WriteString(" fill(none)")
case NumberFill:
_, _ = buf.WriteString(fmt.Sprintf(" fill(%v)", s.FillValue))
case PreviousFill:
_, _ = buf.WriteString(" fill(previous)")
}
if len(s.SortFields) > 0 {
_, _ = buf.WriteString(" ORDER BY ")
_, _ = buf.WriteString(s.SortFields.String())
}
if s.Limit > 0 {
_, _ = fmt.Fprintf(&buf, " LIMIT %d", s.Limit)
}
2015-01-25 20:34:49 +00:00
if s.Offset > 0 {
_, _ = buf.WriteString(" OFFSET ")
_, _ = buf.WriteString(strconv.Itoa(s.Offset))
}
if s.SLimit > 0 {
_, _ = fmt.Fprintf(&buf, " SLIMIT %d", s.SLimit)
}
if s.SOffset > 0 {
_, _ = fmt.Fprintf(&buf, " SOFFSET %d", s.SOffset)
}
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute the SelectStatement.
2015-01-19 20:12:48 +00:00
func (s *SelectStatement) RequiredPrivileges() ExecutionPrivileges {
ep := ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
if s.Target != nil {
p := ExecutionPrivilege{Admin: false, Name: s.Target.Measurement.Database, Privilege: WritePrivilege}
2015-01-19 20:12:48 +00:00
ep = append(ep, p)
}
return ep
}
// HasWildcard returns whether or not the select statement has at least 1 wildcard
func (s *SelectStatement) HasWildcard() bool {
return s.HasFieldWildcard() || s.HasDimensionWildcard()
}
2015-08-10 18:31:04 +00:00
// HasFieldWildcard returns whether or not the select statement has at least 1 wildcard in the fields
func (s *SelectStatement) HasFieldWildcard() bool {
for _, f := range s.Fields {
_, ok := f.Expr.(*Wildcard)
if ok {
return true
}
}
return false
}
// HasDimensionWildcard returns whether or not the select statement has
// at least 1 wildcard in the dimensions aka `GROUP BY`
func (s *SelectStatement) HasDimensionWildcard() bool {
for _, d := range s.Dimensions {
_, ok := d.Expr.(*Wildcard)
if ok {
return true
}
}
return false
}
2015-05-19 15:11:12 +00:00
func (s *SelectStatement) validate(tr targetRequirement) error {
if err := s.validateFields(); err != nil {
return err
}
if err := s.validateDimensions(); err != nil {
return err
}
2015-05-19 15:11:12 +00:00
if err := s.validateDistinct(); err != nil {
2015-05-12 20:30:01 +00:00
return err
}
2015-05-19 00:13:44 +00:00
if err := s.validateCountDistinct(); err != nil {
return err
}
2015-05-19 15:11:12 +00:00
if err := s.validateAggregates(tr); err != nil {
2015-05-12 20:30:01 +00:00
return err
}
if err := s.validateDerivative(); err != nil {
return err
}
return nil
}
func (s *SelectStatement) validateFields() error {
ns := s.NamesInSelect()
if len(ns) == 1 && ns[0] == "time" {
return fmt.Errorf("at least 1 non-time field must be queried")
}
return nil
}
func (s *SelectStatement) validateDimensions() error {
var dur time.Duration
for _, dim := range s.Dimensions {
switch expr := dim.Expr.(type) {
case *Call:
// Ensure the call is time() and it only has one duration argument.
// If we already have a duration
if expr.Name != "time" {
return errors.New("only time() calls allowed in dimensions")
} else if len(expr.Args) != 1 {
return errors.New("time dimension expected one argument")
} else if lit, ok := expr.Args[0].(*DurationLiteral); !ok {
return errors.New("time dimension must have one duration argument")
} else if dur != 0 {
return errors.New("multiple time dimensions not allowed")
} else {
dur = lit.Val
}
case *VarRef:
if strings.ToLower(expr.Val) == "time" {
return errors.New("time() is a function and expects at least one argument")
}
case *Wildcard:
default:
return errors.New("only time and tag dimensions allowed")
}
}
return nil
}
2015-09-04 18:41:46 +00:00
// validSelectWithAggregate determines if a SELECT statement has the correct
// combination of aggregate functions combined with selected fields and tags
// Currently we don't have support for all aggregates, but aggregates that
// can be combined with fields/tags are:
// TOP, BOTTOM, MAX, MIN, FIRST, LAST
2015-09-18 14:57:10 +00:00
func (s *SelectStatement) validSelectWithAggregate() error {
calls := map[string]struct{}{}
numAggregates := 0
for _, f := range s.Fields {
fieldCalls := walkFunctionCalls(f.Expr)
for _, c := range fieldCalls {
2015-09-18 14:57:10 +00:00
calls[c.Name] = struct{}{}
}
if len(fieldCalls) != 0 {
2015-09-18 14:57:10 +00:00
numAggregates++
}
}
// For TOP, BOTTOM, MAX, MIN, FIRST, LAST (selector functions) it is ok to ask for fields and tags
// but only if one function is specified. Combining multiple functions and fields and tags is not currently supported
onlySelectors := true
for k := range calls {
switch k {
case "top", "bottom", "max", "min", "first", "last":
default:
onlySelectors = false
break
2015-09-18 14:57:10 +00:00
}
}
if onlySelectors {
// If they only have one selector, they can have as many fields or tags as they want
if numAggregates == 1 {
return nil
}
// If they have multiple selectors, they are not allowed to have any other fields or tags specified
if numAggregates > 1 && len(s.Fields) != numAggregates {
return fmt.Errorf("mixing multiple selector functions with tags or fields is not supported")
}
}
if numAggregates != 0 && numAggregates != len(s.Fields) {
return fmt.Errorf("mixing aggregate and non-aggregate queries is not supported")
}
return nil
}
// validTopBottomAggr determines if TOP or BOTTOM aggregates have valid arguments.
func (s *SelectStatement) validTopBottomAggr(expr *Call) error {
if exp, got := 2, len(expr.Args); got < exp {
return fmt.Errorf("invalid number of arguments for %s, expected at least %d, got %d", expr.Name, exp, got)
}
if len(expr.Args) > 1 {
callLimit, ok := expr.Args[len(expr.Args)-1].(*NumberLiteral)
if !ok {
return fmt.Errorf("expected integer as last argument in %s(), found %s", expr.Name, expr.Args[len(expr.Args)-1])
}
// Check if they asked for a limit smaller than what they passed into the call
if int64(callLimit.Val) > int64(s.Limit) && s.Limit != 0 {
return fmt.Errorf("limit (%d) in %s function can not be larger than the LIMIT (%d) in the select statement", int64(callLimit.Val), expr.Name, int64(s.Limit))
}
for _, v := range expr.Args[:len(expr.Args)-1] {
if _, ok := v.(*VarRef); !ok {
return fmt.Errorf("only fields or tags are allowed in %s(), found %s", expr.Name, v)
}
}
}
return nil
}
// validPercentileAggr determines if PERCENTILE have valid arguments.
func (s *SelectStatement) validPercentileAggr(expr *Call) error {
if err := s.validSelectWithAggregate(); err != nil {
return err
}
if exp, got := 2, len(expr.Args); got != exp {
return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", expr.Name, exp, got)
}
_, ok := expr.Args[1].(*NumberLiteral)
if !ok {
return fmt.Errorf("expected float argument in percentile()")
}
return nil
}
2015-05-19 15:11:12 +00:00
func (s *SelectStatement) validateAggregates(tr targetRequirement) error {
for _, f := range s.Fields {
for _, expr := range walkFunctionCalls(f.Expr) {
2015-09-03 21:40:10 +00:00
switch expr.Name {
case "derivative", "non_negative_derivative":
2015-09-18 14:57:10 +00:00
if err := s.validSelectWithAggregate(); err != nil {
return err
}
2015-09-03 21:40:10 +00:00
if min, max, got := 1, 2, len(expr.Args); got > max || got < min {
return fmt.Errorf("invalid number of arguments for %s, expected at least %d but no more than %d, got %d", expr.Name, min, max, got)
}
// Validate that if they have grouping by time, they need a sub-call like min/max, etc.
groupByInterval, err := s.GroupByInterval()
if err != nil {
return fmt.Errorf("invalid group interval: %v", err)
}
if groupByInterval > 0 {
c, ok := expr.Args[0].(*Call)
if !ok {
return fmt.Errorf("aggregate function required inside the call to %s", expr.Name)
}
switch c.Name {
case "top", "bottom":
if err := s.validTopBottomAggr(c); err != nil {
return err
}
case "percentile":
if err := s.validPercentileAggr(c); err != nil {
return err
}
default:
if exp, got := 1, len(c.Args); got != exp {
return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", c.Name, exp, got)
}
}
}
case "top", "bottom":
if err := s.validTopBottomAggr(expr); err != nil {
return err
}
case "percentile":
if err := s.validPercentileAggr(expr); err != nil {
return err
}
default:
2015-09-18 14:57:10 +00:00
if err := s.validSelectWithAggregate(); err != nil {
return err
}
2015-09-03 21:40:10 +00:00
if exp, got := 1, len(expr.Args); got != exp {
return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", expr.Name, exp, got)
}
2015-09-03 21:40:10 +00:00
switch fc := expr.Args[0].(type) {
case *VarRef:
2015-09-03 21:40:10 +00:00
// do nothing
case *Call:
if fc.Name != "distinct" {
2015-09-03 21:40:10 +00:00
return fmt.Errorf("expected field argument in %s()", expr.Name)
}
case *Distinct:
if expr.Name != "count" {
return fmt.Errorf("expected field argument in %s()", expr.Name)
}
default:
2015-09-03 21:40:10 +00:00
return fmt.Errorf("expected field argument in %s()", expr.Name)
}
}
}
}
// Check that we have valid duration and where clauses for aggregates
2015-05-12 14:56:38 +00:00
// fetch the group by duration
groupByDuration, _ := s.GroupByInterval()
2015-05-12 14:42:39 +00:00
// If we have a group by interval, but no aggregate function, it's an invalid statement
if s.IsRawQuery && groupByDuration > 0 {
2015-05-12 14:42:39 +00:00
return fmt.Errorf("GROUP BY requires at least one aggregate function")
}
// If we have an aggregate function with a group by time without a where clause, it's an invalid statement
if tr == targetNotRequired { // ignore create continuous query statements
if !s.IsRawQuery && groupByDuration > 0 && !HasTimeExpr(s.Condition) {
2015-05-12 14:42:39 +00:00
return fmt.Errorf("aggregate functions with GROUP BY time require a WHERE time clause")
}
}
2015-05-12 20:30:01 +00:00
return nil
}
2015-05-18 22:28:13 +00:00
func (s *SelectStatement) HasDistinct() bool {
// determine if we have a call named distinct
for _, f := range s.Fields {
switch c := f.Expr.(type) {
case *Call:
if c.Name == "distinct" {
return true
}
case *Distinct:
return true
}
}
return false
}
2015-05-19 15:11:12 +00:00
func (s *SelectStatement) validateDistinct() error {
2015-05-18 22:28:13 +00:00
if !s.HasDistinct() {
return nil
}
2015-05-12 14:42:39 +00:00
if len(s.Fields) > 1 {
return fmt.Errorf("aggregate function distinct() can not be combined with other functions or fields")
}
switch c := s.Fields[0].Expr.(type) {
case *Call:
if len(c.Args) == 0 {
return fmt.Errorf("distinct function requires at least one argument")
}
2015-05-15 21:58:00 +00:00
if len(c.Args) != 1 {
return fmt.Errorf("distinct function can only have one argument")
}
2015-05-15 21:58:00 +00:00
}
return nil
}
2015-05-19 00:13:44 +00:00
func (s *SelectStatement) HasCountDistinct() bool {
for _, f := range s.Fields {
if c, ok := f.Expr.(*Call); ok {
if c.Name == "count" {
for _, a := range c.Args {
if _, ok := a.(*Distinct); ok {
return true
}
2015-05-19 18:43:16 +00:00
if c, ok := a.(*Call); ok {
if c.Name == "distinct" {
return true
}
}
2015-05-19 00:13:44 +00:00
}
}
}
}
return false
}
func (s *SelectStatement) validateCountDistinct() error {
if !s.HasCountDistinct() {
return nil
}
2015-05-19 18:43:16 +00:00
valid := func(e Expr) bool {
2015-05-19 00:13:44 +00:00
c, ok := e.(*Call)
if !ok {
2015-05-19 18:43:16 +00:00
return true
2015-05-19 00:13:44 +00:00
}
if c.Name != "count" {
2015-05-19 18:43:16 +00:00
return true
2015-05-19 00:13:44 +00:00
}
for _, a := range c.Args {
if _, ok := a.(*Distinct); ok {
2015-05-19 18:43:16 +00:00
return len(c.Args) == 1
}
if d, ok := a.(*Call); ok {
if d.Name == "distinct" {
return len(d.Args) == 1
}
2015-05-19 00:13:44 +00:00
}
}
2015-05-19 18:43:16 +00:00
return true
2015-05-19 00:13:44 +00:00
}
for _, f := range s.Fields {
2015-05-19 18:43:16 +00:00
if !valid(f.Expr) {
return fmt.Errorf("count(distinct <field>) can only have one argument")
2015-05-19 00:13:44 +00:00
}
}
return nil
}
func (s *SelectStatement) validateDerivative() error {
if !s.HasDerivative() {
return nil
}
// If a derivative is requested, it must be the only field in the query. We don't support
// multiple fields in combination w/ derivaties yet.
if len(s.Fields) != 1 {
return fmt.Errorf("derivative cannot be used with other fields")
}
aggr := s.FunctionCalls()
if len(aggr) != 1 {
return fmt.Errorf("derivative cannot be used with other fields")
}
// Derivative requires two arguments
derivativeCall := aggr[0]
if len(derivativeCall.Args) == 0 {
return fmt.Errorf("derivative requires a field argument")
}
// First arg must be a field or aggr over a field e.g. (mean(field))
_, callOk := derivativeCall.Args[0].(*Call)
_, varOk := derivativeCall.Args[0].(*VarRef)
if !(callOk || varOk) {
return fmt.Errorf("derivative requires a field argument")
}
// If a duration arg is pased, make sure it's a duration
if len(derivativeCall.Args) == 2 {
// Second must be a duration .e.g (1h)
if _, ok := derivativeCall.Args[1].(*DurationLiteral); !ok {
return fmt.Errorf("derivative requires a duration argument")
}
}
2015-05-12 14:42:39 +00:00
return nil
}
// GroupByIterval extracts the time interval, if specified.
func (s *SelectStatement) GroupByInterval() (time.Duration, error) {
// return if we've already pulled it out
if s.groupByInterval != 0 {
return s.groupByInterval, nil
}
// Ignore if there are no dimensions.
if len(s.Dimensions) == 0 {
return 0, nil
}
for _, d := range s.Dimensions {
2015-05-01 15:29:39 +00:00
if call, ok := d.Expr.(*Call); ok && call.Name == "time" {
// Make sure there is exactly one argument.
if len(call.Args) != 1 {
return 0, errors.New("time dimension expected one argument")
}
// Ensure the argument is a duration.
lit, ok := call.Args[0].(*DurationLiteral)
if !ok {
return 0, errors.New("time dimension must have one duration argument")
}
s.groupByInterval = lit.Val
return lit.Val, nil
}
}
return 0, nil
}
// SetTimeRange sets the start and end time of the select statement to [start, end). i.e. start inclusive, end exclusive.
// This is used commonly for continuous queries so the start and end are in buckets.
func (s *SelectStatement) SetTimeRange(start, end time.Time) error {
cond := fmt.Sprintf("time >= '%s' AND time < '%s'", start.UTC().Format(time.RFC3339Nano), end.UTC().Format(time.RFC3339Nano))
if s.Condition != nil {
cond = fmt.Sprintf("%s AND %s", s.rewriteWithoutTimeDimensions(), cond)
}
expr, err := NewParser(strings.NewReader(cond)).ParseExpr()
if err != nil {
return err
}
// fold out any previously replaced time dimensios and set the condition
s.Condition = Reduce(expr, nil)
return nil
}
// rewriteWithoutTimeDimensions will remove any WHERE time... clauses from the select statement
// This is necessary when setting an explicit time range to override any that previously existed.
func (s *SelectStatement) rewriteWithoutTimeDimensions() string {
n := RewriteFunc(s.Condition, func(n Node) Node {
switch n := n.(type) {
case *BinaryExpr:
if n.LHS.String() == "time" {
return &BooleanLiteral{Val: true}
}
return n
2015-01-28 05:11:48 +00:00
case *Call:
return &BooleanLiteral{Val: true}
default:
return n
}
})
2015-01-28 05:11:48 +00:00
return n.String()
}
2014-12-10 14:44:52 +00:00
/*
BinaryExpr
SELECT mean(xxx.value) + avg(yyy.value) FROM xxx JOIN yyy WHERE xxx.host = 123
from xxx where host = 123
select avg(value) from yyy where host = 123
SELECT xxx.value FROM xxx WHERE xxx.host = 123
SELECT yyy.value FROM yyy
---
SELECT MEAN(xxx.value) + MEAN(cpu.load.value)
FROM xxx JOIN yyy
GROUP BY host
WHERE (xxx.region == "uswest" OR yyy.region == "uswest") AND xxx.otherfield == "XXX"
select * from (
select mean + mean from xxx join yyy
group by time(5m), host
) (xxx.region == "uswest" OR yyy.region == "uswest") AND xxx.otherfield == "XXX"
(seriesIDS for xxx.region = 'uswest' union seriesIDs for yyy.regnion = 'uswest') | seriesIDS xxx.otherfield = 'XXX'
WHERE xxx.region == "uswest" AND xxx.otherfield == "XXX"
WHERE yyy.region == "uswest"
*/
// Substatement returns a single-series statement for a given variable reference.
func (s *SelectStatement) Substatement(ref *VarRef) (*SelectStatement, error) {
// Copy dimensions and properties to new statement.
other := &SelectStatement{
Fields: Fields{{Expr: ref}},
Dimensions: s.Dimensions,
Limit: s.Limit,
Offset: s.Offset,
2014-12-16 14:06:28 +00:00
SortFields: s.SortFields,
}
// If there is only one series source then return it with the whole condition.
2015-03-06 13:52:25 +00:00
if len(s.Sources) == 1 {
other.Sources = s.Sources
other.Condition = s.Condition
return other, nil
}
// Find the matching source.
2015-03-06 13:52:25 +00:00
name := MatchSource(s.Sources, ref.Val)
if name == "" {
return nil, fmt.Errorf("field source not found: %s", ref.Val)
}
2015-03-06 13:52:25 +00:00
other.Sources = append(other.Sources, &Measurement{Name: name})
// Filter out conditions.
if s.Condition != nil {
other.Condition = filterExprBySource(name, s.Condition)
}
return other, nil
}
2015-03-06 19:23:58 +00:00
// NamesInWhere returns the field and tag names (idents) referenced in the where clause
func (s *SelectStatement) NamesInWhere() []string {
var a []string
if s.Condition != nil {
a = walkNames(s.Condition)
2015-03-06 19:23:58 +00:00
}
return a
}
2015-03-06 19:23:58 +00:00
// NamesInSelect returns the field and tag names (idents) in the select clause
func (s *SelectStatement) NamesInSelect() []string {
var a []string
for _, f := range s.Fields {
a = append(a, walkNames(f.Expr)...)
}
2015-03-06 19:23:58 +00:00
return a
}
2015-08-10 18:31:04 +00:00
// NamesInDimension returns the field and tag names (idents) in the group by
func (s *SelectStatement) NamesInDimension() []string {
var a []string
for _, d := range s.Dimensions {
a = append(a, walkNames(d.Expr)...)
}
return a
}
2015-09-20 22:27:22 +00:00
// LimitTagSets returns a tag set list with SLIMIT and SOFFSET applied.
2015-12-22 22:46:10 +00:00
func LimitTagSets(a []*TagSet, slimit, soffset int) []*TagSet {
2015-09-20 22:27:22 +00:00
// Ignore if no limit or offset is specified.
2015-12-22 22:46:10 +00:00
if slimit == 0 && soffset == 0 {
2015-09-20 22:27:22 +00:00
return a
}
// If offset is beyond the number of tag sets then return nil.
2015-12-22 22:46:10 +00:00
if soffset > len(a) {
2015-09-20 22:27:22 +00:00
return nil
}
// Clamp limit to the max number of tag sets.
2015-12-22 22:46:10 +00:00
if soffset+slimit > len(a) {
slimit = len(a) - soffset
2015-09-20 22:27:22 +00:00
}
2015-12-22 22:46:10 +00:00
return a[soffset : soffset+slimit]
2015-09-20 22:27:22 +00:00
}
// walkNames will walk the Expr and return the database fields
func walkNames(exp Expr) []string {
switch expr := exp.(type) {
case *VarRef:
2015-03-06 19:23:58 +00:00
return []string{expr.Val}
case *Call:
if len(expr.Args) == 0 {
return nil
}
lit, ok := expr.Args[0].(*VarRef)
if !ok {
return nil
}
2015-03-06 19:23:58 +00:00
return []string{lit.Val}
case *BinaryExpr:
2015-03-06 19:23:58 +00:00
var ret []string
ret = append(ret, walkNames(expr.LHS)...)
ret = append(ret, walkNames(expr.RHS)...)
return ret
case *ParenExpr:
return walkNames(expr.Expr)
}
return nil
}
2015-12-23 18:05:05 +00:00
// ExprNames returns a list of non-"time" field names from an expression.
func ExprNames(expr Expr) []string {
m := make(map[string]struct{})
for _, name := range walkNames(expr) {
if name == "time" {
continue
}
m[name] = struct{}{}
}
a := make([]string, 0, len(m))
for k := range m {
a = append(a, k)
}
sort.Strings(a)
return a
}
// FunctionCalls returns the Call objects from the query
func (s *SelectStatement) FunctionCalls() []*Call {
var a []*Call
for _, f := range s.Fields {
a = append(a, walkFunctionCalls(f.Expr)...)
}
return a
}
2015-09-23 14:47:24 +00:00
// FunctionCallsByPosition returns the Call objects from the query in the order they appear in the select statement
func (s *SelectStatement) FunctionCallsByPosition() [][]*Call {
2015-09-18 14:57:10 +00:00
var a [][]*Call
for _, f := range s.Fields {
a = append(a, walkFunctionCalls(f.Expr))
}
return a
}
// walkFunctionCalls walks the Field of a query for any function calls made
func walkFunctionCalls(exp Expr) []*Call {
switch expr := exp.(type) {
case *VarRef:
return nil
case *Call:
return []*Call{expr}
case *BinaryExpr:
var ret []*Call
ret = append(ret, walkFunctionCalls(expr.LHS)...)
ret = append(ret, walkFunctionCalls(expr.RHS)...)
return ret
case *ParenExpr:
return walkFunctionCalls(expr.Expr)
}
return nil
}
2014-12-31 22:34:46 +00:00
// filters an expression to exclude expressions unrelated to a source.
func filterExprBySource(name string, expr Expr) Expr {
switch expr := expr.(type) {
case *VarRef:
if !strings.HasPrefix(expr.Val, name) {
return nil
}
case *BinaryExpr:
lhs := filterExprBySource(name, expr.LHS)
rhs := filterExprBySource(name, expr.RHS)
// If an expr is logical then return either LHS/RHS or both.
// If an expr is arithmetic or comparative then require both sides.
if expr.Op == AND || expr.Op == OR {
if lhs == nil && rhs == nil {
return nil
} else if lhs != nil && rhs == nil {
return lhs
} else if lhs == nil && rhs != nil {
return rhs
}
} else {
if lhs == nil || rhs == nil {
return nil
}
}
return &BinaryExpr{Op: expr.Op, LHS: lhs, RHS: rhs}
case *ParenExpr:
exp := filterExprBySource(name, expr.Expr)
if exp == nil {
return nil
}
return &ParenExpr{Expr: exp}
}
return expr
}
// MatchSource returns the source name that matches a field name.
// Returns a blank string if no sources match.
2015-03-06 13:52:25 +00:00
func MatchSource(sources Sources, name string) string {
for _, src := range sources {
switch src := src.(type) {
case *Measurement:
if strings.HasPrefix(name, src.Name) {
return src.Name
}
}
}
return ""
}
2015-06-11 11:48:26 +00:00
// Target represents a target (destination) policy, measurement, and DB.
type Target struct {
// Measurement to write into.
Measurement *Measurement
}
// String returns a string representation of the Target.
func (t *Target) String() string {
if t == nil {
return ""
}
var buf bytes.Buffer
_, _ = buf.WriteString("INTO ")
_, _ = buf.WriteString(t.Measurement.String())
if t.Measurement.Name == "" {
_, _ = buf.WriteString(":MEASUREMENT")
}
return buf.String()
}
2014-11-22 04:12:48 +00:00
// DeleteStatement represents a command for removing data from the database.
type DeleteStatement struct {
2014-11-15 19:04:30 +00:00
// Data source that values are removed from.
2014-11-22 04:12:48 +00:00
Source Source
2014-11-15 19:04:30 +00:00
// An expression evaluated on data point.
Condition Expr
}
// String returns a string representation of the delete statement.
func (s *DeleteStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("DELETE FROM ")
_, _ = buf.WriteString(s.Source.String())
if s.Condition != nil {
_, _ = buf.WriteString(" WHERE ")
_, _ = buf.WriteString(s.Condition.String())
}
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a DeleteStatement.
2015-01-19 20:12:48 +00:00
func (s *DeleteStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: WritePrivilege}}
2015-01-19 20:12:48 +00:00
}
2015-01-26 03:40:50 +00:00
// ShowSeriesStatement represents a command for listing series in the database.
type ShowSeriesStatement struct {
2015-01-28 04:36:19 +00:00
// Measurement(s) the series are listed for.
Sources Sources
2015-01-28 04:36:19 +00:00
// An expression evaluated on a series name or tag.
Condition Expr
// Fields to sort results by
SortFields SortFields
// Maximum number of rows to be returned.
// Unlimited if zero.
Limit int
2015-01-25 20:34:49 +00:00
// Returns rows starting at an offset from the first row.
Offset int
}
// String returns a string representation of the list series statement.
2015-01-26 03:40:50 +00:00
func (s *ShowSeriesStatement) String() string {
var buf bytes.Buffer
2015-01-26 03:40:50 +00:00
_, _ = buf.WriteString("SHOW SERIES")
if s.Sources != nil {
_, _ = buf.WriteString(" FROM ")
_, _ = buf.WriteString(s.Sources.String())
}
if s.Condition != nil {
_, _ = buf.WriteString(" WHERE ")
_, _ = buf.WriteString(s.Condition.String())
}
if len(s.SortFields) > 0 {
_, _ = buf.WriteString(" ORDER BY ")
_, _ = buf.WriteString(s.SortFields.String())
}
if s.Limit > 0 {
_, _ = buf.WriteString(" LIMIT ")
_, _ = buf.WriteString(strconv.Itoa(s.Limit))
}
2015-01-25 20:34:49 +00:00
if s.Offset > 0 {
_, _ = buf.WriteString(" OFFSET ")
_, _ = buf.WriteString(strconv.Itoa(s.Offset))
}
return buf.String()
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a ShowSeriesStatement.
2015-01-26 03:40:50 +00:00
func (s *ShowSeriesStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
}
// DropSeriesStatement represents a command for removing a series from the database.
type DropSeriesStatement struct {
2015-02-17 23:29:25 +00:00
// Data source that fields are extracted from (optional)
Sources Sources
2015-02-17 23:29:25 +00:00
// An expression evaluated on data point (optional)
Condition Expr
}
// String returns a string representation of the drop series statement.
2015-02-17 23:29:25 +00:00
func (s *DropSeriesStatement) String() string {
var buf bytes.Buffer
buf.WriteString("DROP SERIES")
2015-02-17 23:29:25 +00:00
if s.Sources != nil {
buf.WriteString(" FROM ")
buf.WriteString(s.Sources.String())
}
if s.Condition != nil {
buf.WriteString(" WHERE ")
buf.WriteString(s.Condition.String())
2015-02-17 23:29:25 +00:00
}
return buf.String()
}
// RequiredPrivileges returns the privilege required to execute a DropSeriesStatement.
2015-01-19 20:12:48 +00:00
func (s DropSeriesStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: WritePrivilege}}
2015-01-19 20:12:48 +00:00
}
2015-10-03 02:49:11 +00:00
// DropServerStatement represents a command for removing a server from the cluster.
type DropServerStatement struct {
// ID of the node to be dropped.
NodeID uint64
// Meta indicates if the server being dropped is a meta or data node
Meta bool
2015-10-03 02:49:11 +00:00
}
// String returns a string representation of the drop series statement.
func (s *DropServerStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("DROP ")
if s.Meta {
_, _ = buf.WriteString(" META SERVER ")
} else {
_, _ = buf.WriteString(" DATA SERVER ")
2015-10-03 02:49:11 +00:00
}
_, _ = buf.WriteString(strconv.FormatUint(s.NodeID, 10))
2015-10-03 02:49:11 +00:00
return buf.String()
}
// RequiredPrivileges returns the privilege required to execute a DropServerStatement.
func (s *DropServerStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Name: "", Privilege: AllPrivileges}}
}
2015-01-26 03:40:50 +00:00
// ShowContinuousQueriesStatement represents a command for listing continuous queries.
type ShowContinuousQueriesStatement struct{}
// String returns a string representation of the list continuous queries statement.
2015-01-26 03:40:50 +00:00
func (s *ShowContinuousQueriesStatement) String() string { return "SHOW CONTINUOUS QUERIES" }
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a ShowContinuousQueriesStatement.
2015-01-26 03:40:50 +00:00
func (s *ShowContinuousQueriesStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
}
// ShowGrantsForUserStatement represents a command for listing user privileges.
type ShowGrantsForUserStatement struct {
// Name of the user to display privileges.
Name string
}
// String returns a string representation of the show grants for user.
func (s *ShowGrantsForUserStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("SHOW GRANTS FOR ")
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(s.Name))
return buf.String()
}
// RequiredPrivileges returns the privilege required to execute a ShowGrantsForUserStatement
func (s *ShowGrantsForUserStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
2015-03-10 19:46:05 +00:00
// ShowServersStatement represents a command for listing all servers.
type ShowServersStatement struct{}
// String returns a string representation of the show servers command.
func (s *ShowServersStatement) String() string { return "SHOW SERVERS" }
// RequiredPrivileges returns the privilege required to execute a ShowServersStatement
func (s *ShowServersStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-03-10 19:46:05 +00:00
}
2015-01-26 03:40:50 +00:00
// ShowDatabasesStatement represents a command for listing all databases in the cluster.
type ShowDatabasesStatement struct{}
2015-01-09 15:47:57 +00:00
// String returns a string representation of the list databases command.
2015-01-26 03:40:50 +00:00
func (s *ShowDatabasesStatement) String() string { return "SHOW DATABASES" }
2015-01-09 15:47:57 +00:00
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a ShowDatabasesStatement
2015-01-26 03:40:50 +00:00
func (s *ShowDatabasesStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
2015-02-01 18:47:48 +00:00
// CreateContinuousQueryStatement represents a command for creating a continuous query.
2014-11-25 04:49:09 +00:00
type CreateContinuousQueryStatement struct {
// Name of the continuous query to be created.
Name string
// Name of the database to create the continuous query on.
Database string
// Source of data (SELECT statement).
2014-11-25 04:49:09 +00:00
Source *SelectStatement
Add continuous query option for customizing resampling This makes the following syntax possible: CREATE CONTINUOUS QUERY mycq ON mydb RESAMPLE EVERY 1m FOR 1h BEGIN SELECT mean(value) INTO cpu_mean FROM cpu GROUP BY time(5m) END The RESAMPLE option customizes how often an interval will be sampled and the duration. The interval is customized with EVERY. Any intervals within the resampling duration on a multiple of the resample interval will be updated with the new results from the query. The duration is customized with FOR. This determines how long an interval will participate in resampling. Both options are optional. If RESAMPLE is in the syntax, at least one of the two needs to be given. The default for both is the interval of the continuous query. The service also improves tracking of the last run time and the logic of when a query for an interval should be run. When determining the oldest interval to run for a query, the continuous query service determines what would have been the optimal time to perform the next query based on the last run time. It then uses this time to determine the oldest interval that should be run using the resample duration and will resample all intervals between this time and the current time as opposed to potentially forgetting about the last run in an interval if the continuous query service gets delayed for some reason. This removes the previous config options for customizing continuous queries since they are no longer relevant and adds a new option of customizing the run interval. The run interval determines how often the continuous query service polls for when it should execute a query. This option defaults to 1s, but can be set to 1m if the least common factor of all continuous queries' intervals is a higher value (like 1m).
2015-12-18 20:32:05 +00:00
// Interval to resample previous queries
ResampleEvery time.Duration
// Maximum duration to resample previous queries
ResampleFor time.Duration
2014-11-25 04:49:09 +00:00
}
// String returns a string representation of the statement.
func (s *CreateContinuousQueryStatement) String() string {
Add continuous query option for customizing resampling This makes the following syntax possible: CREATE CONTINUOUS QUERY mycq ON mydb RESAMPLE EVERY 1m FOR 1h BEGIN SELECT mean(value) INTO cpu_mean FROM cpu GROUP BY time(5m) END The RESAMPLE option customizes how often an interval will be sampled and the duration. The interval is customized with EVERY. Any intervals within the resampling duration on a multiple of the resample interval will be updated with the new results from the query. The duration is customized with FOR. This determines how long an interval will participate in resampling. Both options are optional. If RESAMPLE is in the syntax, at least one of the two needs to be given. The default for both is the interval of the continuous query. The service also improves tracking of the last run time and the logic of when a query for an interval should be run. When determining the oldest interval to run for a query, the continuous query service determines what would have been the optimal time to perform the next query based on the last run time. It then uses this time to determine the oldest interval that should be run using the resample duration and will resample all intervals between this time and the current time as opposed to potentially forgetting about the last run in an interval if the continuous query service gets delayed for some reason. This removes the previous config options for customizing continuous queries since they are no longer relevant and adds a new option of customizing the run interval. The run interval determines how often the continuous query service polls for when it should execute a query. This option defaults to 1s, but can be set to 1m if the least common factor of all continuous queries' intervals is a higher value (like 1m).
2015-12-18 20:32:05 +00:00
var buf bytes.Buffer
fmt.Fprintf(&buf, "CREATE CONTINUOUS QUERY %s ON %s ", QuoteIdent(s.Name), QuoteIdent(s.Database))
if s.ResampleEvery > 0 || s.ResampleFor > 0 {
buf.WriteString("RESAMPLE ")
if s.ResampleEvery > 0 {
fmt.Fprintf(&buf, "EVERY %s ", FormatDuration(s.ResampleEvery))
}
if s.ResampleFor > 0 {
fmt.Fprintf(&buf, "FOR %s ", FormatDuration(s.ResampleFor))
}
}
fmt.Fprintf(&buf, "BEGIN %s END", s.Source.String())
return buf.String()
}
// DefaultDatabase returns the default database from the statement.
func (s *CreateContinuousQueryStatement) DefaultDatabase() string {
return s.Database
}
2015-02-01 18:47:48 +00:00
// RequiredPrivileges returns the privilege required to execute a CreateContinuousQueryStatement.
2015-01-19 20:12:48 +00:00
func (s *CreateContinuousQueryStatement) RequiredPrivileges() ExecutionPrivileges {
ep := ExecutionPrivileges{{Admin: false, Name: s.Database, Privilege: ReadPrivilege}}
// Selecting into a database that's different from the source?
if s.Source.Target.Measurement.Database != "" {
// Change source database privilege requirement to read.
ep[0].Privilege = ReadPrivilege
// Add destination database privilege requirement and set it to write.
p := ExecutionPrivilege{
Admin: false,
Name: s.Source.Target.Measurement.Database,
Privilege: WritePrivilege,
}
ep = append(ep, p)
}
return ep
2015-01-19 20:12:48 +00:00
}
func (s *CreateContinuousQueryStatement) validate() error {
interval, err := s.Source.GroupByInterval()
if err != nil {
return err
}
if s.ResampleFor != 0 {
if s.ResampleEvery != 0 && s.ResampleEvery > interval {
interval = s.ResampleEvery
}
if interval > s.ResampleFor {
return fmt.Errorf("FOR duration must be >= GROUP BY time duration: must be a minimum of %s, got %s", FormatDuration(interval), FormatDuration(s.ResampleFor))
}
}
return nil
}
2015-02-01 18:47:48 +00:00
// DropContinuousQueryStatement represents a command for removing a continuous query.
type DropContinuousQueryStatement struct {
2015-03-25 00:11:26 +00:00
Name string
Database string
}
// String returns a string representation of the statement.
func (s *DropContinuousQueryStatement) String() string {
return fmt.Sprintf("DROP CONTINUOUS QUERY %s ON %s", QuoteIdent(s.Name), QuoteIdent(s.Database))
}
2015-01-19 20:12:48 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a DropContinuousQueryStatement
func (s *DropContinuousQueryStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: WritePrivilege}}
2015-01-19 20:12:48 +00:00
}
2015-01-26 03:40:50 +00:00
// ShowMeasurementsStatement represents a command for listing measurements.
type ShowMeasurementsStatement struct {
// Measurement name or regex.
Source Source
// An expression evaluated on data point.
Condition Expr
// Fields to sort results by
SortFields SortFields
// Maximum number of rows to be returned.
// Unlimited if zero.
Limit int
2015-01-25 20:34:49 +00:00
// Returns rows starting at an offset from the first row.
Offset int
}
// String returns a string representation of the statement.
2015-01-26 03:40:50 +00:00
func (s *ShowMeasurementsStatement) String() string {
2014-12-16 14:06:28 +00:00
var buf bytes.Buffer
2015-01-26 03:40:50 +00:00
_, _ = buf.WriteString("SHOW MEASUREMENTS")
2015-11-22 20:38:48 +00:00
if s.Source != nil {
_, _ = buf.WriteString(" WITH MEASUREMENT ")
if m, ok := s.Source.(*Measurement); ok && m.Regex != nil {
_, _ = buf.WriteString("=~ ")
} else {
_, _ = buf.WriteString("= ")
}
_, _ = buf.WriteString(s.Source.String())
}
if s.Condition != nil {
_, _ = buf.WriteString(" WHERE ")
_, _ = buf.WriteString(s.Condition.String())
}
if len(s.SortFields) > 0 {
_, _ = buf.WriteString(" ORDER BY ")
_, _ = buf.WriteString(s.SortFields.String())
}
if s.Limit > 0 {
_, _ = buf.WriteString(" LIMIT ")
_, _ = buf.WriteString(strconv.Itoa(s.Limit))
}
2015-01-25 20:34:49 +00:00
if s.Offset > 0 {
_, _ = buf.WriteString(" OFFSET ")
_, _ = buf.WriteString(strconv.Itoa(s.Offset))
}
return buf.String()
}
2015-01-26 03:40:50 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a ShowMeasurementsStatement
func (s *ShowMeasurementsStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
}
2015-06-11 11:48:26 +00:00
// DropMeasurementStatement represents a command to drop a measurement.
2015-02-23 20:51:52 +00:00
type DropMeasurementStatement struct {
// Name of the measurement to be dropped.
Name string
}
// String returns a string representation of the drop measurement statement.
func (s *DropMeasurementStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("DROP MEASUREMENT ")
_, _ = buf.WriteString(QuoteIdent(s.Name))
2015-02-23 20:51:52 +00:00
return buf.String()
}
// RequiredPrivileges returns the privilege(s) required to execute a DropMeasurementStatement
func (s *DropMeasurementStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-02-23 20:51:52 +00:00
}
2015-01-26 03:40:50 +00:00
// ShowRetentionPoliciesStatement represents a command for listing retention policies.
type ShowRetentionPoliciesStatement struct {
// Name of the database to list policies for.
Database string
}
2015-01-26 03:40:50 +00:00
// String returns a string representation of a ShowRetentionPoliciesStatement.
func (s *ShowRetentionPoliciesStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("SHOW RETENTION POLICIES ON ")
_, _ = buf.WriteString(QuoteIdent(s.Database))
return buf.String()
}
2015-01-26 03:40:50 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a ShowRetentionPoliciesStatement
func (s *ShowRetentionPoliciesStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
}
2015-09-22 23:28:24 +00:00
// ShowStats statement displays statistics for a given module.
2015-03-12 23:07:41 +00:00
type ShowStatsStatement struct {
2015-09-22 23:28:24 +00:00
// Module
Module string
2015-03-12 23:07:41 +00:00
}
// String returns a string representation of a ShowStatsStatement.
func (s *ShowStatsStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("SHOW STATS ")
2015-09-22 23:28:24 +00:00
if s.Module != "" {
_, _ = buf.WriteString("FOR ")
2015-09-22 23:28:24 +00:00
_, _ = buf.WriteString(s.Module)
2015-03-12 23:07:41 +00:00
}
return buf.String()
}
// RequiredPrivileges returns the privilege(s) required to execute a ShowStatsStatement
func (s *ShowStatsStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
2015-11-13 23:26:30 +00:00
// ShowShardGroupsStatement represents a command for displaying shard groups in the cluster.
type ShowShardGroupsStatement struct{}
// String returns a string representation of the SHOW SHARD GROUPS command.
func (s *ShowShardGroupsStatement) String() string { return "SHOW SHARD GROUPS" }
// RequiredPrivileges returns the privileges required to execute the statement.
func (s *ShowShardGroupsStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
// ShowShardsStatement represents a command for displaying shards in the cluster.
type ShowShardsStatement struct{}
// String returns a string representation.
func (s *ShowShardsStatement) String() string { return "SHOW SHARDS" }
// RequiredPrivileges returns the privileges required to execute the statement.
func (s *ShowShardsStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-03-12 23:07:41 +00:00
}
2015-03-24 03:13:54 +00:00
// ShowDiagnosticsStatement represents a command for show node diagnostics.
type ShowDiagnosticsStatement struct {
// Module
Module string
}
2015-03-24 03:13:54 +00:00
// String returns a string representation of the ShowDiagnosticsStatement.
func (s *ShowDiagnosticsStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("SHOW DIAGNOSTICS ")
if s.Module != "" {
_, _ = buf.WriteString("FOR ")
_, _ = buf.WriteString(s.Module)
}
return buf.String()
}
2015-03-24 03:13:54 +00:00
// RequiredPrivileges returns the privilege required to execute a ShowDiagnosticsStatement
func (s *ShowDiagnosticsStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-03-24 03:13:54 +00:00
}
// CreateSubscriptionStatement represents a command to add a subscription to the incoming data stream
type CreateSubscriptionStatement struct {
Name string
Database string
RetentionPolicy string
Destinations []string
Mode string
}
// String returns a string representation of the CreateSubscriptionStatement.
func (s *CreateSubscriptionStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("CREATE SUBSCRIPTION ")
_, _ = buf.WriteString(QuoteIdent(s.Name))
_, _ = buf.WriteString(" ON ")
_, _ = buf.WriteString(QuoteIdent(s.Database))
_, _ = buf.WriteString(".")
_, _ = buf.WriteString(QuoteIdent(s.RetentionPolicy))
_, _ = buf.WriteString(" DESTINATIONS ")
_, _ = buf.WriteString(s.Mode)
_, _ = buf.WriteString(" ")
for i, dest := range s.Destinations {
if i != 0 {
_, _ = buf.WriteString(", ")
}
_, _ = buf.WriteString(QuoteString(dest))
}
return buf.String()
}
// RequiredPrivileges returns the privilege required to execute a CreateSubscriptionStatement
func (s *CreateSubscriptionStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
// DropSubscriptionStatement represents a command to drop a subscription to the incoming data stream.
type DropSubscriptionStatement struct {
Name string
Database string
RetentionPolicy string
}
// String returns a string representation of the DropSubscriptionStatement.
func (s *DropSubscriptionStatement) String() string {
return fmt.Sprintf(`DROP SUBSCRIPTION %s ON %s.%s`, QuoteIdent(s.Name), QuoteIdent(s.Database), QuoteIdent(s.RetentionPolicy))
}
// RequiredPrivileges returns the privilege required to execute a DropSubscriptionStatement
func (s *DropSubscriptionStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
// ShowSubscriptionsStatement represents a command to show a list of subscriptions.
type ShowSubscriptionsStatement struct {
}
// String returns a string representation of the ShowSubscriptionStatement.
func (s *ShowSubscriptionsStatement) String() string {
return "SHOW SUBSCRIPTIONS"
}
// RequiredPrivileges returns the privilege required to execute a ShowSubscriptionStatement
func (s *ShowSubscriptionsStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
}
2015-01-26 03:40:50 +00:00
// ShowTagKeysStatement represents a command for listing tag keys.
type ShowTagKeysStatement struct {
// Data sources that fields are extracted from.
Sources Sources
// An expression evaluated on data point.
Condition Expr
// Fields to sort results by
SortFields SortFields
// Maximum number of tag keys per measurement. Unlimited if zero.
Limit int
2015-01-25 20:34:49 +00:00
// Returns tag keys starting at an offset from the first row.
2015-01-25 20:34:49 +00:00
Offset int
// Maxiumum number of series to be returned. Unlimited if zero.
SLimit int
// Returns series starting at an offset from the first one.
SOffset int
}
// String returns a string representation of the statement.
2015-01-26 03:40:50 +00:00
func (s *ShowTagKeysStatement) String() string {
2014-12-16 14:06:28 +00:00
var buf bytes.Buffer
2015-01-26 03:40:50 +00:00
_, _ = buf.WriteString("SHOW TAG KEYS")
if s.Sources != nil {
_, _ = buf.WriteString(" FROM ")
_, _ = buf.WriteString(s.Sources.String())
}
if s.Condition != nil {
_, _ = buf.WriteString(" WHERE ")
_, _ = buf.WriteString(s.Condition.String())
}
if len(s.SortFields) > 0 {
_, _ = buf.WriteString(" ORDER BY ")
_, _ = buf.WriteString(s.SortFields.String())
}
if s.Limit > 0 {
_, _ = buf.WriteString(" LIMIT ")
_, _ = buf.WriteString(strconv.Itoa(s.Limit))
}
2015-01-25 20:34:49 +00:00
if s.Offset > 0 {
_, _ = buf.WriteString(" OFFSET ")
_, _ = buf.WriteString(strconv.Itoa(s.Offset))
}
if s.SLimit > 0 {
_, _ = buf.WriteString(" SLIMIT ")
_, _ = buf.WriteString(strconv.Itoa(s.SLimit))
}
if s.SOffset > 0 {
_, _ = buf.WriteString(" SOFFSET ")
_, _ = buf.WriteString(strconv.Itoa(s.SOffset))
}
return buf.String()
}
2015-01-26 03:40:50 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a ShowTagKeysStatement
func (s *ShowTagKeysStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
}
2015-01-26 03:40:50 +00:00
// ShowTagValuesStatement represents a command for listing tag values.
type ShowTagValuesStatement struct {
// Data source that fields are extracted from.
Sources Sources
// Tag key(s) to pull values from.
TagKeys []string
// An expression evaluated on data point.
Condition Expr
// Fields to sort results by
SortFields SortFields
// Maximum number of rows to be returned.
// Unlimited if zero.
Limit int
2015-01-25 20:34:49 +00:00
// Returns rows starting at an offset from the first row.
Offset int
}
// String returns a string representation of the statement.
2015-01-26 03:40:50 +00:00
func (s *ShowTagValuesStatement) String() string {
2014-12-16 14:06:28 +00:00
var buf bytes.Buffer
2015-01-26 03:40:50 +00:00
_, _ = buf.WriteString("SHOW TAG VALUES")
if s.Sources != nil {
_, _ = buf.WriteString(" FROM ")
_, _ = buf.WriteString(s.Sources.String())
}
_, _ = buf.WriteString(" WITH KEY IN (")
for idx, tagKey := range s.TagKeys {
if idx != 0 {
_, _ = buf.WriteString(", ")
}
_, _ = buf.WriteString(QuoteIdent(tagKey))
}
_, _ = buf.WriteString(")")
if s.Condition != nil {
_, _ = buf.WriteString(" WHERE ")
_, _ = buf.WriteString(s.Condition.String())
}
if len(s.SortFields) > 0 {
_, _ = buf.WriteString(" ORDER BY ")
_, _ = buf.WriteString(s.SortFields.String())
}
if s.Limit > 0 {
_, _ = buf.WriteString(" LIMIT ")
_, _ = buf.WriteString(strconv.Itoa(s.Limit))
}
2015-01-25 20:34:49 +00:00
if s.Offset > 0 {
_, _ = buf.WriteString(" OFFSET ")
_, _ = buf.WriteString(strconv.Itoa(s.Offset))
}
return buf.String()
}
2015-01-26 03:40:50 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a ShowTagValuesStatement
func (s *ShowTagValuesStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
}
2015-01-26 03:40:50 +00:00
// ShowUsersStatement represents a command for listing users.
type ShowUsersStatement struct{}
2015-01-14 16:53:17 +00:00
// String returns a string representation of the ShowUsersStatement.
2015-01-26 03:40:50 +00:00
func (s *ShowUsersStatement) String() string {
return "SHOW USERS"
2015-01-14 16:53:17 +00:00
}
2015-01-26 03:40:50 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a ShowUsersStatement
func (s *ShowUsersStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}
2015-01-19 20:12:48 +00:00
}
2015-02-01 18:47:48 +00:00
// ShowFieldKeysStatement represents a command for listing field keys.
2015-01-26 03:40:50 +00:00
type ShowFieldKeysStatement struct {
// Data sources that fields are extracted from.
Sources Sources
// Fields to sort results by
SortFields SortFields
// Maximum number of rows to be returned.
// Unlimited if zero.
Limit int
2015-01-25 20:34:49 +00:00
// Returns rows starting at an offset from the first row.
Offset int
}
// String returns a string representation of the statement.
2015-01-26 03:40:50 +00:00
func (s *ShowFieldKeysStatement) String() string {
2014-12-16 14:06:28 +00:00
var buf bytes.Buffer
2015-01-26 03:40:50 +00:00
_, _ = buf.WriteString("SHOW FIELD KEYS")
if s.Sources != nil {
_, _ = buf.WriteString(" FROM ")
_, _ = buf.WriteString(s.Sources.String())
}
if len(s.SortFields) > 0 {
_, _ = buf.WriteString(" ORDER BY ")
_, _ = buf.WriteString(s.SortFields.String())
}
if s.Limit > 0 {
_, _ = buf.WriteString(" LIMIT ")
_, _ = buf.WriteString(strconv.Itoa(s.Limit))
}
2015-01-25 20:34:49 +00:00
if s.Offset > 0 {
_, _ = buf.WriteString(" OFFSET ")
_, _ = buf.WriteString(strconv.Itoa(s.Offset))
}
return buf.String()
}
2015-01-26 03:40:50 +00:00
// RequiredPrivileges returns the privilege(s) required to execute a ShowFieldKeysStatement
func (s *ShowFieldKeysStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}
2015-01-19 20:12:48 +00:00
}
2014-11-15 19:04:30 +00:00
// Fields represents a list of fields.
type Fields []*Field
2015-08-05 18:37:02 +00:00
// AliasNames returns a list of calculated field names in
// order of alias, function name, then field.
func (a Fields) AliasNames() []string {
names := []string{}
for _, f := range a {
names = append(names, f.Name())
}
return names
}
2015-12-09 07:27:33 +00:00
// Names returns a list of field names.
2015-08-05 18:37:02 +00:00
func (a Fields) Names() []string {
names := []string{}
for _, f := range a {
switch expr := f.Expr.(type) {
case *Call:
names = append(names, expr.Name)
2015-08-05 18:37:02 +00:00
case *VarRef:
names = append(names, expr.Val)
case *BinaryExpr:
names = append(names, walkNames(expr)...)
2015-12-09 07:27:33 +00:00
case *ParenExpr:
names = append(names, walkNames(expr)...)
2015-08-05 18:37:02 +00:00
}
}
return names
}
// String returns a string representation of the fields.
func (a Fields) String() string {
var str []string
for _, f := range a {
str = append(str, f.String())
}
return strings.Join(str, ", ")
}
2014-11-22 04:12:48 +00:00
// Field represents an expression retrieved from a select statement.
2014-11-15 19:04:30 +00:00
type Field struct {
Expr Expr
Alias string
2014-12-08 05:08:39 +00:00
}
// Name returns the name of the field. Returns alias, if set.
// Otherwise uses the function name or variable name.
func (f *Field) Name() string {
// Return alias, if set.
if f.Alias != "" {
return f.Alias
}
// Return the function name or variable name, if available.
switch expr := f.Expr.(type) {
case *Call:
return expr.Name
case *VarRef:
return expr.Val
}
// Otherwise return a blank name.
return ""
2014-11-15 19:04:30 +00:00
}
// String returns a string representation of the field.
func (f *Field) String() string {
str := f.Expr.String()
if f.Alias == "" {
return str
}
2015-12-20 00:23:51 +00:00
return fmt.Sprintf("%s AS %s", str, QuoteIdent(f.Alias))
}
2015-03-13 22:52:49 +00:00
// Sort Interface for Fields
func (f Fields) Len() int { return len(f) }
func (f Fields) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
func (f Fields) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
2014-11-15 19:04:30 +00:00
// Dimensions represents a list of dimensions.
type Dimensions []*Dimension
// String returns a string representation of the dimensions.
func (a Dimensions) String() string {
var str []string
for _, d := range a {
str = append(str, d.String())
}
return strings.Join(str, ", ")
}
2015-01-23 09:44:56 +00:00
// Normalize returns the interval and tag dimensions separately.
// Returns 0 if no time interval is specified.
func (a Dimensions) Normalize() (time.Duration, []string) {
2015-01-23 09:44:56 +00:00
var dur time.Duration
var tags []string
for _, dim := range a {
switch expr := dim.Expr.(type) {
case *Call:
lit, _ := expr.Args[0].(*DurationLiteral)
dur = lit.Val
2015-01-23 09:44:56 +00:00
case *VarRef:
tags = append(tags, expr.Val)
}
}
return dur, tags
2015-01-23 09:44:56 +00:00
}
2014-11-22 04:12:48 +00:00
// Dimension represents an expression that a select statement is grouped by.
2014-11-15 19:04:30 +00:00
type Dimension struct {
2014-11-22 04:12:48 +00:00
Expr Expr
2014-11-15 19:04:30 +00:00
}
// String returns a string representation of the dimension.
func (d *Dimension) String() string { return d.Expr.String() }
// Measurements represents a list of measurements.
type Measurements []*Measurement
// String returns a string representation of the measurements.
func (a Measurements) String() string {
var str []string
for _, m := range a {
str = append(str, m.String())
}
return strings.Join(str, ", ")
}
// Measurement represents a single measurement used as a datasource.
type Measurement struct {
Database string
RetentionPolicy string
Name string
Regex *RegexLiteral
IsTarget bool
2014-11-15 19:04:30 +00:00
}
// String returns a string representation of the measurement.
2015-03-06 13:52:25 +00:00
func (m *Measurement) String() string {
var buf bytes.Buffer
if m.Database != "" {
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(m.Database))
_, _ = buf.WriteString(".")
2015-03-06 13:52:25 +00:00
}
if m.RetentionPolicy != "" {
2015-11-22 21:08:51 +00:00
_, _ = buf.WriteString(QuoteIdent(m.RetentionPolicy))
}
if m.Database != "" || m.RetentionPolicy != "" {
_, _ = buf.WriteString(`.`)
}
2014-11-15 19:04:30 +00:00
if m.Name != "" {
_, _ = buf.WriteString(QuoteIdent(m.Name))
} else if m.Regex != nil {
_, _ = buf.WriteString(m.Regex.String())
}
return buf.String()
2014-11-15 19:04:30 +00:00
}
2014-11-22 04:12:48 +00:00
// VarRef represents a reference to a variable.
2014-11-15 19:04:30 +00:00
type VarRef struct {
Val string
}
// String returns a string representation of the variable reference.
func (r *VarRef) String() string {
return QuoteIdent(r.Val)
}
2014-11-15 19:04:30 +00:00
// Call represents a function call.
type Call struct {
Name string
2014-11-25 03:43:23 +00:00
Args []Expr
2014-11-15 19:04:30 +00:00
}
// String returns a string representation of the call.
func (c *Call) String() string {
// Join arguments.
var str []string
for _, arg := range c.Args {
str = append(str, arg.String())
}
// Write function name and args.
return fmt.Sprintf("%s(%s)", c.Name, strings.Join(str, ", "))
}
2015-09-02 17:26:40 +00:00
// Fields will extract any field names from the call. Only specific calls support this.
func (c *Call) Fields() []string {
switch c.Name {
case "top", "bottom":
2015-09-04 18:41:46 +00:00
// maintain the order the user specified in the query
2015-09-02 17:26:40 +00:00
keyMap := make(map[string]struct{})
keys := []string{}
for i, a := range c.Args {
if i == 0 {
2015-09-04 18:41:46 +00:00
// special case, first argument is always the name of the function regardless of the field name
keys = append(keys, c.Name)
continue
}
2015-09-02 17:26:40 +00:00
switch v := a.(type) {
case *VarRef:
if _, ok := keyMap[v.Val]; !ok {
keyMap[v.Val] = struct{}{}
keys = append(keys, v.Val)
}
}
}
return keys
2015-09-18 14:57:10 +00:00
case "min", "max", "first", "last", "sum", "mean":
// maintain the order the user specified in the query
keyMap := make(map[string]struct{})
keys := []string{}
for _, a := range c.Args {
switch v := a.(type) {
case *VarRef:
if _, ok := keyMap[v.Val]; !ok {
keyMap[v.Val] = struct{}{}
keys = append(keys, v.Val)
}
}
}
return keys
2015-09-02 17:26:40 +00:00
default:
2015-09-18 14:57:10 +00:00
panic(fmt.Sprintf("*call.Fields is unable to provide information on %s", c.Name))
2015-09-02 17:26:40 +00:00
}
}
// Distinct represents a DISTINCT expression.
type Distinct struct {
// Identifier following DISTINCT
Val string
}
// String returns a string representation of the expression.
func (d *Distinct) String() string {
return fmt.Sprintf("DISTINCT %s", d.Val)
}
// NewCall returns a new call expression from this expressions.
func (d *Distinct) NewCall() *Call {
return &Call{
Name: "distinct",
Args: []Expr{
&VarRef{Val: d.Val},
},
}
}
2014-11-22 04:12:48 +00:00
// NumberLiteral represents a numeric literal.
type NumberLiteral struct {
2014-11-15 19:04:30 +00:00
Val float64
}
// String returns a string representation of the literal.
func (l *NumberLiteral) String() string { return strconv.FormatFloat(l.Val, 'f', 3, 64) }
2014-11-22 04:12:48 +00:00
// BooleanLiteral represents a boolean literal.
2014-11-15 19:04:30 +00:00
type BooleanLiteral struct {
Val bool
}
// String returns a string representation of the literal.
func (l *BooleanLiteral) String() string {
if l.Val {
return "true"
}
return "false"
}
2015-01-23 09:44:56 +00:00
// isTrueLiteral returns true if the expression is a literal "true" value.
func isTrueLiteral(expr Expr) bool {
if expr, ok := expr.(*BooleanLiteral); ok {
return expr.Val == true
}
return false
}
// isFalseLiteral returns true if the expression is a literal "false" value.
func isFalseLiteral(expr Expr) bool {
if expr, ok := expr.(*BooleanLiteral); ok {
return expr.Val == false
}
return false
}
2014-11-22 04:12:48 +00:00
// StringLiteral represents a string literal.
2014-11-15 19:04:30 +00:00
type StringLiteral struct {
Val string
}
// String returns a string representation of the literal.
func (l *StringLiteral) String() string { return QuoteString(l.Val) }
2014-11-22 04:12:48 +00:00
// TimeLiteral represents a point-in-time literal.
2014-11-15 19:04:30 +00:00
type TimeLiteral struct {
Val time.Time
}
// String returns a string representation of the literal.
2014-12-11 06:32:45 +00:00
func (l *TimeLiteral) String() string {
return `'` + l.Val.UTC().Format(time.RFC3339Nano) + `'`
2014-12-11 06:32:45 +00:00
}
2014-11-22 04:12:48 +00:00
// DurationLiteral represents a duration literal.
2014-11-15 19:04:30 +00:00
type DurationLiteral struct {
Val time.Duration
}
// String returns a string representation of the literal.
func (l *DurationLiteral) String() string { return FormatDuration(l.Val) }
2015-01-23 09:44:56 +00:00
// nilLiteral represents a nil literal.
// This is not available to the query language itself. It's only used internally.
type nilLiteral struct{}
// String returns a string representation of the literal.
func (l *nilLiteral) String() string { return `nil` }
2014-11-15 19:04:30 +00:00
// BinaryExpr represents an operation between two expressions.
type BinaryExpr struct {
Op Token
LHS Expr
RHS Expr
}
// String returns a string representation of the binary expression.
func (e *BinaryExpr) String() string {
return fmt.Sprintf("%s %s %s", e.LHS.String(), e.Op.String(), e.RHS.String())
}
2014-11-25 06:12:32 +00:00
// ParenExpr represents a parenthesized expression.
type ParenExpr struct {
Expr Expr
}
// String returns a string representation of the parenthesized expression.
func (e *ParenExpr) String() string { return fmt.Sprintf("(%s)", e.Expr.String()) }
// RegexLiteral represents a regular expression.
type RegexLiteral struct {
Val *regexp.Regexp
}
// String returns a string representation of the literal.
2015-03-06 13:52:25 +00:00
func (r *RegexLiteral) String() string {
if r.Val != nil {
return fmt.Sprintf("/%s/", strings.Replace(r.Val.String(), `/`, `\/`, -1))
2015-03-06 13:52:25 +00:00
}
return ""
}
// CloneRegexLiteral returns a clone of the RegexLiteral.
func CloneRegexLiteral(r *RegexLiteral) *RegexLiteral {
if r == nil {
return nil
}
clone := &RegexLiteral{}
if r.Val != nil {
clone.Val = regexp.MustCompile(r.Val.String())
}
return clone
}
2014-11-25 23:23:10 +00:00
// Wildcard represents a wild card expression.
type Wildcard struct{}
// String returns a string representation of the wildcard.
func (e *Wildcard) String() string { return "*" }
2014-11-25 22:43:22 +00:00
2015-01-23 09:44:56 +00:00
// CloneExpr returns a deep copy of the expression.
func CloneExpr(expr Expr) Expr {
if expr == nil {
return nil
}
2014-12-11 06:32:45 +00:00
switch expr := expr.(type) {
case *BinaryExpr:
2015-01-23 09:44:56 +00:00
return &BinaryExpr{Op: expr.Op, LHS: CloneExpr(expr.LHS), RHS: CloneExpr(expr.RHS)}
2014-12-11 06:32:45 +00:00
case *BooleanLiteral:
2015-01-23 09:44:56 +00:00
return &BooleanLiteral{Val: expr.Val}
case *Call:
args := make([]Expr, len(expr.Args))
for i, arg := range expr.Args {
args[i] = CloneExpr(arg)
2014-12-11 06:32:45 +00:00
}
2015-01-23 09:44:56 +00:00
return &Call{Name: expr.Name, Args: args}
case *Distinct:
return &Distinct{Val: expr.Val}
2014-12-11 06:32:45 +00:00
case *DurationLiteral:
2015-01-23 09:44:56 +00:00
return &DurationLiteral{Val: expr.Val}
case *NumberLiteral:
return &NumberLiteral{Val: expr.Val}
case *ParenExpr:
return &ParenExpr{Expr: CloneExpr(expr.Expr)}
2015-02-16 20:30:58 +00:00
case *RegexLiteral:
return &RegexLiteral{Val: expr.Val}
2014-12-11 06:32:45 +00:00
case *StringLiteral:
2015-01-23 09:44:56 +00:00
return &StringLiteral{Val: expr.Val}
case *TimeLiteral:
return &TimeLiteral{Val: expr.Val}
case *VarRef:
return &VarRef{Val: expr.Val}
case *Wildcard:
return &Wildcard{}
2014-12-11 06:32:45 +00:00
}
2015-01-23 09:44:56 +00:00
panic("unreachable")
2014-12-11 06:32:45 +00:00
}
// HasTimeExpr returns true if the expression has a time term.
func HasTimeExpr(expr Expr) bool {
switch n := expr.(type) {
case *BinaryExpr:
if n.Op == AND || n.Op == OR {
return HasTimeExpr(n.LHS) || HasTimeExpr(n.RHS)
}
if ref, ok := n.LHS.(*VarRef); ok && strings.ToLower(ref.Val) == "time" {
return true
}
return false
case *ParenExpr:
// walk down the tree
return HasTimeExpr(n.Expr)
default:
return false
}
}
// OnlyTimeExpr returns true if the expression only has time constraints.
func OnlyTimeExpr(expr Expr) bool {
if expr == nil {
return false
}
switch n := expr.(type) {
case *BinaryExpr:
if n.Op == AND || n.Op == OR {
return OnlyTimeExpr(n.LHS) && OnlyTimeExpr(n.RHS)
}
if ref, ok := n.LHS.(*VarRef); ok && strings.ToLower(ref.Val) == "time" {
return true
}
return false
case *ParenExpr:
// walk down the tree
return OnlyTimeExpr(n.Expr)
default:
return false
}
}
// TimeRange returns the minimum and maximum times specified by an expression.
2014-12-16 15:50:30 +00:00
// Returns zero times if there is no bound.
func TimeRange(expr Expr) (min, max time.Time) {
WalkFunc(expr, func(n Node) {
if n, ok := n.(*BinaryExpr); ok {
// Extract literal expression & operator on LHS.
// Check for "time" on the left-hand side first.
// Otherwise check for for the right-hand side and flip the operator.
value, op := timeExprValue(n.LHS, n.RHS), n.Op
if value.IsZero() {
if value = timeExprValue(n.RHS, n.LHS); value.IsZero() {
return
} else if op == LT {
op = GT
} else if op == LTE {
op = GTE
} else if op == GT {
op = LT
} else if op == GTE {
op = LTE
}
}
// Update the min/max depending on the operator.
// The GT & LT update the value by +/- 1ns not make them "not equal".
switch op {
case GT:
if min.IsZero() || value.After(min) {
min = value.Add(time.Nanosecond)
}
case GTE:
if min.IsZero() || value.After(min) {
min = value
}
case LT:
if max.IsZero() || value.Before(max) {
max = value.Add(-time.Nanosecond)
}
case LTE:
if max.IsZero() || value.Before(max) {
max = value
}
case EQ:
if min.IsZero() || value.After(min) {
min = value
}
2016-02-02 17:19:15 +00:00
if max.IsZero() || value.Add(1*time.Nanosecond).Before(max) {
max = value.Add(1 * time.Nanosecond)
}
}
}
})
return
}
// TimeRange returns the minimum and maximum times, as epoch nano, specified by
// and expression. If there is no lower bound, the start of the epoch is returned
// for minimum. If there is no higher bound, now is returned for maximum.
func TimeRangeAsEpochNano(expr Expr) (min, max int64) {
tmin, tmax := TimeRange(expr)
if tmin.IsZero() {
min = time.Unix(0, 0).UnixNano()
} else {
min = tmin.UnixNano()
}
if tmax.IsZero() {
max = time.Now().UnixNano()
} else {
max = tmax.UnixNano()
}
return
}
// timeExprValue returns the time literal value of a "time == <TimeLiteral>" expression.
// Returns zero time if the expression is not a time expression.
func timeExprValue(ref Expr, lit Expr) time.Time {
if ref, ok := ref.(*VarRef); ok && strings.ToLower(ref.Val) == "time" {
switch lit := lit.(type) {
case *TimeLiteral:
return lit.Val
case *DurationLiteral:
return time.Unix(0, int64(lit.Val)).UTC()
case *NumberLiteral:
return time.Unix(0, int64(lit.Val)).UTC()
}
}
return time.Time{}
}
2014-12-21 22:18:55 +00:00
// Visitor can be called by Walk to traverse an AST hierarchy.
// The Visit() function is called once per node.
type Visitor interface {
Visit(Node) Visitor
}
2014-11-15 19:04:30 +00:00
// Walk traverses a node hierarchy in depth-first order.
func Walk(v Visitor, node Node) {
if node == nil {
return
}
2014-11-15 19:04:30 +00:00
if v = v.Visit(node); v == nil {
return
}
switch n := node.(type) {
case *BinaryExpr:
Walk(v, n.LHS)
Walk(v, n.RHS)
2014-11-22 04:12:48 +00:00
case *Call:
for _, expr := range n.Args {
Walk(v, expr)
}
case *CreateContinuousQueryStatement:
Walk(v, n.Source)
case *Dimension:
Walk(v, n.Expr)
case Dimensions:
for _, c := range n {
Walk(v, c)
}
2015-10-05 23:54:32 +00:00
case *DropSeriesStatement:
Walk(v, n.Sources)
Walk(v, n.Condition)
case *Field:
Walk(v, n.Expr)
case Fields:
for _, c := range n {
Walk(v, c)
2014-11-15 19:04:30 +00:00
}
case *ParenExpr:
Walk(v, n.Expr)
case *Query:
Walk(v, n.Statements)
2014-11-22 04:12:48 +00:00
case *SelectStatement:
Walk(v, n.Fields)
Walk(v, n.Target)
2014-11-22 04:12:48 +00:00
Walk(v, n.Dimensions)
2015-03-06 13:52:25 +00:00
Walk(v, n.Sources)
2014-11-22 04:12:48 +00:00
Walk(v, n.Condition)
Walk(v, n.SortFields)
2014-11-22 04:12:48 +00:00
2015-01-28 04:36:19 +00:00
case *ShowSeriesStatement:
Walk(v, n.Sources)
2015-01-28 04:36:19 +00:00
Walk(v, n.Condition)
2015-01-29 01:26:15 +00:00
case *ShowTagKeysStatement:
Walk(v, n.Sources)
2015-01-29 01:26:15 +00:00
Walk(v, n.Condition)
Walk(v, n.SortFields)
case *ShowTagValuesStatement:
Walk(v, n.Sources)
2015-01-29 01:26:15 +00:00
Walk(v, n.Condition)
Walk(v, n.SortFields)
case *ShowFieldKeysStatement:
Walk(v, n.Sources)
Walk(v, n.SortFields)
case SortFields:
for _, sf := range n {
Walk(v, sf)
}
2015-03-13 22:35:36 +00:00
case Sources:
for _, s := range n {
Walk(v, s)
}
case Statements:
for _, s := range n {
Walk(v, s)
2014-11-15 19:04:30 +00:00
}
case *Target:
if n != nil {
Walk(v, n.Measurement)
2014-11-25 03:43:23 +00:00
}
2014-11-15 19:04:30 +00:00
}
}
// WalkFunc traverses a node hierarchy in depth-first order.
func WalkFunc(node Node, fn func(Node)) {
Walk(walkFuncVisitor(fn), node)
}
type walkFuncVisitor func(Node)
func (fn walkFuncVisitor) Visit(n Node) Visitor { fn(n); return fn }
2014-12-21 22:18:55 +00:00
// Rewriter can be called by Rewrite to replace nodes in the AST hierarchy.
// The Rewrite() function is called once per node.
type Rewriter interface {
Rewrite(Node) Node
}
// Rewrite recursively invokes the rewriter to replace each node.
// Nodes are traversed depth-first and rewritten from leaf to root.
func Rewrite(r Rewriter, node Node) Node {
switch n := node.(type) {
case *Query:
n.Statements = Rewrite(r, n.Statements).(Statements)
case Statements:
for i, s := range n {
n[i] = Rewrite(r, s).(Statement)
}
case *SelectStatement:
n.Fields = Rewrite(r, n.Fields).(Fields)
n.Dimensions = Rewrite(r, n.Dimensions).(Dimensions)
2015-03-06 13:52:25 +00:00
n.Sources = Rewrite(r, n.Sources).(Sources)
2014-12-21 22:18:55 +00:00
n.Condition = Rewrite(r, n.Condition).(Expr)
case Fields:
for i, f := range n {
n[i] = Rewrite(r, f).(*Field)
}
case *Field:
n.Expr = Rewrite(r, n.Expr).(Expr)
case Dimensions:
for i, d := range n {
n[i] = Rewrite(r, d).(*Dimension)
}
case *Dimension:
n.Expr = Rewrite(r, n.Expr).(Expr)
case *BinaryExpr:
n.LHS = Rewrite(r, n.LHS).(Expr)
n.RHS = Rewrite(r, n.RHS).(Expr)
case *ParenExpr:
n.Expr = Rewrite(r, n.Expr).(Expr)
case *Call:
for i, expr := range n.Args {
n.Args[i] = Rewrite(r, expr).(Expr)
}
}
return r.Rewrite(node)
}
// RewriteFunc rewrites a node hierarchy.
func RewriteFunc(node Node, fn func(Node) Node) Node {
return Rewrite(rewriterFunc(fn), node)
}
type rewriterFunc func(Node) Node
func (fn rewriterFunc) Rewrite(n Node) Node { return fn(n) }
2015-01-23 09:44:56 +00:00
2015-01-28 00:20:34 +00:00
// Eval evaluates expr against a map.
func Eval(expr Expr, m map[string]interface{}) interface{} {
if expr == nil {
return nil
}
switch expr := expr.(type) {
case *BinaryExpr:
return evalBinaryExpr(expr, m)
case *BooleanLiteral:
return expr.Val
case *NumberLiteral:
return expr.Val
case *ParenExpr:
return Eval(expr.Expr, m)
case *StringLiteral:
return expr.Val
case *VarRef:
return m[expr.Val]
default:
return nil
}
}
func evalBinaryExpr(expr *BinaryExpr, m map[string]interface{}) interface{} {
lhs := Eval(expr.LHS, m)
rhs := Eval(expr.RHS, m)
// Evaluate if both sides are simple types.
switch lhs := lhs.(type) {
case bool:
rhs, _ := rhs.(bool)
switch expr.Op {
case AND:
return lhs && rhs
case OR:
return lhs || rhs
case EQ:
return lhs == rhs
case NEQ:
return lhs != rhs
2015-01-28 00:20:34 +00:00
}
case float64:
rhs, _ := rhs.(float64)
switch expr.Op {
case EQ:
return lhs == rhs
case NEQ:
return lhs != rhs
case LT:
return lhs < rhs
case LTE:
return lhs <= rhs
case GT:
return lhs > rhs
case GTE:
return lhs >= rhs
case ADD:
return lhs + rhs
case SUB:
return lhs - rhs
case MUL:
return lhs * rhs
case DIV:
if rhs == 0 {
return float64(0)
}
return lhs / rhs
}
case int64:
// we parse all number literals as float 64, so we have to convert from
// an interface to the float64, then cast to an int64 for comparison
rhsf, _ := rhs.(float64)
rhs := int64(rhsf)
switch expr.Op {
case EQ:
return lhs == rhs
case NEQ:
return lhs != rhs
case LT:
return lhs < rhs
case LTE:
return lhs <= rhs
case GT:
return lhs > rhs
case GTE:
return lhs >= rhs
case ADD:
return lhs + rhs
case SUB:
return lhs - rhs
case MUL:
return lhs * rhs
case DIV:
if rhs == 0 {
return int64(0)
}
return lhs / rhs
}
2015-01-28 00:20:34 +00:00
case string:
rhs, _ := rhs.(string)
switch expr.Op {
case EQ:
return lhs == rhs
case NEQ:
return lhs != rhs
}
}
return nil
}
2015-09-16 20:17:58 +00:00
// EvalBool evaluates expr and returns true if result is a boolean true.
// Otherwise returns false.
func EvalBool(expr Expr, m map[string]interface{}) bool {
v, _ := Eval(expr, m).(bool)
return v
}
2015-01-23 09:44:56 +00:00
// Reduce evaluates expr using the available values in valuer.
// References that don't exist in valuer are ignored.
func Reduce(expr Expr, valuer Valuer) Expr {
expr = reduce(expr, valuer)
// Unwrap parens at top level.
if expr, ok := expr.(*ParenExpr); ok {
return expr.Expr
}
return expr
}
func reduce(expr Expr, valuer Valuer) Expr {
if expr == nil {
return nil
}
switch expr := expr.(type) {
case *BinaryExpr:
return reduceBinaryExpr(expr, valuer)
case *Call:
return reduceCall(expr, valuer)
case *ParenExpr:
return reduceParenExpr(expr, valuer)
case *VarRef:
return reduceVarRef(expr, valuer)
default:
return CloneExpr(expr)
}
}
func reduceBinaryExpr(expr *BinaryExpr, valuer Valuer) Expr {
// Reduce both sides first.
op := expr.Op
lhs := reduce(expr.LHS, valuer)
rhs := reduce(expr.RHS, valuer)
// Do not evaluate if one side is nil.
if lhs == nil || rhs == nil {
return &BinaryExpr{LHS: lhs, RHS: rhs, Op: expr.Op}
}
// If we have a logical operator (AND, OR) and one side is a boolean literal
// then we need to have special handling.
if op == AND {
if isFalseLiteral(lhs) || isFalseLiteral(rhs) {
return &BooleanLiteral{Val: false}
} else if isTrueLiteral(lhs) {
return rhs
} else if isTrueLiteral(rhs) {
return lhs
}
} else if op == OR {
if isTrueLiteral(lhs) || isTrueLiteral(rhs) {
return &BooleanLiteral{Val: true}
} else if isFalseLiteral(lhs) {
return rhs
} else if isFalseLiteral(rhs) {
return lhs
}
}
// Evaluate if both sides are simple types.
switch lhs := lhs.(type) {
case *BooleanLiteral:
return reduceBinaryExprBooleanLHS(op, lhs, rhs)
case *DurationLiteral:
return reduceBinaryExprDurationLHS(op, lhs, rhs)
case *nilLiteral:
return reduceBinaryExprNilLHS(op, lhs, rhs)
case *NumberLiteral:
return reduceBinaryExprNumberLHS(op, lhs, rhs)
case *StringLiteral:
return reduceBinaryExprStringLHS(op, lhs, rhs)
case *TimeLiteral:
return reduceBinaryExprTimeLHS(op, lhs, rhs)
default:
return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs}
}
}
func reduceBinaryExprBooleanLHS(op Token, lhs *BooleanLiteral, rhs Expr) Expr {
switch rhs := rhs.(type) {
case *BooleanLiteral:
switch op {
case EQ:
return &BooleanLiteral{Val: lhs.Val == rhs.Val}
case NEQ:
return &BooleanLiteral{Val: lhs.Val != rhs.Val}
case AND:
return &BooleanLiteral{Val: lhs.Val && rhs.Val}
case OR:
return &BooleanLiteral{Val: lhs.Val || rhs.Val}
}
case *nilLiteral:
return &BooleanLiteral{Val: false}
}
return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs}
}
func reduceBinaryExprDurationLHS(op Token, lhs *DurationLiteral, rhs Expr) Expr {
switch rhs := rhs.(type) {
case *DurationLiteral:
switch op {
case ADD:
return &DurationLiteral{Val: lhs.Val + rhs.Val}
case SUB:
return &DurationLiteral{Val: lhs.Val - rhs.Val}
case EQ:
return &BooleanLiteral{Val: lhs.Val == rhs.Val}
case NEQ:
return &BooleanLiteral{Val: lhs.Val != rhs.Val}
case GT:
return &BooleanLiteral{Val: lhs.Val > rhs.Val}
case GTE:
return &BooleanLiteral{Val: lhs.Val >= rhs.Val}
case LT:
return &BooleanLiteral{Val: lhs.Val < rhs.Val}
case LTE:
return &BooleanLiteral{Val: lhs.Val <= rhs.Val}
}
case *NumberLiteral:
switch op {
case MUL:
return &DurationLiteral{Val: lhs.Val * time.Duration(rhs.Val)}
case DIV:
if rhs.Val == 0 {
return &DurationLiteral{Val: 0}
}
return &DurationLiteral{Val: lhs.Val / time.Duration(rhs.Val)}
}
case *TimeLiteral:
switch op {
case ADD:
return &TimeLiteral{Val: rhs.Val.Add(lhs.Val)}
}
case *nilLiteral:
return &BooleanLiteral{Val: false}
}
return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs}
}
func reduceBinaryExprNilLHS(op Token, lhs *nilLiteral, rhs Expr) Expr {
switch op {
case EQ, NEQ:
return &BooleanLiteral{Val: false}
}
return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs}
}
func reduceBinaryExprNumberLHS(op Token, lhs *NumberLiteral, rhs Expr) Expr {
switch rhs := rhs.(type) {
case *NumberLiteral:
switch op {
case ADD:
return &NumberLiteral{Val: lhs.Val + rhs.Val}
case SUB:
return &NumberLiteral{Val: lhs.Val - rhs.Val}
case MUL:
return &NumberLiteral{Val: lhs.Val * rhs.Val}
case DIV:
if rhs.Val == 0 {
return &NumberLiteral{Val: 0}
}
return &NumberLiteral{Val: lhs.Val / rhs.Val}
case EQ:
return &BooleanLiteral{Val: lhs.Val == rhs.Val}
case NEQ:
return &BooleanLiteral{Val: lhs.Val != rhs.Val}
case GT:
return &BooleanLiteral{Val: lhs.Val > rhs.Val}
case GTE:
return &BooleanLiteral{Val: lhs.Val >= rhs.Val}
case LT:
return &BooleanLiteral{Val: lhs.Val < rhs.Val}
case LTE:
return &BooleanLiteral{Val: lhs.Val <= rhs.Val}
}
case *nilLiteral:
return &BooleanLiteral{Val: false}
}
return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs}
}
func reduceBinaryExprStringLHS(op Token, lhs *StringLiteral, rhs Expr) Expr {
switch rhs := rhs.(type) {
case *StringLiteral:
switch op {
case EQ:
return &BooleanLiteral{Val: lhs.Val == rhs.Val}
case NEQ:
return &BooleanLiteral{Val: lhs.Val != rhs.Val}
case ADD:
return &StringLiteral{Val: lhs.Val + rhs.Val}
}
case *nilLiteral:
switch op {
case EQ, NEQ:
return &BooleanLiteral{Val: false}
}
}
return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs}
}
func reduceBinaryExprTimeLHS(op Token, lhs *TimeLiteral, rhs Expr) Expr {
switch rhs := rhs.(type) {
case *DurationLiteral:
switch op {
case ADD:
return &TimeLiteral{Val: lhs.Val.Add(rhs.Val)}
case SUB:
return &TimeLiteral{Val: lhs.Val.Add(-rhs.Val)}
}
case *TimeLiteral:
switch op {
case SUB:
return &DurationLiteral{Val: lhs.Val.Sub(rhs.Val)}
case EQ:
return &BooleanLiteral{Val: lhs.Val.Equal(rhs.Val)}
case NEQ:
return &BooleanLiteral{Val: !lhs.Val.Equal(rhs.Val)}
case GT:
return &BooleanLiteral{Val: lhs.Val.After(rhs.Val)}
case GTE:
return &BooleanLiteral{Val: lhs.Val.After(rhs.Val) || lhs.Val.Equal(rhs.Val)}
case LT:
return &BooleanLiteral{Val: lhs.Val.Before(rhs.Val)}
case LTE:
return &BooleanLiteral{Val: lhs.Val.Before(rhs.Val) || lhs.Val.Equal(rhs.Val)}
}
case *nilLiteral:
return &BooleanLiteral{Val: false}
}
return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs}
}
func reduceCall(expr *Call, valuer Valuer) Expr {
// Evaluate "now()" if valuer is set.
2015-05-01 15:29:39 +00:00
if expr.Name == "now" && len(expr.Args) == 0 && valuer != nil {
2015-01-23 09:44:56 +00:00
if v, ok := valuer.Value("now()"); ok {
v, _ := v.(time.Time)
return &TimeLiteral{Val: v}
}
}
// Otherwise reduce arguments.
args := make([]Expr, len(expr.Args))
for i, arg := range expr.Args {
args[i] = reduce(arg, valuer)
}
return &Call{Name: expr.Name, Args: args}
}
func reduceParenExpr(expr *ParenExpr, valuer Valuer) Expr {
subexpr := reduce(expr.Expr, valuer)
if subexpr, ok := subexpr.(*BinaryExpr); ok {
return &ParenExpr{Expr: subexpr}
}
return subexpr
}
func reduceVarRef(expr *VarRef, valuer Valuer) Expr {
// Ignore if there is no valuer.
if valuer == nil {
return &VarRef{Val: expr.Val}
}
// Retrieve the value of the ref.
// Ignore if the value doesn't exist.
v, ok := valuer.Value(expr.Val)
if !ok {
return &VarRef{Val: expr.Val}
}
// Return the value as a literal.
switch v := v.(type) {
case bool:
return &BooleanLiteral{Val: v}
case time.Duration:
return &DurationLiteral{Val: v}
case float64:
return &NumberLiteral{Val: v}
case string:
return &StringLiteral{Val: v}
case time.Time:
return &TimeLiteral{Val: v}
default:
return &nilLiteral{}
}
}
// Valuer is the interface that wraps the Value() method.
//
// Value returns the value and existence flag for a given key.
type Valuer interface {
Value(key string) (interface{}, bool)
}
// nowValuer returns only the value for "now()".
2015-04-15 15:26:36 +00:00
type NowValuer struct {
2015-01-23 09:44:56 +00:00
Now time.Time
}
2015-04-15 15:26:36 +00:00
func (v *NowValuer) Value(key string) (interface{}, bool) {
2015-01-23 09:44:56 +00:00
if key == "now()" {
return v.Now, true
}
return nil, false
}
2016-01-25 17:36:04 +00:00
// ContainsVarRef returns true if expr is a VarRef or contains one.
func ContainsVarRef(expr Expr) bool {
var v containsVarRefVisitor
Walk(&v, expr)
return v.contains
}
type containsVarRefVisitor struct {
contains bool
}
2016-02-02 17:19:15 +00:00
func (v *containsVarRefVisitor) Visit(n Node) Visitor {
2016-01-25 17:36:04 +00:00
switch n.(type) {
case *Call:
return nil
case *VarRef:
v.contains = true
}
return v
}