package influxql import ( "bytes" "errors" "fmt" "math" "regexp" "regexp/syntax" "sort" "strconv" "strings" "time" "github.com/gogo/protobuf/proto" internal "github.com/influxdata/influxdb/influxql/internal" ) // DataType represents the primitive data types available in InfluxQL. type DataType int const ( // Unknown primitive data type. Unknown DataType = 0 // Float means the data type is a float. Float = 1 // Integer means the data type is an integer. Integer = 2 // String means the data type is a string of text. String = 3 // Boolean means the data type is a boolean. Boolean = 4 // Time means the data type is a time. Time = 5 // Duration means the data type is a duration of time. Duration = 6 // Tag means the data type is a tag. Tag = 7 // AnyField means the data type is any field. AnyField = 8 ) var ( // ErrInvalidTime is returned when the timestamp string used to // compare against time field is invalid. ErrInvalidTime = errors.New("invalid timestamp string") ) // InspectDataType returns the data type of a given value. func InspectDataType(v interface{}) DataType { switch v.(type) { case float64: return Float case int64, int32, int: return Integer case string: return String case bool: return Boolean case time.Time: return Time case time.Duration: return Duration default: return Unknown } } // InspectDataTypes returns all of the data types for an interface slice. func InspectDataTypes(a []interface{}) []DataType { dta := make([]DataType, len(a)) for i, v := range a { dta[i] = InspectDataType(v) } return dta } // LessThan returns true if the other DataType has greater precedence than the // current data type. Unknown has the lowest precedence. // // NOTE: This is not the same as using the `<` or `>` operator because the // integers used decrease with higher precedence, but Unknown is the lowest // precedence at the zero value. func (d DataType) LessThan(other DataType) bool { return d == Unknown || (other != Unknown && other < d) } // String returns the human-readable string representation of the DataType. 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" case Tag: return "tag" case AnyField: return "field" } return "unknown" } // Node represents a node in the InfluxDB abstract syntax tree. type Node interface { // node is unexported to ensure implementations of Node // can only originate in this package. node() String() string } func (*Query) node() {} func (Statements) node() {} func (*AlterRetentionPolicyStatement) node() {} func (*CreateContinuousQueryStatement) node() {} func (*CreateDatabaseStatement) node() {} func (*CreateRetentionPolicyStatement) node() {} func (*CreateSubscriptionStatement) node() {} func (*CreateUserStatement) node() {} func (*Distinct) node() {} func (*DeleteSeriesStatement) node() {} func (*DeleteStatement) node() {} func (*DropContinuousQueryStatement) node() {} func (*DropDatabaseStatement) node() {} func (*DropMeasurementStatement) node() {} func (*DropRetentionPolicyStatement) node() {} func (*DropSeriesStatement) node() {} func (*DropShardStatement) node() {} func (*DropSubscriptionStatement) node() {} func (*DropUserStatement) node() {} func (*GrantStatement) node() {} func (*GrantAdminStatement) node() {} func (*KillQueryStatement) node() {} func (*RevokeStatement) node() {} func (*RevokeAdminStatement) node() {} func (*SelectStatement) node() {} func (*SetPasswordUserStatement) node() {} func (*ShowContinuousQueriesStatement) node() {} func (*ShowGrantsForUserStatement) node() {} func (*ShowDatabasesStatement) node() {} func (*ShowFieldKeysStatement) node() {} func (*ShowRetentionPoliciesStatement) node() {} func (*ShowMeasurementsStatement) node() {} func (*ShowQueriesStatement) node() {} func (*ShowSeriesStatement) node() {} func (*ShowShardGroupsStatement) node() {} func (*ShowShardsStatement) node() {} func (*ShowStatsStatement) node() {} func (*ShowSubscriptionsStatement) node() {} func (*ShowDiagnosticsStatement) node() {} 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 (*IntegerLiteral) 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() {} func (*ListLiteral) node() {} func (*SortField) node() {} func (SortFields) node() {} func (Sources) node() {} func (*StringLiteral) node() {} func (*SubQuery) node() {} func (*Target) node() {} func (*TimeLiteral) node() {} func (*VarRef) node() {} func (*Wildcard) node() {} // Query represents a collection of ordered statements. type Query struct { Statements Statements } // String returns a string representation of the query. func (q *Query) String() string { return q.Statements.String() } // 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") } // Statement represents a single command in InfluxQL. type Statement interface { Node // stmt is unexported to ensure implementations of Statement // can only originate in this package. stmt() RequiredPrivileges() (ExecutionPrivileges, error) } // HasDefaultDatabase provides an interface to get the default database from a Statement. type HasDefaultDatabase interface { Node // stmt is unexported to ensure implementations of HasDefaultDatabase // can only originate in this package. stmt() DefaultDatabase() string } // 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. Name string // Database privilege required. Privilege Privilege } // ExecutionPrivileges is a list of privileges required to execute a statement. type ExecutionPrivileges []ExecutionPrivilege func (*AlterRetentionPolicyStatement) stmt() {} func (*CreateContinuousQueryStatement) stmt() {} func (*CreateDatabaseStatement) stmt() {} func (*CreateRetentionPolicyStatement) stmt() {} func (*CreateSubscriptionStatement) stmt() {} func (*CreateUserStatement) stmt() {} func (*DeleteSeriesStatement) stmt() {} func (*DeleteStatement) stmt() {} func (*DropContinuousQueryStatement) stmt() {} func (*DropDatabaseStatement) stmt() {} func (*DropMeasurementStatement) stmt() {} func (*DropRetentionPolicyStatement) stmt() {} func (*DropSeriesStatement) stmt() {} func (*DropSubscriptionStatement) stmt() {} func (*DropUserStatement) stmt() {} func (*GrantStatement) stmt() {} func (*GrantAdminStatement) stmt() {} func (*KillQueryStatement) stmt() {} func (*ShowContinuousQueriesStatement) stmt() {} func (*ShowGrantsForUserStatement) stmt() {} func (*ShowDatabasesStatement) stmt() {} func (*ShowFieldKeysStatement) stmt() {} func (*ShowMeasurementsStatement) stmt() {} func (*ShowQueriesStatement) stmt() {} func (*ShowRetentionPoliciesStatement) stmt() {} func (*ShowSeriesStatement) stmt() {} func (*ShowShardGroupsStatement) stmt() {} func (*ShowShardsStatement) stmt() {} func (*ShowStatsStatement) stmt() {} func (*DropShardStatement) stmt() {} func (*ShowSubscriptionsStatement) stmt() {} func (*ShowDiagnosticsStatement) stmt() {} func (*ShowTagKeysStatement) stmt() {} func (*ShowTagValuesStatement) stmt() {} func (*ShowUsersStatement) stmt() {} func (*RevokeStatement) stmt() {} func (*RevokeAdminStatement) stmt() {} func (*SelectStatement) stmt() {} func (*SetPasswordUserStatement) stmt() {} // Expr represents an expression that can be evaluated to a value. type Expr interface { Node // expr is unexported to ensure implementations of Expr // can only originate in this package. expr() } func (*BinaryExpr) expr() {} func (*BooleanLiteral) expr() {} func (*Call) expr() {} func (*Distinct) expr() {} func (*DurationLiteral) expr() {} func (*IntegerLiteral) expr() {} func (*nilLiteral) expr() {} func (*NumberLiteral) expr() {} func (*ParenExpr) expr() {} func (*RegexLiteral) expr() {} func (*ListLiteral) expr() {} func (*StringLiteral) expr() {} func (*TimeLiteral) expr() {} func (*VarRef) expr() {} func (*Wildcard) expr() {} // Literal represents a static literal. type Literal interface { Expr // literal is unexported to ensure implementations of Literal // can only originate in this package. literal() } func (*BooleanLiteral) literal() {} func (*DurationLiteral) literal() {} func (*IntegerLiteral) literal() {} func (*nilLiteral) literal() {} func (*NumberLiteral) literal() {} func (*RegexLiteral) literal() {} func (*ListLiteral) literal() {} func (*StringLiteral) literal() {} func (*TimeLiteral) literal() {} // Source represents a source of data for a statement. type Source interface { Node // source is unexported to ensure implementations of Source // can only originate in this package. source() } func (*Measurement) source() {} func (*SubQuery) source() {} // Sources represents a list of sources. type Sources []Source // 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 } // Filter returns a list of source names filtered by the database/retention policy. func (a Sources) Filter(database, retentionPolicy string) []Source { sources := make([]Source, 0, len(a)) for _, s := range a { switch s := s.(type) { case *Measurement: if s.Database == database && s.RetentionPolicy == retentionPolicy { sources = append(sources, s) } case *SubQuery: filteredSources := s.Statement.Sources.Filter(database, retentionPolicy) sources = append(sources, filteredSources...) } } return sources } // 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 } // HasRegex returns true if any of the sources are regex measurements. func (a Sources) HasRegex() bool { for _, s := range a { switch s := s.(type) { case *Measurement: if s.Regex != nil { return true } } } return false } // 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() } // Measurements returns all measurements including ones embedded in subqueries. func (a Sources) Measurements() []*Measurement { mms := make([]*Measurement, 0, len(a)) for _, src := range a { switch src := src.(type) { case *Measurement: mms = append(mms, src) case *SubQuery: mms = append(mms, src.Statement.Sources.Measurements()...) } } return mms } // MarshalBinary encodes a list of sources to a binary format. func (a Sources) MarshalBinary() ([]byte, error) { var pb internal.Measurements pb.Items = make([]*internal.Measurement, len(a)) for i, source := range a { pb.Items[i] = encodeMeasurement(source.(*Measurement)) } return proto.Marshal(&pb) } // UnmarshalBinary decodes binary data into a list of sources. func (a *Sources) UnmarshalBinary(buf []byte) error { var pb internal.Measurements if err := proto.Unmarshal(buf, &pb); err != nil { return err } *a = make(Sources, len(pb.GetItems())) for i := range pb.GetItems() { mm, err := decodeMeasurement(pb.GetItems()[i]) if err != nil { return err } (*a)[i] = mm } return nil } // IsSystemName returns true if name is an internal system name. func IsSystemName(name string) bool { switch name { case "_fieldKeys", "_measurements", "_series", "_tagKeys", "_tags": return true default: return false } } // 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 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, ", ") } // CreateDatabaseStatement represents a command for creating a new database. type CreateDatabaseStatement struct { // Name of the database to be created. Name string // 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 // RetentionPolicyShardGroupDuration indicates shard group duration for the new database. RetentionPolicyShardGroupDuration time.Duration } // String returns a string representation of the create database statement. func (s *CreateDatabaseStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("CREATE DATABASE ") _, _ = buf.WriteString(QuoteIdent(s.Name)) if s.RetentionPolicyCreate { _, _ = buf.WriteString(" WITH") if s.RetentionPolicyDuration != nil { _, _ = buf.WriteString(" DURATION ") _, _ = buf.WriteString(s.RetentionPolicyDuration.String()) } if s.RetentionPolicyReplication != nil { _, _ = buf.WriteString(" REPLICATION ") _, _ = buf.WriteString(strconv.Itoa(*s.RetentionPolicyReplication)) } if s.RetentionPolicyShardGroupDuration > 0 { _, _ = buf.WriteString(" SHARD DURATION ") _, _ = buf.WriteString(s.RetentionPolicyShardGroupDuration.String()) } if s.RetentionPolicyName != "" { _, _ = buf.WriteString(" NAME ") _, _ = buf.WriteString(QuoteIdent(s.RetentionPolicyName)) } } return buf.String() } // RequiredPrivileges returns the privilege required to execute a CreateDatabaseStatement. func (s *CreateDatabaseStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // DropDatabaseStatement represents a command to drop a database. type DropDatabaseStatement struct { // Name of the database to be dropped. Name string } // String returns a string representation of the drop database statement. func (s *DropDatabaseStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("DROP DATABASE ") _, _ = buf.WriteString(QuoteIdent(s.Name)) return buf.String() } // RequiredPrivileges returns the privilege required to execute a DropDatabaseStatement. func (s *DropDatabaseStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // 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() } // RequiredPrivileges returns the privilege required to execute a DropRetentionPolicyStatement. func (s *DropRetentionPolicyStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: s.Database, Privilege: WritePrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *DropRetentionPolicyStatement) DefaultDatabase() string { return s.Database } // CreateUserStatement represents a command for creating a new user. type CreateUserStatement struct { // Name of the user to be created. Name string // User's password. Password string // User's admin privilege. Admin bool } // 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)) _, _ = buf.WriteString(" WITH PASSWORD ") _, _ = buf.WriteString("[REDACTED]") if s.Admin { _, _ = buf.WriteString(" WITH ALL PRIVILEGES") } return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a CreateUserStatement. func (s *CreateUserStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // 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 ") _, _ = buf.WriteString(QuoteIdent(s.Name)) return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a DropUserStatement. func (s *DropUserStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // Privilege is a type of action a user can be granted the right to use. type Privilege int const ( // NoPrivileges means no privileges required / granted / revoked. NoPrivileges Privilege = iota // ReadPrivilege means read privilege required / granted / revoked. ReadPrivilege // WritePrivilege means write privilege required / granted / revoked. WritePrivilege // AllPrivileges means all privileges required / granted / revoked. AllPrivileges ) // NewPrivilege returns an initialized *Privilege. func NewPrivilege(p Privilege) *Privilege { return &p } // String returns a string representation of a Privilege. func (p Privilege) String() string { switch p { case NoPrivileges: return "NO PRIVILEGES" 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. 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 ") _, _ = buf.WriteString(QuoteIdent(s.On)) _, _ = buf.WriteString(" TO ") _, _ = buf.WriteString(QuoteIdent(s.User)) return buf.String() } // RequiredPrivileges returns the privilege required to execute a GrantStatement. func (s *GrantStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // DefaultDatabase returns the default database from the statement. func (s *GrantStatement) DefaultDatabase() string { return s.On } // 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 ") _, _ = buf.WriteString(QuoteIdent(s.User)) return buf.String() } // RequiredPrivileges returns the privilege required to execute a GrantAdminStatement. func (s *GrantAdminStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // KillQueryStatement represents a command for killing a query. type KillQueryStatement struct { // The query to kill. QueryID uint64 // The host to delegate the kill to. Host string } // String returns a string representation of the kill query statement. func (s *KillQueryStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("KILL QUERY ") _, _ = buf.WriteString(strconv.FormatUint(s.QueryID, 10)) if s.Host != "" { _, _ = buf.WriteString(" ON ") _, _ = buf.WriteString(QuoteIdent(s.Host)) } return buf.String() } // RequiredPrivileges returns the privilege required to execute a KillQueryStatement. func (s *KillQueryStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // SetPasswordUserStatement represents a command for changing user password. type SetPasswordUserStatement struct { // Plain-text 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 ") _, _ = 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, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // RevokeStatement represents a command to revoke a privilege from a user. type RevokeStatement struct { // The privilege to be revoked. Privilege Privilege // Database to revoke the privilege from. 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 ") _, _ = buf.WriteString(QuoteIdent(s.On)) _, _ = buf.WriteString(" FROM ") _, _ = buf.WriteString(QuoteIdent(s.User)) return buf.String() } // RequiredPrivileges returns the privilege required to execute a RevokeStatement. func (s *RevokeStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // DefaultDatabase returns the default database from the statement. func (s *RevokeStatement) DefaultDatabase() string { return s.On } // 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 ") _, _ = buf.WriteString(QuoteIdent(s.User)) return buf.String() } // RequiredPrivileges returns the privilege required to execute a RevokeAdminStatement. func (s *RevokeAdminStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // 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 // Shard Duration. ShardGroupDuration time.Duration } // 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.ShardGroupDuration > 0 { _, _ = buf.WriteString(" SHARD DURATION ") _, _ = buf.WriteString(FormatDuration(s.ShardGroupDuration)) } if s.Default { _, _ = buf.WriteString(" DEFAULT") } return buf.String() } // RequiredPrivileges returns the privilege required to execute a CreateRetentionPolicyStatement. func (s *CreateRetentionPolicyStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // DefaultDatabase returns the default database from the statement. func (s *CreateRetentionPolicyStatement) DefaultDatabase() string { return s.Database } // 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 // Duration of the Shard. ShardGroupDuration *time.Duration } // 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.ShardGroupDuration != nil { _, _ = buf.WriteString(" SHARD DURATION ") _, _ = buf.WriteString(FormatDuration(*s.ShardGroupDuration)) } if s.Default { _, _ = buf.WriteString(" DEFAULT") } return buf.String() } // RequiredPrivileges returns the privilege required to execute an AlterRetentionPolicyStatement. func (s *AlterRetentionPolicyStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // DefaultDatabase returns the default database from the statement. func (s *AlterRetentionPolicyStatement) DefaultDatabase() string { return s.Database } // FillOption represents different options for filling aggregate windows. 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 // NumberFill means that empty aggregate windows will be filled with a provided number. NumberFill // PreviousFill means that empty aggregate windows will be filled with whatever the previous aggregate window had. PreviousFill // LinearFill means that empty aggregate windows will be filled with whatever a linear value between non null windows. LinearFill ) // SelectStatement represents a command for extracting data from the database. type SelectStatement struct { // Expressions returned from the selection. Fields Fields // Target (destination) for the result of a SELECT INTO query. Target *Target // Expressions used for grouping the selection. Dimensions Dimensions // Data sources (measurements) 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 rows to be returned. Unlimited if zero. Limit int // 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 // Memoized group by interval from GroupBy(). groupByInterval time.Duration // Whether 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{} // The timezone for the query, if any. Location *time.Location // Renames the implicit time field name. TimeAlias string // Removes the "time" column from the output. OmitTime bool // Removes duplicate rows from raw queries. Dedupe bool } // HasDerivative returns true if any function call in the statement is a // derivative aggregate. func (s *SelectStatement) HasDerivative() bool { for _, f := range s.FunctionCalls() { if f.Name == "derivative" || f.Name == "non_negative_derivative" { return true } } return false } // IsSimpleDerivative return true if any function call is a derivative function with a // variable ref as the first arg. func (s *SelectStatement) IsSimpleDerivative() bool { for _, f := range s.FunctionCalls() { if f.Name == "derivative" || f.Name == "non_negative_derivative" { // it's nested if the first argument is an aggregate function if _, ok := f.Args[0].(*VarRef); ok { return true } } } return false } // HasSelector returns true if there is exactly one selector. func (s *SelectStatement) HasSelector() bool { var selector *Call for _, f := range s.Fields { if call, ok := f.Expr.(*Call); ok { if selector != nil || !IsSelector(call) { // This is an aggregate call or there is already a selector. return false } selector = call } } return selector != nil } // 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 } // TimeFieldName returns the name of the time field. func (s *SelectStatement) TimeFieldName() string { if s.TimeAlias != "" { return s.TimeAlias } return "time" } // Clone returns a deep copy of the statement. func (s *SelectStatement) Clone() *SelectStatement { clone := *s clone.Fields = make(Fields, 0, len(s.Fields)) clone.Dimensions = make(Dimensions, 0, len(s.Dimensions)) clone.Sources = cloneSources(s.Sources) clone.SortFields = make(SortFields, 0, len(s.SortFields)) clone.Condition = CloneExpr(s.Condition) 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), }, } } for _, f := range s.Fields { clone.Fields = append(clone.Fields, &Field{Expr: CloneExpr(f.Expr), Alias: f.Alias}) } for _, d := range s.Dimensions { clone.Dimensions = append(clone.Dimensions, &Dimension{Expr: CloneExpr(d.Expr)}) } for _, f := range s.SortFields { clone.SortFields = append(clone.SortFields, &SortField{Name: f.Name, Ascending: f.Ascending}) } return &clone } func cloneSources(sources Sources) Sources { clone := make(Sources, 0, len(sources)) for _, s := range sources { clone = append(clone, cloneSource(s)) } return clone } 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} if s.Regex != nil { m.Regex = &RegexLiteral{Val: regexp.MustCompile(s.Regex.Val.String())} } return m case *SubQuery: return &SubQuery{Statement: s.Statement.Clone()} default: panic("unreachable") } } // RewriteFields 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. Any fields with no type specifier are rewritten with the // appropriate type. func (s *SelectStatement) RewriteFields(m FieldMapper) (*SelectStatement, error) { // Clone the statement so we aren't rewriting the original. other := s.Clone() // Iterate through the sources and rewrite any subqueries first. for _, src := range other.Sources { switch src := src.(type) { case *SubQuery: stmt, err := src.Statement.RewriteFields(m) if err != nil { return nil, err } src.Statement = stmt } } // Rewrite all variable references in the fields with their types if one // hasn't been specified. rewrite := func(n Node) { ref, ok := n.(*VarRef) if !ok || (ref.Type != Unknown && ref.Type != AnyField) { return } typ := EvalType(ref, other.Sources, m) if typ == Tag && ref.Type == AnyField { return } ref.Type = typ } WalkFunc(other.Fields, rewrite) WalkFunc(other.Condition, rewrite) // Ignore if there are no wildcards. hasFieldWildcard := other.HasFieldWildcard() hasDimensionWildcard := other.HasDimensionWildcard() if !hasFieldWildcard && !hasDimensionWildcard { return other, nil } fieldSet, dimensionSet, err := FieldDimensions(other.Sources, m) if err != nil { return nil, err } // If there are no dimension wildcards then merge dimensions to fields. if !hasDimensionWildcard { // Remove the dimensions present in the group by so they don't get added as fields. for _, d := range other.Dimensions { switch expr := d.Expr.(type) { case *VarRef: if _, ok := dimensionSet[expr.Val]; ok { delete(dimensionSet, expr.Val) } } } } // Sort the field and dimension names for wildcard expansion. var fields []VarRef if len(fieldSet) > 0 { fields = make([]VarRef, 0, len(fieldSet)) for name, typ := range fieldSet { fields = append(fields, VarRef{Val: name, Type: typ}) } if !hasDimensionWildcard { for name := range dimensionSet { fields = append(fields, VarRef{Val: name, Type: Tag}) } dimensionSet = nil } sort.Sort(VarRefs(fields)) } dimensions := stringSetSlice(dimensionSet) // Rewrite all wildcard query fields if hasFieldWildcard { // Allocate a slice assuming there is exactly one wildcard for efficiency. rwFields := make(Fields, 0, len(other.Fields)+len(fields)-1) for _, f := range other.Fields { switch expr := f.Expr.(type) { case *Wildcard: for _, ref := range fields { if expr.Type == FIELD && ref.Type == Tag { continue } else if expr.Type == TAG && ref.Type != Tag { continue } rwFields = append(rwFields, &Field{Expr: &VarRef{Val: ref.Val, Type: ref.Type}}) } case *RegexLiteral: for _, ref := range fields { if expr.Val.MatchString(ref.Val) { rwFields = append(rwFields, &Field{Expr: &VarRef{Val: ref.Val, Type: ref.Type}}) } } case *Call: // Clone a template that we can modify and use for new fields. template := CloneExpr(expr).(*Call) // Search for the call with a wildcard by continuously descending until // we no longer have a call. call := template for len(call.Args) > 0 { arg, ok := call.Args[0].(*Call) if !ok { break } call = arg } // Check if this field value is a wildcard. if len(call.Args) == 0 { rwFields = append(rwFields, f) continue } // Retrieve if this is a wildcard or a regular expression. var re *regexp.Regexp switch expr := call.Args[0].(type) { case *Wildcard: if expr.Type == TAG { return nil, fmt.Errorf("unable to use tag wildcard in %s()", call.Name) } case *RegexLiteral: re = expr.Val default: rwFields = append(rwFields, f) continue } // All types that can expand wildcards support float and integer. supportedTypes := map[DataType]struct{}{ Float: struct{}{}, Integer: struct{}{}, } // Add additional types for certain functions. switch call.Name { case "count", "first", "last", "distinct", "elapsed", "mode", "sample": supportedTypes[String] = struct{}{} fallthrough case "min", "max": supportedTypes[Boolean] = struct{}{} } for _, ref := range fields { // Do not expand tags within a function call. It likely won't do anything // anyway and will be the wrong thing in 99% of cases. if ref.Type == Tag { continue } else if _, ok := supportedTypes[ref.Type]; !ok { continue } else if re != nil && !re.MatchString(ref.Val) { continue } // Make a new expression and replace the wildcard within this cloned expression. call.Args[0] = &VarRef{Val: ref.Val, Type: ref.Type} rwFields = append(rwFields, &Field{ Expr: CloneExpr(template), Alias: fmt.Sprintf("%s_%s", f.Name(), ref.Val), }) } case *BinaryExpr: // Search for regexes or wildcards within the binary // expression. If we find any, throw an error indicating that // it's illegal. var regex, wildcard bool WalkFunc(expr, func(n Node) { switch n.(type) { case *RegexLiteral: regex = true case *Wildcard: wildcard = true } }) if wildcard { return nil, fmt.Errorf("unsupported expression with wildcard: %s", f.Expr) } else if regex { return nil, fmt.Errorf("unsupported expression with regex field: %s", f.Expr) } rwFields = append(rwFields, f) default: rwFields = append(rwFields, f) } } other.Fields = rwFields } // Rewrite all wildcard GROUP BY fields if hasDimensionWildcard { // Allocate a slice assuming there is exactly one wildcard for efficiency. rwDimensions := make(Dimensions, 0, len(other.Dimensions)+len(dimensions)-1) for _, d := range other.Dimensions { switch expr := d.Expr.(type) { case *Wildcard: for _, name := range dimensions { rwDimensions = append(rwDimensions, &Dimension{Expr: &VarRef{Val: name}}) } case *RegexLiteral: for _, name := range dimensions { if expr.Val.MatchString(name) { rwDimensions = append(rwDimensions, &Dimension{Expr: &VarRef{Val: name}}) } } default: rwDimensions = append(rwDimensions, d) } } other.Dimensions = rwDimensions } return other, nil } // RewriteRegexConditions rewrites regex conditions to make better use of the // database index. // // Conditions that can currently be simplified are: // // - host =~ /^foo$/ becomes host = 'foo' // - host !~ /^foo$/ becomes host != 'foo' // // Note: if the regex contains groups, character classes, repetition or // similar, it's likely it won't be rewritten. In order to support rewriting // regexes with these characters would be a lot more work. func (s *SelectStatement) RewriteRegexConditions() { s.Condition = RewriteExpr(s.Condition, func(e Expr) Expr { be, ok := e.(*BinaryExpr) if !ok || (be.Op != EQREGEX && be.Op != NEQREGEX) { // This expression is not a binary condition or doesn't have a // regex based operator. return e } // Handle regex-based condition. rhs := be.RHS.(*RegexLiteral) // This must be a regex. val, ok := matchExactRegex(rhs.Val.String()) if !ok { // Regex didn't match. return e } // Remove leading and trailing ^ and $. be.RHS = &StringLiteral{Val: val} // Update the condition operator. if be.Op == EQREGEX { be.Op = EQ } else { be.Op = NEQ } return be }) } // matchExactRegex matches regexes that have the following form: /^foo$/. It // considers /^$/ to be a matching regex. func matchExactRegex(v string) (string, bool) { re, err := syntax.Parse(v, syntax.Perl) if err != nil { // Nothing we can do or log. return "", false } if re.Op != syntax.OpConcat { return "", false } if len(re.Sub) < 2 || len(re.Sub) > 3 { // Regex has too few or too many subexpressions. return "", false } start := re.Sub[0] if !(start.Op == syntax.OpBeginLine || start.Op == syntax.OpBeginText) { // Regex does not begin with ^ return "", false } end := re.Sub[len(re.Sub)-1] if !(end.Op == syntax.OpEndLine || end.Op == syntax.OpEndText) { // Regex does not end with $ return "", false } if len(re.Sub) == 3 { middle := re.Sub[1] if middle.Op != syntax.OpLiteral || middle.Flags^syntax.Perl != 0 { // Regex does not contain a literal op. return "", false } // We can rewrite this regex. return string(middle.Rune), true } // The regex /^$/ return "", true } // 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() { 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.TimeAlias = s.Fields[i].Alias s.Fields = append(s.Fields[:i], s.Fields[i+1:]...) } } } } // RewriteTimeCondition adds time constraints to aggregate queries. func (s *SelectStatement) RewriteTimeCondition(now time.Time) error { interval, err := s.GroupByInterval() if err != nil { return err } else if interval > 0 && s.Condition != nil { _, tmax, err := TimeRange(s.Condition, s.Location) if err != nil { return err } if tmax.IsZero() { s.Condition = &BinaryExpr{ Op: AND, LHS: s.Condition, RHS: &BinaryExpr{ Op: LTE, LHS: &VarRef{Val: "time"}, RHS: &TimeLiteral{Val: now}, }, } } } for _, source := range s.Sources { switch source := source.(type) { case *SubQuery: if err := source.Statement.RewriteTimeCondition(now); err != nil { return err } } } return nil } // ColumnNames will walk all fields and functions and return the appropriate field names for the select statement // while maintaining order of the field names. func (s *SelectStatement) ColumnNames() []string { // First walk each field to determine the number of columns. columnFields := Fields{} for _, field := range s.Fields { columnFields = append(columnFields, field) switch f := field.Expr.(type) { case *Call: if s.Target == nil && (f.Name == "top" || f.Name == "bottom") { for _, arg := range f.Args[1:] { ref, ok := arg.(*VarRef) if ok { columnFields = append(columnFields, &Field{Expr: ref}) } } } } } // Determine if we should add an extra column for an implicit time. offset := 0 if !s.OmitTime { offset++ } columnNames := make([]string, len(columnFields)+offset) if !s.OmitTime { // Add the implicit time if requested. columnNames[0] = s.TimeFieldName() } // Keep track of the encountered column names. names := make(map[string]int) // Resolve aliases first. for i, col := range columnFields { if col.Alias != "" { columnNames[i+offset] = col.Alias names[col.Alias] = 1 } } // Resolve any generated names and resolve conflicts. for i, col := range columnFields { if columnNames[i+offset] != "" { continue } name := col.Name() count, conflict := names[name] if conflict { for { resolvedName := fmt.Sprintf("%s_%d", name, count) _, conflict = names[resolvedName] if !conflict { names[name] = count + 1 name = resolvedName break } count++ } } names[name]++ columnNames[i+offset] = name } return columnNames } // FieldExprByName returns the expression that matches the field name and the // index where this was found. If the name matches one of the arguments to // "top" or "bottom", the variable reference inside of the function is returned // and the index is of the function call rather than the variable reference. // If no expression is found, -1 is returned for the index and the expression // will be nil. func (s *SelectStatement) FieldExprByName(name string) (int, Expr) { for i, f := range s.Fields { if f.Name() == name { return i, f.Expr } else if call, ok := f.Expr.(*Call); ok && (call.Name == "top" || call.Name == "bottom") && len(call.Args) > 2 { for _, arg := range call.Args[1 : len(call.Args)-1] { if arg, ok := arg.(*VarRef); ok && arg.Val == name { return i, arg } } } } return -1, nil } // Reduce calls the Reduce function on the different components of the // SelectStatement to reduce the statement. func (s *SelectStatement) Reduce(valuer Valuer) *SelectStatement { stmt := s.Clone() stmt.Condition = Reduce(stmt.Condition, valuer) for _, d := range stmt.Dimensions { d.Expr = Reduce(d.Expr, valuer) } for _, source := range stmt.Sources { switch source := source.(type) { case *SubQuery: source.Statement = source.Statement.Reduce(valuer) } } return stmt } // 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()) } 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 LinearFill: _, _ = buf.WriteString(" fill(linear)") 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) } 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) } if s.Location != nil { _, _ = fmt.Fprintf(&buf, ` TZ('%s')`, s.Location) } return buf.String() } // RequiredPrivileges returns the privilege required to execute the SelectStatement. // NOTE: Statement should be normalized first (database name(s) in Sources and // Target should be populated). If the statement has not been normalized, an // empty string will be returned for the database name and it is up to the caller // to interpret that as the default database. func (s *SelectStatement) RequiredPrivileges() (ExecutionPrivileges, error) { ep := ExecutionPrivileges{} for _, source := range s.Sources { switch source := source.(type) { case *Measurement: ep = append(ep, ExecutionPrivilege{ Name: source.Database, Privilege: ReadPrivilege, }) case *SubQuery: privs, err := source.Statement.RequiredPrivileges() if err != nil { return nil, err } ep = append(ep, privs...) default: return nil, fmt.Errorf("invalid source: %s", source) } } if s.Target != nil { p := ExecutionPrivilege{Admin: false, Name: s.Target.Measurement.Database, Privilege: WritePrivilege} ep = append(ep, p) } return ep, nil } // HasWildcard returns whether or not the select statement has at least 1 wildcard. func (s *SelectStatement) HasWildcard() bool { return s.HasFieldWildcard() || s.HasDimensionWildcard() } // HasFieldWildcard returns whether or not the select statement has at least 1 wildcard in the fields. func (s *SelectStatement) HasFieldWildcard() (hasWildcard bool) { WalkFunc(s.Fields, func(n Node) { if hasWildcard { return } switch n.(type) { case *Wildcard, *RegexLiteral: hasWildcard = true } }) return hasWildcard } // 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 { switch d.Expr.(type) { case *Wildcard, *RegexLiteral: return true } } return false } func (s *SelectStatement) validate(tr targetRequirement) error { if err := s.validateFields(); err != nil { return err } if err := s.validateDimensions(); err != nil { return err } if err := s.validateDistinct(); err != nil { return err } if err := s.validateTopBottom(); err != nil { return err } if err := s.validateAggregates(tr); err != nil { return err } if err := s.validateFill(); 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") } for _, f := range s.Fields { switch expr := f.Expr.(type) { case *BinaryExpr: if err := expr.validate(); err != nil { return err } } } 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 has one or two duration arguments. // If we already have a duration if expr.Name != "time" { return errors.New("only time() calls allowed in dimensions") } else if got := len(expr.Args); got < 1 || got > 2 { return errors.New("time dimension expected 1 or 2 arguments") } else if lit, ok := expr.Args[0].(*DurationLiteral); !ok { return errors.New("time dimension must have duration argument") } else if dur != 0 { return errors.New("multiple time dimensions not allowed") } else { dur = lit.Val if len(expr.Args) == 2 { switch lit := expr.Args[1].(type) { case *DurationLiteral: // noop case *Call: if lit.Name != "now" { return errors.New("time dimension offset function must be now()") } else if len(lit.Args) != 0 { return errors.New("time dimension offset now() function requires no arguments") } default: return errors.New("time dimension offset must be duration or now()") } } } case *VarRef: if strings.ToLower(expr.Val) == "time" { return errors.New("time() is a function and expects at least one argument") } case *Wildcard: case *RegexLiteral: default: return errors.New("only time and tag dimensions allowed") } } return nil } // 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 func (s *SelectStatement) validSelectWithAggregate() error { calls := map[string]struct{}{} numAggregates := 0 for _, f := range s.Fields { fieldCalls := walkFunctionCalls(f.Expr) for _, c := range fieldCalls { calls[c.Name] = struct{}{} } if len(fieldCalls) != 0 { numAggregates++ } } // For TOP, BOTTOM, MAX, MIN, FIRST, LAST, PERCENTILE (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", "percentile", "sample": default: onlySelectors = false break } } 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].(*IntegerLiteral) 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 the call to PERCENTILE has 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) } switch expr.Args[0].(type) { case *VarRef, *RegexLiteral, *Wildcard: // do nothing default: return fmt.Errorf("expected field argument in percentile()") } switch expr.Args[1].(type) { case *IntegerLiteral, *NumberLiteral: return nil default: return fmt.Errorf("expected float argument in percentile()") } } // validPercentileAggr determines if the call to SAMPLE has valid arguments. func (s *SelectStatement) validSampleAggr(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) } switch expr.Args[0].(type) { case *VarRef, *RegexLiteral, *Wildcard: // do nothing default: return fmt.Errorf("expected field argument in sample()") } switch expr.Args[1].(type) { case *IntegerLiteral: return nil default: return fmt.Errorf("expected integer argument in sample()") } } func (s *SelectStatement) validateAggregates(tr targetRequirement) error { for _, f := range s.Fields { for _, expr := range walkFunctionCalls(f.Expr) { switch expr.Name { case "derivative", "non_negative_derivative", "difference", "non_negative_difference", "moving_average", "cumulative_sum", "elapsed": if err := s.validSelectWithAggregate(); err != nil { return err } switch expr.Name { case "derivative", "non_negative_derivative", "elapsed": 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) } // If a duration arg is passed, make sure it's a duration if len(expr.Args) == 2 { // Second must be a duration .e.g (1h) if _, ok := expr.Args[1].(*DurationLiteral); !ok { return fmt.Errorf("second argument to %s must be a duration, got %T", expr.Name, expr.Args[1]) } } case "difference", "non_negative_difference", "cumulative_sum": if got := len(expr.Args); got != 1 { return fmt.Errorf("invalid number of arguments for %s, expected 1, got %d", expr.Name, got) } case "moving_average": if got := len(expr.Args); got != 2 { return fmt.Errorf("invalid number of arguments for moving_average, expected 2, got %d", got) } if lit, ok := expr.Args[1].(*IntegerLiteral); !ok { return fmt.Errorf("second argument for moving_average must be an integer, got %T", expr.Args[1]) } else if lit.Val <= 1 { return fmt.Errorf("moving_average window must be greater than 1, got %d", lit.Val) } else if int64(int(lit.Val)) != lit.Val { return fmt.Errorf("moving_average window too large, got %d", lit.Val) } } // 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 c, ok := expr.Args[0].(*Call); ok && groupByInterval == 0 && tr != targetSubquery { return fmt.Errorf("%s aggregate requires a GROUP BY interval", expr.Name) } else if !ok && groupByInterval > 0 { return fmt.Errorf("aggregate function required inside the call to %s", expr.Name) } else if ok { 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) } switch fc := c.Args[0].(type) { case *VarRef, *Wildcard, *RegexLiteral: // do nothing case *Call: if fc.Name != "distinct" || expr.Name != "count" { return fmt.Errorf("expected field argument in %s()", c.Name) } else if exp, got := 1, len(fc.Args); got != exp { return fmt.Errorf("count(distinct %s) can only have %d argument(s), got %d", fc.Name, exp, got) } else if _, ok := fc.Args[0].(*VarRef); !ok { return fmt.Errorf("expected field argument in distinct()") } case *Distinct: if expr.Name != "count" { return fmt.Errorf("expected field argument in %s()", c.Name) } default: return fmt.Errorf("expected field argument in %s()", c.Name) } } } case "top", "bottom": if err := s.validTopBottomAggr(expr); err != nil { return err } case "percentile": if err := s.validPercentileAggr(expr); err != nil { return err } case "sample": if err := s.validSampleAggr(expr); err != nil { return err } case "integral": if err := s.validSelectWithAggregate(); err != nil { return err } 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) } // If a duration arg is passed, make sure it's a duration if len(expr.Args) == 2 { // Second must be a duration .e.g (1h) if _, ok := expr.Args[1].(*DurationLiteral); !ok { return errors.New("second argument must be a duration") } } case "holt_winters", "holt_winters_with_fit": if exp, got := 3, len(expr.Args); got != exp { return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", expr.Name, exp, 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 _, ok := expr.Args[0].(*Call); ok && groupByInterval == 0 && tr != targetSubquery { return fmt.Errorf("%s aggregate requires a GROUP BY interval", expr.Name) } else if !ok { return fmt.Errorf("must use aggregate function with %s", expr.Name) } if arg, ok := expr.Args[1].(*IntegerLiteral); !ok { return fmt.Errorf("expected integer argument as second arg in %s", expr.Name) } else if arg.Val <= 0 { return fmt.Errorf("second arg to %s must be greater than 0, got %d", expr.Name, arg.Val) } if _, ok := expr.Args[2].(*IntegerLiteral); !ok { return fmt.Errorf("expected integer argument as third arg in %s", expr.Name) } default: if err := s.validSelectWithAggregate(); err != nil { return err } if exp, got := 1, len(expr.Args); got != exp { // Special error message if distinct was used as the argument. if expr.Name == "count" && got >= 1 { if _, ok := expr.Args[0].(*Distinct); ok { return fmt.Errorf("count(distinct ) can only have one argument") } } return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", expr.Name, exp, got) } switch fc := expr.Args[0].(type) { case *VarRef, *Wildcard, *RegexLiteral: // do nothing case *Call: if fc.Name != "distinct" || expr.Name != "count" { return fmt.Errorf("expected field argument in %s()", expr.Name) } else if exp, got := 1, len(fc.Args); got != exp { return fmt.Errorf("count(distinct ) can only have one argument") } else if _, ok := fc.Args[0].(*VarRef); !ok { return fmt.Errorf("expected field argument in distinct()") } case *Distinct: if expr.Name != "count" { return fmt.Errorf("expected field argument in %s()", expr.Name) } default: return fmt.Errorf("expected field argument in %s()", expr.Name) } } } } // Check that we have valid duration and where clauses for aggregates // fetch the group by duration groupByDuration, _ := s.GroupByInterval() // If we have a group by interval, but no aggregate function, it's an invalid statement if s.IsRawQuery && groupByDuration > 0 { 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 err := s.validateTimeExpression(); err != nil { return err } } if tr != targetSubquery { if err := s.validateGroupByInterval(); err != nil { return err } } return nil } // validateFill ensures that the fill option matches the query type. func (s *SelectStatement) validateFill() error { info := newSelectInfo(s) if len(info.calls) == 0 { switch s.Fill { case NoFill: return errors.New("fill(none) must be used with a function") case LinearFill: return errors.New("fill(linear) must be used with a function") } } return nil } // validateTimeExpression ensures that any select statements that have a group // by interval either have a time expression limiting the time range or have a // parent query that does that. func (s *SelectStatement) validateTimeExpression() error { // If we have a time expression, we and all subqueries are fine. if HasTimeExpr(s.Condition) { return nil } // Check if this is not a raw query and if the group by duration exists. // If these are true, then we have an error. interval, err := s.GroupByInterval() if err != nil { return err } else if !s.IsRawQuery && interval > 0 { return fmt.Errorf("aggregate functions with GROUP BY time require a WHERE time clause") } // Validate the subqueries. If we have a time expression in this select // statement, we don't need to do this because parent time ranges propagate // to children. So we only execute this when there is no time condition in // the parent. for _, source := range s.Sources { switch source := source.(type) { case *SubQuery: if err := source.Statement.validateTimeExpression(); err != nil { return err } } } return nil } // validateGroupByInterval ensures that a select statement is grouped by an // interval if it contains certain functions. func (s *SelectStatement) validateGroupByInterval() error { interval, err := s.GroupByInterval() if err != nil { return err } else if interval > 0 { // If we have an interval here, that means the interval will propagate // into any subqueries and we can just stop looking. return nil } // Check inside of the fields for any of the specific functions that ned a group by interval. for _, f := range s.Fields { switch expr := f.Expr.(type) { case *Call: switch expr.Name { case "derivative", "non_negative_derivative", "difference", "non_negative_difference", "moving_average", "cumulative_sum", "elapsed", "holt_winters", "holt_winters_with_fit": // If the first argument is a call, we needed a group by interval and we don't have one. if _, ok := expr.Args[0].(*Call); ok { return fmt.Errorf("%s aggregate requires a GROUP BY interval", expr.Name) } } } } // Validate the subqueries. for _, source := range s.Sources { switch source := source.(type) { case *SubQuery: if err := source.Statement.validateGroupByInterval(); err != nil { return err } } } return nil } // HasDistinct checks if a select statement contains a call to DISTINCT. func (s *SelectStatement) HasDistinct() bool { for _, f := range s.Fields { switch c := f.Expr.(type) { case *Call: if c.Name == "distinct" { return true } case *Distinct: return true } } return false } func (s *SelectStatement) validateDistinct() error { if !s.HasDistinct() { return nil } if len(s.Fields) > 1 { return fmt.Errorf("aggregate function distinct() cannot 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") } if len(c.Args) != 1 { return fmt.Errorf("distinct function can only have one argument") } } return nil } func (s *SelectStatement) validateTopBottom() error { // Ensure there are not multiple calls if top/bottom is present. info := newSelectInfo(s) if len(info.calls) > 1 { for call := range info.calls { if call.Name == "top" || call.Name == "bottom" { return fmt.Errorf("selector function %s() cannot be combined with other functions", call.Name) } } } return nil } // GroupByInterval 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 { if call, ok := d.Expr.(*Call); ok && call.Name == "time" { // Make sure there is exactly one argument. if got := len(call.Args); got < 1 || got > 2 { return 0, errors.New("time dimension expected 1 or 2 arguments") } // Ensure the argument is a duration. lit, ok := call.Args[0].(*DurationLiteral) if !ok { return 0, errors.New("time dimension must have duration argument") } s.groupByInterval = lit.Val return lit.Val, nil } } return 0, nil } // GroupByOffset extracts the time interval offset, if specified. func (s *SelectStatement) GroupByOffset() (time.Duration, error) { interval, err := s.GroupByInterval() if err != nil { return 0, err } // Ignore if there are no dimensions. if len(s.Dimensions) == 0 { return 0, nil } for _, d := range s.Dimensions { if call, ok := d.Expr.(*Call); ok && call.Name == "time" { if len(call.Args) == 2 { switch expr := call.Args[1].(type) { case *DurationLiteral: return expr.Val % interval, nil case *TimeLiteral: return expr.Val.Sub(expr.Val.Truncate(interval)), nil default: return 0, fmt.Errorf("invalid time dimension offset: %s", expr) } } return 0, 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 dimensions 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 case *Call: return &BooleanLiteral{Val: true} default: return n } }) return n.String() } // 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) } return a } // 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)...) } return a } // NamesInDimension returns the field and tag names (idents) in the group by clause. func (s *SelectStatement) NamesInDimension() []string { var a []string for _, d := range s.Dimensions { a = append(a, walkNames(d.Expr)...) } return a } // LimitTagSets returns a tag set list with SLIMIT and SOFFSET applied. func LimitTagSets(a []*TagSet, slimit, soffset int) []*TagSet { // Ignore if no limit or offset is specified. if slimit == 0 && soffset == 0 { return a } // If offset is beyond the number of tag sets then return nil. if soffset > len(a) { return nil } // Clamp limit to the max number of tag sets. if soffset+slimit > len(a) { slimit = len(a) - soffset } return a[soffset : soffset+slimit] } // walkNames will walk the Expr and return the identifier names used. func walkNames(exp Expr) []string { switch expr := exp.(type) { case *VarRef: return []string{expr.Val} case *Call: var a []string for _, expr := range expr.Args { if ref, ok := expr.(*VarRef); ok { a = append(a, ref.Val) } } return a case *BinaryExpr: 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 } // walkRefs will walk the Expr and return the var refs used. func walkRefs(exp Expr) []VarRef { refs := make(map[VarRef]struct{}) var walk func(exp Expr) walk = func(exp Expr) { switch expr := exp.(type) { case *VarRef: refs[*expr] = struct{}{} case *Call: for _, expr := range expr.Args { if ref, ok := expr.(*VarRef); ok { refs[*ref] = struct{}{} } } case *BinaryExpr: walk(expr.LHS) walk(expr.RHS) case *ParenExpr: walk(expr.Expr) } } walk(exp) // Turn the map into a slice. a := make([]VarRef, 0, len(refs)) for ref := range refs { a = append(a, ref) } return a } // ExprNames returns a list of non-"time" field names from an expression. func ExprNames(expr Expr) []VarRef { m := make(map[VarRef]struct{}) for _, ref := range walkRefs(expr) { if ref.Val == "time" { continue } m[ref] = struct{}{} } a := make([]VarRef, 0, len(m)) for k := range m { a = append(a, k) } sort.Sort(VarRefs(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 } // FunctionCallsByPosition returns the Call objects from the query in the order they appear in the select statement. func (s *SelectStatement) FunctionCallsByPosition() [][]*Call { var a [][]*Call for _, f := range s.Fields { a = append(a, walkFunctionCalls(f.Expr)) } return a } // walkFunctionCalls walks the Expr and returns 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 } // MatchSource returns the source name that matches a field name. // It returns a blank string if no sources match. 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 "" } // 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() } // DeleteStatement represents a command for deleting data from the database. type DeleteStatement struct { // Data source that values are removed from. Source Source // 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() } // RequiredPrivileges returns the privilege required to execute a DeleteStatement. func (s *DeleteStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: WritePrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *DeleteStatement) DefaultDatabase() string { if m, ok := s.Source.(*Measurement); ok { return m.Database } return "" } // ShowSeriesStatement represents a command for listing series in the database. type ShowSeriesStatement struct { // Database to query. If blank, use the default database. // The database can also be specified per source in the Sources. Database string // Measurement(s) the series are listed for. Sources Sources // 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 // Returns rows starting at an offset from the first row. Offset int } // String returns a string representation of the list series statement. func (s *ShowSeriesStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("SHOW SERIES") if s.Database != "" { _, _ = buf.WriteString(" ON ") _, _ = buf.WriteString(QuoteIdent(s.Database)) } 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)) } if s.Offset > 0 { _, _ = buf.WriteString(" OFFSET ") _, _ = buf.WriteString(strconv.Itoa(s.Offset)) } return buf.String() } // RequiredPrivileges returns the privilege required to execute a ShowSeriesStatement. func (s *ShowSeriesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *ShowSeriesStatement) DefaultDatabase() string { return s.Database } // DropSeriesStatement represents a command for removing a series from the database. type DropSeriesStatement struct { // Data source that fields are extracted from (optional) Sources Sources // An expression evaluated on data point (optional) Condition Expr } // String returns a string representation of the drop series statement. func (s *DropSeriesStatement) String() string { var buf bytes.Buffer buf.WriteString("DROP 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()) } return buf.String() } // RequiredPrivileges returns the privilege required to execute a DropSeriesStatement. func (s DropSeriesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: WritePrivilege}}, nil } // DeleteSeriesStatement represents a command for deleting all or part of a series from a database. type DeleteSeriesStatement struct { // Data source that fields are extracted from (optional) Sources Sources // An expression evaluated on data point (optional) Condition Expr } // String returns a string representation of the delete series statement. func (s *DeleteSeriesStatement) String() string { var buf bytes.Buffer buf.WriteString("DELETE") if s.Sources != nil { buf.WriteString(" FROM ") buf.WriteString(s.Sources.String()) } if s.Condition != nil { buf.WriteString(" WHERE ") buf.WriteString(s.Condition.String()) } return buf.String() } // RequiredPrivileges returns the privilege required to execute a DeleteSeriesStatement. func (s DeleteSeriesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: WritePrivilege}}, nil } // DropShardStatement represents a command for removing a shard from // the node. type DropShardStatement struct { // ID of the shard to be dropped. ID uint64 } // String returns a string representation of the drop series statement. func (s *DropShardStatement) String() string { var buf bytes.Buffer buf.WriteString("DROP SHARD ") buf.WriteString(strconv.FormatUint(s.ID, 10)) return buf.String() } // RequiredPrivileges returns the privilege required to execute a // DropShardStatement. func (s *DropShardStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // ShowContinuousQueriesStatement represents a command for listing continuous queries. type ShowContinuousQueriesStatement struct{} // String returns a string representation of the show continuous queries statement. func (s *ShowContinuousQueriesStatement) String() string { return "SHOW CONTINUOUS QUERIES" } // RequiredPrivileges returns the privilege required to execute a ShowContinuousQueriesStatement. func (s *ShowContinuousQueriesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // 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 ") _, _ = buf.WriteString(QuoteIdent(s.Name)) return buf.String() } // RequiredPrivileges returns the privilege required to execute a ShowGrantsForUserStatement func (s *ShowGrantsForUserStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // ShowDatabasesStatement represents a command for listing all databases in the cluster. type ShowDatabasesStatement struct{} // String returns a string representation of the show databases command. func (s *ShowDatabasesStatement) String() string { return "SHOW DATABASES" } // RequiredPrivileges returns the privilege required to execute a ShowDatabasesStatement. func (s *ShowDatabasesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { // SHOW DATABASES is one of few statements that have no required privileges. // Anyone is allowed to execute it, but the returned results depend on the user's // individual database permissions. return ExecutionPrivileges{{Admin: false, Name: "", Privilege: NoPrivileges}}, nil } // CreateContinuousQueryStatement represents a command for creating a continuous query. 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). Source *SelectStatement // Interval to resample previous queries. ResampleEvery time.Duration // Maximum duration to resample previous queries. ResampleFor time.Duration } // String returns a string representation of the statement. func (s *CreateContinuousQueryStatement) String() string { 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 } // RequiredPrivileges returns the privilege required to execute a CreateContinuousQueryStatement. func (s *CreateContinuousQueryStatement) RequiredPrivileges() (ExecutionPrivileges, error) { 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, nil } 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 } // DropContinuousQueryStatement represents a command for removing a continuous query. type DropContinuousQueryStatement struct { 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)) } // RequiredPrivileges returns the privilege(s) required to execute a DropContinuousQueryStatement func (s *DropContinuousQueryStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: WritePrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *DropContinuousQueryStatement) DefaultDatabase() string { return s.Database } // ShowMeasurementsStatement represents a command for listing measurements. type ShowMeasurementsStatement struct { // Database to query. If blank, use the default database. Database string // 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 // Returns rows starting at an offset from the first row. Offset int } // String returns a string representation of the statement. func (s *ShowMeasurementsStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("SHOW MEASUREMENTS") if s.Database != "" { _, _ = buf.WriteString(" ON ") _, _ = buf.WriteString(s.Database) } 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)) } if s.Offset > 0 { _, _ = buf.WriteString(" OFFSET ") _, _ = buf.WriteString(strconv.Itoa(s.Offset)) } return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a ShowMeasurementsStatement. func (s *ShowMeasurementsStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *ShowMeasurementsStatement) DefaultDatabase() string { return s.Database } // DropMeasurementStatement represents a command to drop a measurement. 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)) return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a DropMeasurementStatement func (s *DropMeasurementStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // ShowQueriesStatement represents a command for listing all running queries. type ShowQueriesStatement struct{} // String returns a string representation of the show queries statement. func (s *ShowQueriesStatement) String() string { return "SHOW QUERIES" } // RequiredPrivileges returns the privilege required to execute a ShowQueriesStatement. func (s *ShowQueriesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // ShowRetentionPoliciesStatement represents a command for listing retention policies. type ShowRetentionPoliciesStatement struct { // Name of the database to list policies for. Database string } // String returns a string representation of a ShowRetentionPoliciesStatement. func (s *ShowRetentionPoliciesStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("SHOW RETENTION POLICIES") if s.Database != "" { _, _ = buf.WriteString(" ON ") _, _ = buf.WriteString(QuoteIdent(s.Database)) } return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a ShowRetentionPoliciesStatement func (s *ShowRetentionPoliciesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *ShowRetentionPoliciesStatement) DefaultDatabase() string { return s.Database } // ShowStatsStatement displays statistics for a given module. type ShowStatsStatement struct { Module string } // String returns a string representation of a ShowStatsStatement. func (s *ShowStatsStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("SHOW STATS") if s.Module != "" { _, _ = buf.WriteString(" FOR ") _, _ = buf.WriteString(QuoteString(s.Module)) } return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a ShowStatsStatement func (s *ShowStatsStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // 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, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // 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, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // ShowDiagnosticsStatement represents a command for show node diagnostics. type ShowDiagnosticsStatement struct { // Module Module string } // 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(QuoteString(s.Module)) } return buf.String() } // RequiredPrivileges returns the privilege required to execute a ShowDiagnosticsStatement func (s *ShowDiagnosticsStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // 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, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // DefaultDatabase returns the default database from the statement. func (s *CreateSubscriptionStatement) DefaultDatabase() string { return s.Database } // 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, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // DefaultDatabase returns the default database from the statement. func (s *DropSubscriptionStatement) DefaultDatabase() string { return s.Database } // ShowSubscriptionsStatement represents a command to show a list of subscriptions. type ShowSubscriptionsStatement struct { } // String returns a string representation of the ShowSubscriptionsStatement. func (s *ShowSubscriptionsStatement) String() string { return "SHOW SUBSCRIPTIONS" } // RequiredPrivileges returns the privilege required to execute a ShowSubscriptionsStatement. func (s *ShowSubscriptionsStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // ShowTagKeysStatement represents a command for listing tag keys. type ShowTagKeysStatement struct { // Database to query. If blank, use the default database. // The database can also be specified per source in the Sources. Database string // 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 // Returns tag keys 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 } // String returns a string representation of the statement. func (s *ShowTagKeysStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("SHOW TAG KEYS") if s.Database != "" { _, _ = buf.WriteString(" ON ") _, _ = buf.WriteString(QuoteIdent(s.Database)) } 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)) } 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() } // RequiredPrivileges returns the privilege(s) required to execute a ShowTagKeysStatement. func (s *ShowTagKeysStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *ShowTagKeysStatement) DefaultDatabase() string { return s.Database } // ShowTagValuesStatement represents a command for listing tag values. type ShowTagValuesStatement struct { // Database to query. If blank, use the default database. // The database can also be specified per source in the Sources. Database string // Data source that fields are extracted from. Sources Sources // Operation to use when selecting tag key(s). Op Token // Literal to compare the tag key(s) with. TagKeyExpr Literal // 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 // Returns rows starting at an offset from the first row. Offset int } // String returns a string representation of the statement. func (s *ShowTagValuesStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("SHOW TAG VALUES") if s.Database != "" { _, _ = buf.WriteString(" ON ") _, _ = buf.WriteString(QuoteIdent(s.Database)) } if s.Sources != nil { _, _ = buf.WriteString(" FROM ") _, _ = buf.WriteString(s.Sources.String()) } _, _ = buf.WriteString(" WITH KEY ") _, _ = buf.WriteString(s.Op.String()) _, _ = buf.WriteString(" ") if lit, ok := s.TagKeyExpr.(*StringLiteral); ok { _, _ = buf.WriteString(QuoteIdent(lit.Val)) } else { _, _ = buf.WriteString(s.TagKeyExpr.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)) } if s.Offset > 0 { _, _ = buf.WriteString(" OFFSET ") _, _ = buf.WriteString(strconv.Itoa(s.Offset)) } return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a ShowTagValuesStatement. func (s *ShowTagValuesStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *ShowTagValuesStatement) DefaultDatabase() string { return s.Database } // ShowUsersStatement represents a command for listing users. type ShowUsersStatement struct{} // String returns a string representation of the ShowUsersStatement. func (s *ShowUsersStatement) String() string { return "SHOW USERS" } // RequiredPrivileges returns the privilege(s) required to execute a ShowUsersStatement func (s *ShowUsersStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: true, Name: "", Privilege: AllPrivileges}}, nil } // ShowFieldKeysStatement represents a command for listing field keys. type ShowFieldKeysStatement struct { // Database to query. If blank, use the default database. // The database can also be specified per source in the Sources. Database string // 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 // Returns rows starting at an offset from the first row. Offset int } // String returns a string representation of the statement. func (s *ShowFieldKeysStatement) String() string { var buf bytes.Buffer _, _ = buf.WriteString("SHOW FIELD KEYS") if s.Database != "" { _, _ = buf.WriteString(" ON ") _, _ = buf.WriteString(QuoteIdent(s.Database)) } 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)) } if s.Offset > 0 { _, _ = buf.WriteString(" OFFSET ") _, _ = buf.WriteString(strconv.Itoa(s.Offset)) } return buf.String() } // RequiredPrivileges returns the privilege(s) required to execute a ShowFieldKeysStatement. func (s *ShowFieldKeysStatement) RequiredPrivileges() (ExecutionPrivileges, error) { return ExecutionPrivileges{{Admin: false, Name: "", Privilege: ReadPrivilege}}, nil } // DefaultDatabase returns the default database from the statement. func (s *ShowFieldKeysStatement) DefaultDatabase() string { return s.Database } // Fields represents a list of fields. type Fields []*Field // 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 } // Names returns a list of field names. func (a Fields) Names() []string { names := []string{} for _, f := range a { switch expr := f.Expr.(type) { case *Call: names = append(names, expr.Name) case *VarRef: names = append(names, expr.Val) case *BinaryExpr: names = append(names, walkNames(expr)...) case *ParenExpr: names = append(names, walkNames(expr)...) } } 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, ", ") } // Field represents an expression retrieved from a select statement. type Field struct { Expr Expr Alias string } // 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 *BinaryExpr: return BinaryExprName(expr) case *ParenExpr: f := Field{Expr: expr.Expr} return f.Name() case *VarRef: return expr.Val } // Otherwise return a blank name. return "" } // String returns a string representation of the field. func (f *Field) String() string { str := f.Expr.String() if f.Alias == "" { return str } return fmt.Sprintf("%s AS %s", str, QuoteIdent(f.Alias)) } // Len implements sort.Interface. func (a Fields) Len() int { return len(a) } // Less implements sort.Interface. func (a Fields) Less(i, j int) bool { return a[i].Name() < a[j].Name() } // Swap implements sort.Interface. func (a Fields) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // 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, ", ") } // Normalize returns the interval and tag dimensions separately. // Returns 0 if no time interval is specified. func (a Dimensions) Normalize() (time.Duration, []string) { 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 case *VarRef: tags = append(tags, expr.Val) } } return dur, tags } // Dimension represents an expression that a select statement is grouped by. type Dimension struct { Expr Expr } // 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 } // String returns a string representation of the measurement. func (m *Measurement) String() string { var buf bytes.Buffer if m.Database != "" { _, _ = buf.WriteString(QuoteIdent(m.Database)) _, _ = buf.WriteString(".") } if m.RetentionPolicy != "" { _, _ = buf.WriteString(QuoteIdent(m.RetentionPolicy)) } if m.Database != "" || m.RetentionPolicy != "" { _, _ = buf.WriteString(`.`) } if m.Name != "" { _, _ = buf.WriteString(QuoteIdent(m.Name)) } else if m.Regex != nil { _, _ = buf.WriteString(m.Regex.String()) } return buf.String() } func encodeMeasurement(mm *Measurement) *internal.Measurement { pb := &internal.Measurement{ Database: proto.String(mm.Database), RetentionPolicy: proto.String(mm.RetentionPolicy), Name: proto.String(mm.Name), IsTarget: proto.Bool(mm.IsTarget), } if mm.Regex != nil { pb.Regex = proto.String(mm.Regex.Val.String()) } return pb } func decodeMeasurement(pb *internal.Measurement) (*Measurement, error) { mm := &Measurement{ Database: pb.GetDatabase(), RetentionPolicy: pb.GetRetentionPolicy(), Name: pb.GetName(), IsTarget: pb.GetIsTarget(), } if pb.Regex != nil { regex, err := regexp.Compile(pb.GetRegex()) if err != nil { return nil, fmt.Errorf("invalid binary measurement regex: value=%q, err=%s", pb.GetRegex(), err) } mm.Regex = &RegexLiteral{Val: regex} } return mm, nil } // SubQuery is a source with a SelectStatement as the backing store. type SubQuery struct { Statement *SelectStatement } // String returns a string representation of the subquery. func (s *SubQuery) String() string { return fmt.Sprintf("(%s)", s.Statement.String()) } // VarRef represents a reference to a variable. type VarRef struct { Val string Type DataType } // String returns a string representation of the variable reference. func (r *VarRef) String() string { buf := bytes.NewBufferString(QuoteIdent(r.Val)) if r.Type != Unknown { buf.WriteString("::") buf.WriteString(r.Type.String()) } return buf.String() } // VarRefs represents a slice of VarRef types. type VarRefs []VarRef // Len implements sort.Interface. func (a VarRefs) Len() int { return len(a) } // Less implements sort.Interface. func (a VarRefs) Less(i, j int) bool { if a[i].Val != a[j].Val { return a[i].Val < a[j].Val } return a[i].Type < a[j].Type } // Swap implements sort.Interface. func (a VarRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // Strings returns a slice of the variable names. func (a VarRefs) Strings() []string { s := make([]string, len(a)) for i, ref := range a { s[i] = ref.Val } return s } // Call represents a function call. type Call struct { Name string Args []Expr } // 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, ", ")) } // 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}, }, } } // NumberLiteral represents a numeric literal. type NumberLiteral struct { Val float64 } // String returns a string representation of the literal. func (l *NumberLiteral) String() string { return strconv.FormatFloat(l.Val, 'f', 3, 64) } // IntegerLiteral represents an integer literal. type IntegerLiteral struct { Val int64 } // String returns a string representation of the literal. func (l *IntegerLiteral) String() string { return fmt.Sprintf("%d", l.Val) } // BooleanLiteral represents a boolean literal. 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" } // 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 } // ListLiteral represents a list of tag key literals. type ListLiteral struct { Vals []string } // String returns a string representation of the literal. func (s *ListLiteral) String() string { var buf bytes.Buffer _, _ = buf.WriteString("(") for idx, tagKey := range s.Vals { if idx != 0 { _, _ = buf.WriteString(", ") } _, _ = buf.WriteString(QuoteIdent(tagKey)) } _, _ = buf.WriteString(")") return buf.String() } // StringLiteral represents a string literal. type StringLiteral struct { Val string } // String returns a string representation of the literal. func (l *StringLiteral) String() string { return QuoteString(l.Val) } // IsTimeLiteral returns if this string can be interpreted as a time literal. func (l *StringLiteral) IsTimeLiteral() bool { return isDateTimeString(l.Val) || isDateString(l.Val) } // ToTimeLiteral returns a time literal if this string can be converted to a time literal. func (l *StringLiteral) ToTimeLiteral(loc *time.Location) (*TimeLiteral, error) { if loc == nil { loc = time.UTC } if isDateTimeString(l.Val) { t, err := time.ParseInLocation(DateTimeFormat, l.Val, loc) if err != nil { // try to parse it as an RFCNano time t, err = time.ParseInLocation(time.RFC3339Nano, l.Val, loc) if err != nil { return nil, ErrInvalidTime } } return &TimeLiteral{Val: t}, nil } else if isDateString(l.Val) { t, err := time.ParseInLocation(DateFormat, l.Val, loc) if err != nil { return nil, ErrInvalidTime } return &TimeLiteral{Val: t}, nil } return nil, ErrInvalidTime } // TimeLiteral represents a point-in-time literal. type TimeLiteral struct { Val time.Time } // String returns a string representation of the literal. func (l *TimeLiteral) String() string { return `'` + l.Val.UTC().Format(time.RFC3339Nano) + `'` } // DurationLiteral represents a duration literal. type DurationLiteral struct { Val time.Duration } // String returns a string representation of the literal. func (l *DurationLiteral) String() string { return FormatDuration(l.Val) } // 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` } // 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()) } func (e *BinaryExpr) validate() error { v := binaryExprValidator{} Walk(&v, e) if v.err != nil { return v.err } else if v.calls && v.refs { return errors.New("binary expressions cannot mix aggregates and raw fields") } return nil } type binaryExprValidator struct { calls bool refs bool err error } func (v *binaryExprValidator) Visit(n Node) Visitor { if v.err != nil { return nil } switch n := n.(type) { case *Call: v.calls = true if n.Name == "top" || n.Name == "bottom" { v.err = fmt.Errorf("cannot use %s() inside of a binary expression", n.Name) return nil } for _, expr := range n.Args { switch e := expr.(type) { case *BinaryExpr: v.err = e.validate() return nil } } return nil case *VarRef: v.refs = true return nil } return v } // BinaryExprName returns the name of a binary expression by concatenating // the variables in the binary expression with underscores. func BinaryExprName(expr *BinaryExpr) string { v := binaryExprNameVisitor{} Walk(&v, expr) return strings.Join(v.names, "_") } type binaryExprNameVisitor struct { names []string } func (v *binaryExprNameVisitor) Visit(n Node) Visitor { switch n := n.(type) { case *VarRef: v.names = append(v.names, n.Val) case *Call: v.names = append(v.names, n.Name) return nil } return v } // 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. func (r *RegexLiteral) String() string { if r.Val != nil { return fmt.Sprintf("/%s/", strings.Replace(r.Val.String(), `/`, `\/`, -1)) } 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 } // Wildcard represents a wild card expression. type Wildcard struct { Type Token } // String returns a string representation of the wildcard. func (e *Wildcard) String() string { switch e.Type { case FIELD: return "*::field" case TAG: return "*::tag" default: return "*" } } // CloneExpr returns a deep copy of the expression. func CloneExpr(expr Expr) Expr { if expr == nil { return nil } switch expr := expr.(type) { case *BinaryExpr: return &BinaryExpr{Op: expr.Op, LHS: CloneExpr(expr.LHS), RHS: CloneExpr(expr.RHS)} case *BooleanLiteral: return &BooleanLiteral{Val: expr.Val} case *Call: args := make([]Expr, len(expr.Args)) for i, arg := range expr.Args { args[i] = CloneExpr(arg) } return &Call{Name: expr.Name, Args: args} case *Distinct: return &Distinct{Val: expr.Val} case *DurationLiteral: return &DurationLiteral{Val: expr.Val} case *IntegerLiteral: return &IntegerLiteral{Val: expr.Val} case *NumberLiteral: return &NumberLiteral{Val: expr.Val} case *ParenExpr: return &ParenExpr{Expr: CloneExpr(expr.Expr)} case *RegexLiteral: return &RegexLiteral{Val: expr.Val} case *StringLiteral: return &StringLiteral{Val: expr.Val} case *TimeLiteral: return &TimeLiteral{Val: expr.Val} case *VarRef: return &VarRef{Val: expr.Val, Type: expr.Type} case *Wildcard: return &Wildcard{Type: expr.Type} } panic("unreachable") } // 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. // It returns zero times if there is no bound. func TimeRange(expr Expr, loc *time.Location) (min, max time.Time, err error) { WalkFunc(expr, func(n Node) { if err != nil { return } 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. op := n.Op var value time.Time value, err = timeExprValue(n.LHS, n.RHS, loc) if err != nil { return } else if value.IsZero() { if value, err = timeExprValue(n.RHS, n.LHS, loc); value.IsZero() || err != nil { 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 } if max.IsZero() || value.Before(max) { max = value } } } }) return } // TimeRangeAsEpochNano returns the minimum and maximum times, as epoch nano, specified by // an expression. If there is no lower bound, the minimum time is returned // for minimum. If there is no higher bound, the maximum time is returned. func TimeRangeAsEpochNano(expr Expr) (min, max int64, err error) { tmin, tmax, err := TimeRange(expr, nil) if err != nil { return 0, 0, err } if tmin.IsZero() { min = time.Unix(0, MinTime).UnixNano() } else { min = tmin.UnixNano() } if tmax.IsZero() { max = time.Unix(0, MaxTime).UnixNano() } else { max = tmax.UnixNano() } return } // timeExprValue returns the time literal value of a "time == " expression. // Returns zero time if the expression is not a time expression. func timeExprValue(ref Expr, lit Expr, loc *time.Location) (t time.Time, err error) { if ref, ok := ref.(*VarRef); ok && strings.ToLower(ref.Val) == "time" { // If literal looks like a date time then parse it as a time literal. if strlit, ok := lit.(*StringLiteral); ok { if strlit.IsTimeLiteral() { t, err := strlit.ToTimeLiteral(loc) if err != nil { return time.Time{}, err } lit = t } } switch lit := lit.(type) { case *TimeLiteral: if lit.Val.After(time.Unix(0, MaxTime)) { return time.Time{}, fmt.Errorf("time %s overflows time literal", lit.Val.Format(time.RFC3339)) } else if lit.Val.Before(time.Unix(0, MinTime+1)) { // The minimum allowable time literal is one greater than the minimum time because the minimum time // is a sentinel value only used internally. return time.Time{}, fmt.Errorf("time %s underflows time literal", lit.Val.Format(time.RFC3339)) } return lit.Val, nil case *DurationLiteral: return time.Unix(0, int64(lit.Val)).UTC(), nil case *NumberLiteral: return time.Unix(0, int64(lit.Val)).UTC(), nil case *IntegerLiteral: return time.Unix(0, lit.Val).UTC(), nil default: return time.Time{}, fmt.Errorf("invalid operation: time and %T are not compatible", lit) } } return time.Time{}, nil } // 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 } // Walk traverses a node hierarchy in depth-first order. func Walk(v Visitor, node Node) { if node == nil { return } if v = v.Visit(node); v == nil { return } switch n := node.(type) { case *BinaryExpr: Walk(v, n.LHS) Walk(v, n.RHS) 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) } case *DeleteSeriesStatement: Walk(v, n.Sources) Walk(v, n.Condition) 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) } case *ParenExpr: Walk(v, n.Expr) case *Query: Walk(v, n.Statements) case *SelectStatement: Walk(v, n.Fields) Walk(v, n.Target) Walk(v, n.Dimensions) Walk(v, n.Sources) Walk(v, n.Condition) Walk(v, n.SortFields) case *ShowSeriesStatement: Walk(v, n.Sources) Walk(v, n.Condition) case *ShowTagKeysStatement: Walk(v, n.Sources) Walk(v, n.Condition) Walk(v, n.SortFields) case *ShowTagValuesStatement: Walk(v, n.Sources) 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) } case Sources: for _, s := range n { Walk(v, s) } case *SubQuery: Walk(v, n.Statement) case Statements: for _, s := range n { Walk(v, s) } case *Target: if n != nil { Walk(v, n.Measurement) } } } // 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 } // 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) n.Sources = Rewrite(r, n.Sources).(Sources) // Rewrite may return nil. Nil does not satisfy the Expr // interface. We only assert the rewritten result to be an // Expr if it is not nil: if cond := Rewrite(r, n.Condition); cond != nil { n.Condition = cond.(Expr) } else { n.Condition = nil } case *SubQuery: n.Statement = Rewrite(r, n.Statement).(*SelectStatement) 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) } // RewriteExpr recursively invokes the function to replace each expr. // Nodes are traversed depth-first and rewritten from leaf to root. func RewriteExpr(expr Expr, fn func(Expr) Expr) Expr { switch e := expr.(type) { case *BinaryExpr: e.LHS = RewriteExpr(e.LHS, fn) e.RHS = RewriteExpr(e.RHS, fn) if e.LHS != nil && e.RHS == nil { expr = e.LHS } else if e.RHS != nil && e.LHS == nil { expr = e.RHS } else if e.LHS == nil && e.RHS == nil { return nil } case *ParenExpr: e.Expr = RewriteExpr(e.Expr, fn) if e.Expr == nil { return nil } case *Call: for i, expr := range e.Args { e.Args[i] = RewriteExpr(expr, fn) } } return fn(expr) } // 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 *IntegerLiteral: return expr.Val case *NumberLiteral: return expr.Val case *ParenExpr: return Eval(expr.Expr, m) case *RegexLiteral: return expr.Val 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) if lhs == nil && rhs != nil { // When the LHS is nil and the RHS is a boolean, implicitly cast the // nil to false. if _, ok := rhs.(bool); ok { lhs = false } } else if lhs != nil && rhs == nil { // Implicit cast of the RHS nil to false when the LHS is a boolean. if _, ok := lhs.(bool); ok { rhs = false } } // Evaluate if both sides are simple types. switch lhs := lhs.(type) { case bool: rhs, ok := rhs.(bool) switch expr.Op { case AND: return ok && (lhs && rhs) case OR: return ok && (lhs || rhs) case BITWISE_AND: return ok && (lhs && rhs) case BITWISE_OR: return ok && (lhs || rhs) case BITWISE_XOR: return ok && (lhs != rhs) case EQ: return ok && (lhs == rhs) case NEQ: return ok && (lhs != rhs) } case float64: // Try the rhs as a float64 or int64 rhsf, ok := rhs.(float64) if !ok { var rhsi int64 if rhsi, ok = rhs.(int64); ok { rhsf = float64(rhsi) } } rhs := rhsf switch expr.Op { case EQ: return ok && (lhs == rhs) case NEQ: return ok && (lhs != rhs) case LT: return ok && (lhs < rhs) case LTE: return ok && (lhs <= rhs) case GT: return ok && (lhs > rhs) case GTE: return ok && (lhs >= rhs) case ADD: if !ok { return nil } return lhs + rhs case SUB: if !ok { return nil } return lhs - rhs case MUL: if !ok { return nil } return lhs * rhs case DIV: if !ok { return nil } else if rhs == 0 { return float64(0) } return lhs / rhs case MOD: if !ok { return nil } return math.Mod(lhs, rhs) } case int64: // Try as a float64 to see if a float cast is required. rhsf, ok := rhs.(float64) if ok { lhs := float64(lhs) rhs := 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 float64(0) } return lhs / rhs case MOD: return math.Mod(lhs, rhs) } } else { rhs, ok := rhs.(int64) switch expr.Op { case EQ: return ok && (lhs == rhs) case NEQ: return ok && (lhs != rhs) case LT: return ok && (lhs < rhs) case LTE: return ok && (lhs <= rhs) case GT: return ok && (lhs > rhs) case GTE: return ok && (lhs >= rhs) case ADD: if !ok { return nil } return lhs + rhs case SUB: if !ok { return nil } return lhs - rhs case MUL: if !ok { return nil } return lhs * rhs case DIV: if !ok { return nil } else if rhs == 0 { return float64(0) } return lhs / rhs case MOD: if !ok { return nil } else if rhs == 0 { return int64(0) } return lhs % rhs case BITWISE_AND: if !ok { return nil } return lhs & rhs case BITWISE_OR: if !ok { return nil } return lhs | rhs case BITWISE_XOR: if !ok { return nil } return lhs ^ rhs } } case string: switch expr.Op { case EQ: rhs, ok := rhs.(string) if !ok { return nil } return lhs == rhs case NEQ: rhs, ok := rhs.(string) if !ok { return nil } return lhs != rhs case EQREGEX: rhs, ok := rhs.(*regexp.Regexp) if !ok { return nil } return rhs.MatchString(lhs) case NEQREGEX: rhs, ok := rhs.(*regexp.Regexp) if !ok { return nil } return !rhs.MatchString(lhs) } } return nil } // 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 } // TypeMapper maps a data type to the measurement and field. type TypeMapper interface { MapType(measurement *Measurement, field string) DataType } type nilTypeMapper struct{} func (nilTypeMapper) MapType(*Measurement, string) DataType { return Unknown } // EvalType evaluates the expression's type. func EvalType(expr Expr, sources Sources, typmap TypeMapper) DataType { if typmap == nil { typmap = nilTypeMapper{} } switch expr := expr.(type) { case *VarRef: // If this variable already has an assigned type, just use that. if expr.Type != Unknown && expr.Type != AnyField { return expr.Type } var typ DataType for _, src := range sources { switch src := src.(type) { case *Measurement: if t := typmap.MapType(src, expr.Val); typ.LessThan(t) { typ = t } case *SubQuery: _, e := src.Statement.FieldExprByName(expr.Val) if e != nil { if t := EvalType(e, src.Statement.Sources, typmap); typ.LessThan(t) { typ = t } } if typ == Unknown { for _, d := range src.Statement.Dimensions { if d, ok := d.Expr.(*VarRef); ok && expr.Val == d.Val { typ = Tag } } } } } return typ case *Call: switch expr.Name { case "mean", "median", "integral": return Float case "count": return Integer default: return EvalType(expr.Args[0], sources, typmap) } case *ParenExpr: return EvalType(expr.Expr, sources, typmap) case *NumberLiteral: return Float case *IntegerLiteral: return Integer case *StringLiteral: return String case *BooleanLiteral: return Boolean case *BinaryExpr: lhs := EvalType(expr.LHS, sources, typmap) rhs := EvalType(expr.RHS, sources, typmap) if lhs != Unknown && rhs != Unknown { if lhs < rhs { return lhs } else { return rhs } } else if lhs != Unknown { return lhs } else { return rhs } } return Unknown } func FieldDimensions(sources Sources, m FieldMapper) (fields map[string]DataType, dimensions map[string]struct{}, err error) { fields = make(map[string]DataType) dimensions = make(map[string]struct{}) for _, src := range sources { switch src := src.(type) { case *Measurement: f, d, err := m.FieldDimensions(src) if err != nil { return nil, nil, err } for k, typ := range f { if _, ok := fields[k]; typ != Unknown && (!ok || typ < fields[k]) { fields[k] = typ } } for k := range d { dimensions[k] = struct{}{} } case *SubQuery: for _, f := range src.Statement.Fields { k := f.Name() typ := EvalType(f.Expr, src.Statement.Sources, m) if _, ok := fields[k]; typ != Unknown && (!ok || typ < fields[k]) { fields[k] = typ } } for _, d := range src.Statement.Dimensions { if expr, ok := d.Expr.(*VarRef); ok { dimensions[expr.Val] = struct{}{} } } } } return } // 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) case *nilLiteral: return expr 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) loc := time.UTC if v, ok := valuer.(ZoneValuer); ok { loc = v.Zone() } // 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, loc) case *IntegerLiteral: return reduceBinaryExprIntegerLHS(op, lhs, rhs, loc) case *nilLiteral: return reduceBinaryExprNilLHS(op, lhs, rhs) case *NumberLiteral: return reduceBinaryExprNumberLHS(op, lhs, rhs) case *StringLiteral: return reduceBinaryExprStringLHS(op, lhs, rhs, loc) case *TimeLiteral: return reduceBinaryExprTimeLHS(op, lhs, rhs, loc) 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 BITWISE_AND: return &BooleanLiteral{Val: lhs.Val && rhs.Val} case BITWISE_OR: return &BooleanLiteral{Val: lhs.Val || rhs.Val} case BITWISE_XOR: 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, loc *time.Location) 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 *IntegerLiteral: 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 *StringLiteral: t, err := rhs.ToTimeLiteral(loc) if err != nil { break } expr := reduceBinaryExprDurationLHS(op, lhs, t, loc) // If the returned expression is still a binary expr, that means // we couldn't reduce it so this wasn't used in a time literal context. if _, ok := expr.(*BinaryExpr); !ok { return expr } case *nilLiteral: return &BooleanLiteral{Val: false} } return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs} } func reduceBinaryExprIntegerLHS(op Token, lhs *IntegerLiteral, rhs Expr, loc *time.Location) Expr { switch rhs := rhs.(type) { case *NumberLiteral: return reduceBinaryExprNumberLHS(op, &NumberLiteral{Val: float64(lhs.Val)}, rhs) case *IntegerLiteral: switch op { case ADD: return &IntegerLiteral{Val: lhs.Val + rhs.Val} case SUB: return &IntegerLiteral{Val: lhs.Val - rhs.Val} case MUL: return &IntegerLiteral{Val: lhs.Val * rhs.Val} case DIV: if rhs.Val == 0 { return &NumberLiteral{Val: 0} } return &NumberLiteral{Val: float64(lhs.Val) / float64(rhs.Val)} case MOD: if rhs.Val == 0 { return &IntegerLiteral{Val: 0} } return &IntegerLiteral{Val: lhs.Val % rhs.Val} case BITWISE_AND: return &IntegerLiteral{Val: lhs.Val & rhs.Val} case BITWISE_OR: return &IntegerLiteral{Val: lhs.Val | rhs.Val} case BITWISE_XOR: return &IntegerLiteral{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 *DurationLiteral: // Treat the integer as a timestamp. switch op { case ADD: return &TimeLiteral{Val: time.Unix(0, lhs.Val).Add(rhs.Val)} case SUB: return &TimeLiteral{Val: time.Unix(0, lhs.Val).Add(-rhs.Val)} } case *TimeLiteral: d := &DurationLiteral{Val: time.Duration(lhs.Val)} expr := reduceBinaryExprDurationLHS(op, d, rhs, loc) if _, ok := expr.(*BinaryExpr); !ok { return expr } case *StringLiteral: t, err := rhs.ToTimeLiteral(loc) if err != nil { break } d := &DurationLiteral{Val: time.Duration(lhs.Val)} expr := reduceBinaryExprDurationLHS(op, d, t, loc) if _, ok := expr.(*BinaryExpr); !ok { return expr } 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 MOD: return &NumberLiteral{Val: math.Mod(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 *IntegerLiteral: switch op { case ADD: return &NumberLiteral{Val: lhs.Val + float64(rhs.Val)} case SUB: return &NumberLiteral{Val: lhs.Val - float64(rhs.Val)} case MUL: return &NumberLiteral{Val: lhs.Val * float64(rhs.Val)} case DIV: if float64(rhs.Val) == 0 { return &NumberLiteral{Val: 0} } return &NumberLiteral{Val: lhs.Val / float64(rhs.Val)} case MOD: return &NumberLiteral{Val: math.Mod(lhs.Val, float64(rhs.Val))} case EQ: return &BooleanLiteral{Val: lhs.Val == float64(rhs.Val)} case NEQ: return &BooleanLiteral{Val: lhs.Val != float64(rhs.Val)} case GT: return &BooleanLiteral{Val: lhs.Val > float64(rhs.Val)} case GTE: return &BooleanLiteral{Val: lhs.Val >= float64(rhs.Val)} case LT: return &BooleanLiteral{Val: lhs.Val < float64(rhs.Val)} case LTE: return &BooleanLiteral{Val: lhs.Val <= float64(rhs.Val)} } case *nilLiteral: return &BooleanLiteral{Val: false} } return &BinaryExpr{Op: op, LHS: lhs, RHS: rhs} } func reduceBinaryExprStringLHS(op Token, lhs *StringLiteral, rhs Expr, loc *time.Location) Expr { switch rhs := rhs.(type) { case *StringLiteral: switch op { case EQ: var expr Expr = &BooleanLiteral{Val: lhs.Val == rhs.Val} // This might be a comparison between time literals. // If it is, parse the time literals and then compare since it // could be a different result if they use different formats // for the same time. if lhs.IsTimeLiteral() && rhs.IsTimeLiteral() { tlhs, err := lhs.ToTimeLiteral(loc) if err != nil { return expr } trhs, err := rhs.ToTimeLiteral(loc) if err != nil { return expr } t := reduceBinaryExprTimeLHS(op, tlhs, trhs, loc) if _, ok := t.(*BinaryExpr); !ok { expr = t } } return expr case NEQ: var expr Expr = &BooleanLiteral{Val: lhs.Val != rhs.Val} // This might be a comparison between time literals. // If it is, parse the time literals and then compare since it // could be a different result if they use different formats // for the same time. if lhs.IsTimeLiteral() && rhs.IsTimeLiteral() { tlhs, err := lhs.ToTimeLiteral(loc) if err != nil { return expr } trhs, err := rhs.ToTimeLiteral(loc) if err != nil { return expr } t := reduceBinaryExprTimeLHS(op, tlhs, trhs, loc) if _, ok := t.(*BinaryExpr); !ok { expr = t } } return expr case ADD: return &StringLiteral{Val: lhs.Val + rhs.Val} default: // Attempt to convert the string literal to a time literal. t, err := lhs.ToTimeLiteral(loc) if err != nil { break } expr := reduceBinaryExprTimeLHS(op, t, rhs, loc) // If the returned expression is still a binary expr, that means // we couldn't reduce it so this wasn't used in a time literal context. if _, ok := expr.(*BinaryExpr); !ok { return expr } } case *DurationLiteral: // Attempt to convert the string literal to a time literal. t, err := lhs.ToTimeLiteral(loc) if err != nil { break } expr := reduceBinaryExprTimeLHS(op, t, rhs, loc) // If the returned expression is still a binary expr, that means // we couldn't reduce it so this wasn't used in a time literal context. if _, ok := expr.(*BinaryExpr); !ok { return expr } case *TimeLiteral: // Attempt to convert the string literal to a time literal. t, err := lhs.ToTimeLiteral(loc) if err != nil { break } expr := reduceBinaryExprTimeLHS(op, t, rhs, loc) // If the returned expression is still a binary expr, that means // we couldn't reduce it so this wasn't used in a time literal context. if _, ok := expr.(*BinaryExpr); !ok { return expr } case *IntegerLiteral: // Attempt to convert the string literal to a time literal. t, err := lhs.ToTimeLiteral(loc) if err != nil { break } expr := reduceBinaryExprTimeLHS(op, t, rhs, loc) // If the returned expression is still a binary expr, that means // we couldn't reduce it so this wasn't used in a time literal context. if _, ok := expr.(*BinaryExpr); !ok { return expr } 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, loc *time.Location) 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 *IntegerLiteral: d := &DurationLiteral{Val: time.Duration(rhs.Val)} expr := reduceBinaryExprTimeLHS(op, lhs, d, loc) if _, ok := expr.(*BinaryExpr); !ok { return expr } 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 *StringLiteral: t, err := rhs.ToTimeLiteral(loc) if err != nil { break } expr := reduceBinaryExprTimeLHS(op, lhs, t, loc) // If the returned expression is still a binary expr, that means // we couldn't reduce it so this wasn't used in a time literal context. if _, ok := expr.(*BinaryExpr); !ok { return expr } 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. if expr.Name == "now" && len(expr.Args) == 0 && valuer != nil { 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, Type: expr.Type} } // 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, Type: expr.Type} } // 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. type Valuer interface { // Value returns the value and existence flag for a given key. Value(key string) (interface{}, bool) } // ZoneValuer is the interface that specifies the current time zone. type ZoneValuer interface { // Zone returns the time zone location. Zone() *time.Location } // NowValuer returns only the value for "now()". type NowValuer struct { Now time.Time Location *time.Location } // Value is a method that returns the value and existence flag for a given key. func (v *NowValuer) Value(key string) (interface{}, bool) { if key == "now()" { return v.Now, true } return nil, false } // Zone is a method that returns the time.Location. func (v *NowValuer) Zone() *time.Location { if v.Location != nil { return v.Location } return time.UTC } // 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 } func (v *containsVarRefVisitor) Visit(n Node) Visitor { switch n.(type) { case *Call: return nil case *VarRef: v.contains = true } return v } func IsSelector(expr Expr) bool { if call, ok := expr.(*Call); ok { switch call.Name { case "first", "last", "min", "max", "percentile", "sample", "top", "bottom": return true } } return false }