diff --git a/query/iterator.gen.go b/query/iterator.gen.go index cd55fbe43e..27f8d401c0 100644 --- a/query/iterator.gen.go +++ b/query/iterator.gen.go @@ -1114,28 +1114,28 @@ func (itr *floatReduceFloatIterator) reduce() ([]FloatPoint, error) { rp.Aggregator.AggregateFloat(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]FloatPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(floatPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -1144,10 +1144,20 @@ func (itr *floatReduceFloatIterator) reduce() ([]FloatPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = floatPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -1392,28 +1402,28 @@ func (itr *floatReduceIntegerIterator) reduce() ([]IntegerPoint, error) { rp.Aggregator.AggregateFloat(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]IntegerPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(integerPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -1422,10 +1432,20 @@ func (itr *floatReduceIntegerIterator) reduce() ([]IntegerPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = integerPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -1670,28 +1690,28 @@ func (itr *floatReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { rp.Aggregator.AggregateFloat(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]UnsignedPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(unsignedPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -1700,10 +1720,20 @@ func (itr *floatReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = unsignedPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -1948,28 +1978,28 @@ func (itr *floatReduceStringIterator) reduce() ([]StringPoint, error) { rp.Aggregator.AggregateFloat(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]StringPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(stringPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -1978,10 +2008,20 @@ func (itr *floatReduceStringIterator) reduce() ([]StringPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = stringPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -2226,28 +2266,28 @@ func (itr *floatReduceBooleanIterator) reduce() ([]BooleanPoint, error) { rp.Aggregator.AggregateFloat(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]BooleanPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(booleanPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -2256,10 +2296,20 @@ func (itr *floatReduceBooleanIterator) reduce() ([]BooleanPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = booleanPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -3728,28 +3778,28 @@ func (itr *integerReduceFloatIterator) reduce() ([]FloatPoint, error) { rp.Aggregator.AggregateInteger(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]FloatPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(floatPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -3758,10 +3808,20 @@ func (itr *integerReduceFloatIterator) reduce() ([]FloatPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = floatPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -4006,28 +4066,28 @@ func (itr *integerReduceIntegerIterator) reduce() ([]IntegerPoint, error) { rp.Aggregator.AggregateInteger(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]IntegerPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(integerPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -4036,10 +4096,20 @@ func (itr *integerReduceIntegerIterator) reduce() ([]IntegerPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = integerPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -4284,28 +4354,28 @@ func (itr *integerReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { rp.Aggregator.AggregateInteger(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]UnsignedPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(unsignedPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -4314,10 +4384,20 @@ func (itr *integerReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = unsignedPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -4562,28 +4642,28 @@ func (itr *integerReduceStringIterator) reduce() ([]StringPoint, error) { rp.Aggregator.AggregateInteger(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]StringPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(stringPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -4592,10 +4672,20 @@ func (itr *integerReduceStringIterator) reduce() ([]StringPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = stringPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -4840,28 +4930,28 @@ func (itr *integerReduceBooleanIterator) reduce() ([]BooleanPoint, error) { rp.Aggregator.AggregateInteger(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]BooleanPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(booleanPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -4870,10 +4960,20 @@ func (itr *integerReduceBooleanIterator) reduce() ([]BooleanPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = booleanPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -6342,28 +6442,28 @@ func (itr *unsignedReduceFloatIterator) reduce() ([]FloatPoint, error) { rp.Aggregator.AggregateUnsigned(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]FloatPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(floatPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -6372,10 +6472,20 @@ func (itr *unsignedReduceFloatIterator) reduce() ([]FloatPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = floatPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -6620,28 +6730,28 @@ func (itr *unsignedReduceIntegerIterator) reduce() ([]IntegerPoint, error) { rp.Aggregator.AggregateUnsigned(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]IntegerPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(integerPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -6650,10 +6760,20 @@ func (itr *unsignedReduceIntegerIterator) reduce() ([]IntegerPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = integerPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -6898,28 +7018,28 @@ func (itr *unsignedReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { rp.Aggregator.AggregateUnsigned(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]UnsignedPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(unsignedPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -6928,10 +7048,20 @@ func (itr *unsignedReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = unsignedPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -7176,28 +7306,28 @@ func (itr *unsignedReduceStringIterator) reduce() ([]StringPoint, error) { rp.Aggregator.AggregateUnsigned(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]StringPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(stringPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -7206,10 +7336,20 @@ func (itr *unsignedReduceStringIterator) reduce() ([]StringPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = stringPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -7454,28 +7594,28 @@ func (itr *unsignedReduceBooleanIterator) reduce() ([]BooleanPoint, error) { rp.Aggregator.AggregateUnsigned(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]BooleanPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(booleanPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -7484,10 +7624,20 @@ func (itr *unsignedReduceBooleanIterator) reduce() ([]BooleanPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = booleanPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -8942,28 +9092,28 @@ func (itr *stringReduceFloatIterator) reduce() ([]FloatPoint, error) { rp.Aggregator.AggregateString(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]FloatPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(floatPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -8972,10 +9122,20 @@ func (itr *stringReduceFloatIterator) reduce() ([]FloatPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = floatPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -9220,28 +9380,28 @@ func (itr *stringReduceIntegerIterator) reduce() ([]IntegerPoint, error) { rp.Aggregator.AggregateString(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]IntegerPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(integerPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -9250,10 +9410,20 @@ func (itr *stringReduceIntegerIterator) reduce() ([]IntegerPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = integerPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -9498,28 +9668,28 @@ func (itr *stringReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { rp.Aggregator.AggregateString(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]UnsignedPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(unsignedPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -9528,10 +9698,20 @@ func (itr *stringReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = unsignedPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -9776,28 +9956,28 @@ func (itr *stringReduceStringIterator) reduce() ([]StringPoint, error) { rp.Aggregator.AggregateString(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]StringPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(stringPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -9806,10 +9986,20 @@ func (itr *stringReduceStringIterator) reduce() ([]StringPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = stringPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -10054,28 +10244,28 @@ func (itr *stringReduceBooleanIterator) reduce() ([]BooleanPoint, error) { rp.Aggregator.AggregateString(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]BooleanPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(booleanPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -10084,10 +10274,20 @@ func (itr *stringReduceBooleanIterator) reduce() ([]BooleanPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = booleanPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -11542,28 +11742,28 @@ func (itr *booleanReduceFloatIterator) reduce() ([]FloatPoint, error) { rp.Aggregator.AggregateBoolean(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]FloatPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(floatPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -11572,10 +11772,20 @@ func (itr *booleanReduceFloatIterator) reduce() ([]FloatPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = floatPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -11820,28 +12030,28 @@ func (itr *booleanReduceIntegerIterator) reduce() ([]IntegerPoint, error) { rp.Aggregator.AggregateBoolean(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]IntegerPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(integerPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -11850,10 +12060,20 @@ func (itr *booleanReduceIntegerIterator) reduce() ([]IntegerPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = integerPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -12098,28 +12318,28 @@ func (itr *booleanReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { rp.Aggregator.AggregateBoolean(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]UnsignedPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(unsignedPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -12128,10 +12348,20 @@ func (itr *booleanReduceUnsignedIterator) reduce() ([]UnsignedPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = unsignedPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -12376,28 +12606,28 @@ func (itr *booleanReduceStringIterator) reduce() ([]StringPoint, error) { rp.Aggregator.AggregateBoolean(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]StringPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(stringPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -12406,10 +12636,20 @@ func (itr *booleanReduceStringIterator) reduce() ([]StringPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = stringPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } @@ -12654,28 +12894,28 @@ func (itr *booleanReduceBooleanIterator) reduce() ([]BooleanPoint, error) { rp.Aggregator.AggregateBoolean(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]BooleanPoint, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable(booleanPointsByTime(points)) - } for i := len(points) - 1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -12684,10 +12924,20 @@ func (itr *booleanReduceBooleanIterator) reduce() ([]BooleanPoint, error) { // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = booleanPointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } diff --git a/query/iterator.gen.go.tmpl b/query/iterator.gen.go.tmpl index f3d5a98d51..e9ac8940b4 100644 --- a/query/iterator.gen.go.tmpl +++ b/query/iterator.gen.go.tmpl @@ -450,7 +450,7 @@ func (h *{{$k.name}}SortedMergeHeap) Less(i, j int) bool { } else if xTags, yTags := x.Tags.Subset(h.opt.Dimensions), y.Tags.Subset(h.opt.Dimensions); !xTags.Equals(&yTags) { return xTags.ID() > yTags.ID() } - + if x.Time != y.Time{ return x.Time > y.Time } @@ -1118,28 +1118,28 @@ func (itr *{{$k.name}}Reduce{{$v.Name}}Iterator) reduce() ([]{{$v.Name}}Point, e rp.Aggregator.Aggregate{{$k.Name}}(curr) } - // Reverse sort points by name & tag if our output is supposed to be ordered. - // This is because the final array needs to have the first - // point at the end since they are popped off of the end. keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } - if len(keys) > 1 && itr.opt.Ordered { - sort.Sort(reverseStringSlice(keys)) + + // Reverse sort points by name & tag. + // This ensures a consistent order of output. + if len(keys) > 0 { + var sorted sort.Interface = sort.StringSlice(keys) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Sort(sorted) } + // Assume the points are already sorted until proven otherwise. + sortedByTime := true // Emit the points for each name & tag combination. a := make([]{{$v.Name}}Point, 0, len(m)) for _, k := range keys { rp := m[k] points := rp.Emitter.Emit() - // If the points are meant to be ordered, - // ensure that is done here. The tags are already - // sorted and should remain sorted. - if len(points) > 1 && itr.opt.Ordered { - sort.Stable({{$v.name}}PointsByTime(points)) - } for i := len(points)-1; i >= 0; i-- { points[i].Name = rp.Name if !itr.keepTags { @@ -1148,10 +1148,20 @@ func (itr *{{$k.name}}Reduce{{$v.Name}}Iterator) reduce() ([]{{$v.Name}}Point, e // Set the points time to the interval time if the reducer didn't provide one. if points[i].Time == ZeroTime { points[i].Time = startTime + } else { + sortedByTime = false } a = append(a, points[i]) } } + // Points may be out of order. Perform a stable sort by time if requested. + if !sortedByTime && itr.opt.Ordered { + var sorted sort.Interface = {{$v.name}}PointsByTime(a) + if itr.opt.Ascending { + sorted = sort.Reverse(sorted) + } + sort.Stable(sorted) + } return a, nil } diff --git a/query/select.go b/query/select.go index 755779d62c..6fc6bfe9f4 100644 --- a/query/select.go +++ b/query/select.go @@ -587,6 +587,7 @@ func (b *exprIteratorBuilder) callIterator(ctx context.Context, expr *influxql.C // Identify the name of the field we are using. arg0 := expr.Args[0].(*influxql.VarRef) + opt.Ordered = false input, err := buildExprIterator(ctx, arg0, b.ic, []influxql.Source{source}, opt, b.selector, false) if err != nil { return err @@ -801,7 +802,7 @@ func buildAuxIterator(ctx context.Context, ic IteratorCreator, sources influxql. return nil, err } - // Merge iterators to read auxiliary fields. + // Merge iterators to read auxilary fields. input, err := Iterators(inputs).Merge(opt) if err != nil { Iterators(inputs).Close() diff --git a/query/subquery_test.go b/query/subquery_test.go index 6b02873afe..6589e524b2 100644 --- a/query/subquery_test.go +++ b/query/subquery_test.go @@ -273,6 +273,40 @@ func TestSubquery(t *testing.T) { {Time: 30 * Second, Series: query.Series{Name: "cpu"}, Values: []interface{}{float64(8)}}, }, }, + { + Name: "TimeOrderingInTheOuterQuery", + Statement: `select * from (select last(value) from cpu group by host) order by time asc`, + Fields: map[string]influxql.DataType{"value": influxql.Float}, + MapShardsFn: func(t *testing.T, tr influxql.TimeRange) CreateIteratorFn { + + return func(ctx context.Context, m *influxql.Measurement, opt query.IteratorOptions) query.Iterator { + if got, want := m.Name, "cpu"; got != want { + t.Errorf("unexpected source: got=%s want=%s", got, want) + } + + var itr query.Iterator = &FloatIterator{Points: []query.FloatPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0 * Second, Value: 2}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 10 * Second, Value: 7}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20 * Second, Value: 3}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 0 * Second, Value: 8}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 10 * Second, Value: 3}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 19 * Second, Value: 7}, + }} + if _, ok := opt.Expr.(*influxql.Call); ok { + i, err := query.NewCallIterator(itr, opt) + if err != nil { + panic(err) + } + itr = i + } + return itr + } + }, + Rows: []query.Row{ + {Time: 19 * Second, Series: query.Series{Name: "cpu"}, Values: []interface{}{"B", float64(7)}}, + {Time: 20 * Second, Series: query.Series{Name: "cpu"}, Values: []interface{}{"A", float64(3)}}, + }, + }, { Name: "TimeZone", Statement: `SELECT * FROM (SELECT * FROM cpu WHERE time >= '2019-04-17 09:00:00' and time < '2019-04-17 10:00:00' TZ('America/Chicago'))`, @@ -289,6 +323,47 @@ func TestSubquery(t *testing.T) { } }, }, + { + Name: "DifferentDimensionsOrderByDesc", + Statement: `SELECT value, mytag FROM (SELECT last(value) AS value FROM testing GROUP BY mytag) ORDER BY desc`, + Fields: map[string]influxql.DataType{"value": influxql.Float}, + MapShardsFn: func(t *testing.T, tr influxql.TimeRange) CreateIteratorFn { + return func(ctx context.Context, m *influxql.Measurement, opt query.IteratorOptions) query.Iterator { + if got, want := m.Name, "testing"; got != want { + t.Errorf("unexpected source: got=%s want=%s", got, want) + } + + if opt.Ascending { + t.Error("expected iterator to be descending, not ascending") + } + + var itr query.Iterator = &FloatIterator{Points: []query.FloatPoint{ + {Name: "testing", Tags: ParseTags("mytag=c"), Time: mustParseTime("2019-06-25T22:36:20.93605779Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=c"), Time: mustParseTime("2019-06-25T22:36:20.671604877Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=c"), Time: mustParseTime("2019-06-25T22:36:20.255794481Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=b"), Time: mustParseTime("2019-06-25T22:36:18.176662543Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=b"), Time: mustParseTime("2019-06-25T22:36:17.815979113Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=b"), Time: mustParseTime("2019-06-25T22:36:17.265031598Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=a"), Time: mustParseTime("2019-06-25T22:36:15.144253616Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=a"), Time: mustParseTime("2019-06-25T22:36:14.719167205Z").UnixNano(), Value: 2}, + {Name: "testing", Tags: ParseTags("mytag=a"), Time: mustParseTime("2019-06-25T22:36:13.711721316Z").UnixNano(), Value: 2}, + }} + if _, ok := opt.Expr.(*influxql.Call); ok { + i, err := query.NewCallIterator(itr, opt) + if err != nil { + panic(err) + } + itr = i + } + return itr + } + }, + Rows: []query.Row{ + {Time: mustParseTime("2019-06-25T22:36:20.93605779Z").UnixNano(), Series: query.Series{Name: "testing"}, Values: []interface{}{float64(2), "c"}}, + {Time: mustParseTime("2019-06-25T22:36:18.176662543Z").UnixNano(), Series: query.Series{Name: "testing"}, Values: []interface{}{float64(2), "b"}}, + {Time: mustParseTime("2019-06-25T22:36:15.144253616Z").UnixNano(), Series: query.Series{Name: "testing"}, Values: []interface{}{float64(2), "a"}}, + }, + }, } { t.Run(test.Name, func(t *testing.T) { shardMapper := ShardMapper{