fix #2644: make SHOW FIELD KEYS FROM /regex/ work
parent
8866c09e67
commit
0a8be47ca1
|
@ -1459,6 +1459,7 @@ func runTestsData(t *testing.T, testName string, nodes Cluster, database, retent
|
|||
},
|
||||
|
||||
{
|
||||
name: `show field keys`,
|
||||
reset: true,
|
||||
write: `{"database" : "%DB%", "retentionPolicy" : "%RP%", "points": [
|
||||
{"measurement": "cpu", "tags": {"host": "server01"},"time": "2009-11-10T23:00:00Z","fields": {"field1": 100}},
|
||||
|
@ -1466,17 +1467,25 @@ func runTestsData(t *testing.T, testName string, nodes Cluster, database, retent
|
|||
{"measurement": "cpu", "tags": {"host": "server01", "region": "useast"},"time": "2009-11-10T23:00:00Z","fields": {"field1": 200, "field2": 300, "field3": 400}},
|
||||
{"measurement": "cpu", "tags": {"host": "server02", "region": "useast"},"time": "2009-11-10T23:00:00Z","fields": {"field1": 200, "field2": 300, "field3": 400}},
|
||||
{"measurement": "gpu", "tags": {"host": "server01", "region": "useast"},"time": "2009-11-10T23:00:00Z","fields": {"field4": 200, "field5": 300}},
|
||||
{"measurement": "gpu", "tags": {"host": "server03", "region": "caeast"},"time": "2009-11-10T23:00:00Z","fields": {"field6": 200, "field7": 300}}
|
||||
{"measurement": "gpu", "tags": {"host": "server03", "region": "caeast"},"time": "2009-11-10T23:00:00Z","fields": {"field6": 200, "field7": 300}},
|
||||
{"measurement": "disk", "tags": {"host": "server03", "region": "caeast"},"time": "2009-11-10T23:00:00Z","fields": {"field8": 200, "field9": 300}}
|
||||
]}`,
|
||||
query: `SHOW FIELD KEYS`,
|
||||
queryDb: "%DB%",
|
||||
expected: `{"results":[{"series":[{"name":"cpu","columns":["fieldKey"],"values":[["field1"],["field2"],["field3"]]},{"name":"gpu","columns":["fieldKey"],"values":[["field4"],["field5"],["field6"],["field7"]]}]}]}`,
|
||||
expected: `{"results":[{"series":[{"name":"cpu","columns":["fieldKey"],"values":[["field1"],["field2"],["field3"]]},{"name":"disk","columns":["fieldKey"],"values":[["field8"],["field9"]]},{"name":"gpu","columns":["fieldKey"],"values":[["field4"],["field5"],["field6"],["field7"]]}]}]}`,
|
||||
},
|
||||
{
|
||||
name: `show field keys`,
|
||||
query: `SHOW FIELD KEYS FROM cpu`,
|
||||
queryDb: "%DB%",
|
||||
expected: `{"results":[{"series":[{"name":"cpu","columns":["fieldKey"],"values":[["field1"],["field2"],["field3"]]}]}]}`,
|
||||
},
|
||||
{
|
||||
name: `show field keys`,
|
||||
query: `SHOW FIELD KEYS FROM /[cg]pu/`,
|
||||
queryDb: "%DB%",
|
||||
expected: `{"results":[{"series":[{"name":"cpu","columns":["fieldKey"],"values":[["field1"],["field2"],["field3"]]},{"name":"gpu","columns":["fieldKey"],"values":[["field4"],["field5"],["field6"],["field7"]]}]}]}`,
|
||||
},
|
||||
|
||||
// Database control tests
|
||||
{
|
||||
|
|
|
@ -1817,8 +1817,8 @@ func (s *ShowUsersStatement) RequiredPrivileges() ExecutionPrivileges {
|
|||
|
||||
// ShowFieldKeysStatement represents a command for listing field keys.
|
||||
type ShowFieldKeysStatement struct {
|
||||
// Data source that fields are extracted from.
|
||||
Source Source
|
||||
// Data sources that fields are extracted from.
|
||||
Sources Sources
|
||||
|
||||
// Fields to sort results by
|
||||
SortFields SortFields
|
||||
|
@ -1836,9 +1836,9 @@ func (s *ShowFieldKeysStatement) String() string {
|
|||
var buf bytes.Buffer
|
||||
_, _ = buf.WriteString("SHOW FIELD KEYS")
|
||||
|
||||
if s.Source != nil {
|
||||
if s.Sources != nil {
|
||||
_, _ = buf.WriteString(" FROM ")
|
||||
_, _ = buf.WriteString(s.Source.String())
|
||||
_, _ = buf.WriteString(s.Sources.String())
|
||||
}
|
||||
if len(s.SortFields) > 0 {
|
||||
_, _ = buf.WriteString(" ORDER BY ")
|
||||
|
@ -2364,6 +2364,10 @@ func Walk(v Visitor, node Node) {
|
|||
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)
|
||||
|
|
|
@ -977,7 +977,7 @@ func (p *Parser) parseShowFieldKeysStatement() (*ShowFieldKeysStatement, error)
|
|||
|
||||
// Parse optional source.
|
||||
if tok, _, _ := p.scanIgnoreWhitespace(); tok == FROM {
|
||||
if stmt.Source, err = p.parseSource(); err != nil {
|
||||
if stmt.Sources, err = p.parseSources(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -371,7 +371,8 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
IsRawQuery: true,
|
||||
Fields: []*influxql.Field{{Expr: &influxql.Wildcard{}}},
|
||||
Sources: []influxql.Source{&influxql.Measurement{
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}}},
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -384,7 +385,8 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
Sources: []influxql.Source{&influxql.Measurement{
|
||||
Database: `db`,
|
||||
RetentionPolicy: `rp`,
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}}},
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -396,7 +398,8 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
Fields: []*influxql.Field{{Expr: &influxql.Wildcard{}}},
|
||||
Sources: []influxql.Source{&influxql.Measurement{
|
||||
Database: `db`,
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}}},
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -408,7 +411,8 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
Fields: []*influxql.Field{{Expr: &influxql.Wildcard{}}},
|
||||
Sources: []influxql.Source{&influxql.Measurement{
|
||||
RetentionPolicy: `rp`,
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}}},
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile("cpu.*")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -751,7 +755,7 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
{
|
||||
s: `SHOW FIELD KEYS FROM src ORDER BY ASC, field1, field2 DESC LIMIT 10`,
|
||||
stmt: &influxql.ShowFieldKeysStatement{
|
||||
Source: &influxql.Measurement{Name: "src"},
|
||||
Sources: influxql.Sources{&influxql.Measurement{Name: "src"}},
|
||||
SortFields: []*influxql.SortField{
|
||||
{Ascending: true},
|
||||
{Name: "field1"},
|
||||
|
@ -760,6 +764,16 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
Limit: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
s: `SHOW FIELD KEYS FROM /[cg]pu/`,
|
||||
stmt: &influxql.ShowFieldKeysStatement{
|
||||
Sources: influxql.Sources{
|
||||
&influxql.Measurement{
|
||||
Regex: &influxql.RegexLiteral{Val: regexp.MustCompile(`[cg]pu`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// DROP SERIES statement
|
||||
{
|
||||
|
|
40
server.go
40
server.go
|
@ -2987,8 +2987,13 @@ func (s *Server) executeShowFieldKeysStatement(stmt *influxql.ShowFieldKeysState
|
|||
return &Result{Err: ErrDatabaseNotFound(database)}
|
||||
}
|
||||
|
||||
// Get the list of measurements we're interested in.
|
||||
measurements, err := measurementsFromSourceOrDB(stmt.Source, db)
|
||||
// Expand regex expressions in the FROM clause.
|
||||
sources, err := s.expandSources(stmt.Sources)
|
||||
if err != nil {
|
||||
return &Result{Err: err}
|
||||
}
|
||||
|
||||
measurements, err := measurementsFromSourcesOrDB(db, sources...)
|
||||
if err != nil {
|
||||
return &Result{Err: err}
|
||||
}
|
||||
|
@ -3034,36 +3039,6 @@ func (s *Server) executeRevokeStatement(stmt *influxql.RevokeStatement, user *Us
|
|||
return &Result{Err: s.SetPrivilege(influxql.NoPrivileges, stmt.User, stmt.On)}
|
||||
}
|
||||
|
||||
// measurementsFromSourceOrDB returns a list of measurements from the
|
||||
// statement passed in or, if the statement is nil, a list of all
|
||||
// measurement names from the database passed in.
|
||||
func measurementsFromSourceOrDB(stmt influxql.Source, db *database) (Measurements, error) {
|
||||
var measurements Measurements
|
||||
if stmt != nil {
|
||||
// TODO: handle multiple measurement sources
|
||||
if m, ok := stmt.(*influxql.Measurement); ok {
|
||||
measurement := db.measurements[m.Name]
|
||||
if measurement == nil {
|
||||
return nil, ErrMeasurementNotFound(m.Name)
|
||||
}
|
||||
|
||||
measurements = append(measurements, measurement)
|
||||
} else {
|
||||
return nil, errors.New("identifiers in FROM clause must be measurement names")
|
||||
}
|
||||
} else {
|
||||
// No measurements specified in FROM clause so get all measurements that have series.
|
||||
for _, m := range db.Measurements() {
|
||||
if len(m.seriesIDs) > 0 {
|
||||
measurements = append(measurements, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Sort(measurements)
|
||||
|
||||
return measurements, nil
|
||||
}
|
||||
|
||||
// measurementsFromSourcesOrDB returns a list of measurements from the
|
||||
// sources passed in or, if sources is empty, a list of all
|
||||
// measurement names from the database passed in.
|
||||
|
@ -3305,7 +3280,6 @@ func (s *Server) NormalizeStatement(stmt influxql.Statement, defaultDatabase str
|
|||
func (s *Server) normalizeStatement(stmt influxql.Statement, defaultDatabase string) (err error) {
|
||||
// Track prefixes for replacing field names.
|
||||
prefixes := make(map[string]string)
|
||||
|
||||
// Qualify all measurements.
|
||||
influxql.WalkFunc(stmt, func(n influxql.Node) {
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue