fix #2644: make SHOW FIELD KEYS FROM /regex/ work

pull/2649/head
David Norton 2015-05-24 07:05:42 -04:00
parent 8866c09e67
commit 0a8be47ca1
5 changed files with 46 additions and 45 deletions

View File

@ -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
{

View File

@ -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)

View File

@ -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 {

View File

@ -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
{

View File

@ -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 {