Skip to content

Commit

Permalink
Merge #64887
Browse files Browse the repository at this point in the history
64887: add generate_series for timestampTZ values r=RaduBerinde a=oeph

This change adds `generate_series(timestamptz, timestamptz, interval)` as it is also supported by postgres

Fixes #64850

Co-authored-by: oeph <me@philippoeh.me>
  • Loading branch information
craig[bot] and oeph committed May 8, 2021
2 parents d302ba8 + 723ded9 commit 704e841
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/generated/sql/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,8 @@ the locality flag on node startup. Returns an error if no region is set.</p>
</span></td></tr>
<tr><td><a name="generate_series"></a><code>generate_series(start: <a href="timestamp.html">timestamp</a>, end: <a href="timestamp.html">timestamp</a>, step: <a href="interval.html">interval</a>) &rarr; <a href="timestamp.html">timestamp</a></code></td><td><span class="funcdesc"><p>Produces a virtual table containing the timestamp values from <code>start</code> to <code>end</code>, inclusive, by increment of <code>step</code>.</p>
</span></td></tr>
<tr><td><a name="generate_series"></a><code>generate_series(start: <a href="timestamp.html">timestamptz</a>, end: <a href="timestamp.html">timestamptz</a>, step: <a href="interval.html">interval</a>) &rarr; <a href="timestamp.html">timestamptz</a></code></td><td><span class="funcdesc"><p>Produces a virtual table containing the timestampTZ values from <code>start</code> to <code>end</code>, inclusive, by increment of <code>step</code>.</p>
</span></td></tr>
<tr><td><a name="generate_subscripts"></a><code>generate_subscripts(array: anyelement[]) &rarr; <a href="int.html">int</a></code></td><td><span class="funcdesc"><p>Returns a series comprising the given array’s subscripts.</p>
</span></td></tr>
<tr><td><a name="generate_subscripts"></a><code>generate_subscripts(array: anyelement[], dim: <a href="int.html">int</a>) &rarr; <a href="int.html">int</a></code></td><td><span class="funcdesc"><p>Returns a series comprising the given array’s subscripts.</p>
Expand Down
78 changes: 78 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/builtin_function
Original file line number Diff line number Diff line change
Expand Up @@ -3004,3 +3004,81 @@ query B
SELECT * FROM crdb_internal.set_trace_verbose(0, false)
WHERE false
----

# set timezone to something other then UTC
statement ok
SET timezone = 'Europe/Berlin'

query T
select generate_series('2021-07-05'::timestamptz, '2021-07-06'::timestamptz, '1day'::interval)
----
2021-07-05 00:00:00 +0200 CEST
2021-07-06 00:00:00 +0200 CEST

statement ok
SET TIME ZONE +0

statement ok
set timezone = 'Europe/Bucharest';

# the following two queries should provide the same output
query T
select '2020-10-25 00:00'::TIMESTAMPTZ + (i::text || ' hour')::interval from generate_series(0, 24) AS g(i);
----
2020-10-25 00:00:00 +0300 EEST
2020-10-25 01:00:00 +0300 EEST
2020-10-25 02:00:00 +0300 EEST
2020-10-25 03:00:00 +0300 EEST
2020-10-25 03:00:00 +0200 EET
2020-10-25 04:00:00 +0200 EET
2020-10-25 05:00:00 +0200 EET
2020-10-25 06:00:00 +0200 EET
2020-10-25 07:00:00 +0200 EET
2020-10-25 08:00:00 +0200 EET
2020-10-25 09:00:00 +0200 EET
2020-10-25 10:00:00 +0200 EET
2020-10-25 11:00:00 +0200 EET
2020-10-25 12:00:00 +0200 EET
2020-10-25 13:00:00 +0200 EET
2020-10-25 14:00:00 +0200 EET
2020-10-25 15:00:00 +0200 EET
2020-10-25 16:00:00 +0200 EET
2020-10-25 17:00:00 +0200 EET
2020-10-25 18:00:00 +0200 EET
2020-10-25 19:00:00 +0200 EET
2020-10-25 20:00:00 +0200 EET
2020-10-25 21:00:00 +0200 EET
2020-10-25 22:00:00 +0200 EET
2020-10-25 23:00:00 +0200 EET

query T
select generate_series('2020-10-25 00:00'::TIMESTAMPTZ, '2020-10-25 23:00'::TIMESTAMPTZ, '1 hour');
----
2020-10-25 00:00:00 +0300 EEST
2020-10-25 01:00:00 +0300 EEST
2020-10-25 02:00:00 +0300 EEST
2020-10-25 03:00:00 +0300 EEST
2020-10-25 03:00:00 +0200 EET
2020-10-25 04:00:00 +0200 EET
2020-10-25 05:00:00 +0200 EET
2020-10-25 06:00:00 +0200 EET
2020-10-25 07:00:00 +0200 EET
2020-10-25 08:00:00 +0200 EET
2020-10-25 09:00:00 +0200 EET
2020-10-25 10:00:00 +0200 EET
2020-10-25 11:00:00 +0200 EET
2020-10-25 12:00:00 +0200 EET
2020-10-25 13:00:00 +0200 EET
2020-10-25 14:00:00 +0200 EET
2020-10-25 15:00:00 +0200 EET
2020-10-25 16:00:00 +0200 EET
2020-10-25 17:00:00 +0200 EET
2020-10-25 18:00:00 +0200 EET
2020-10-25 19:00:00 +0200 EET
2020-10-25 20:00:00 +0200 EET
2020-10-25 21:00:00 +0200 EET
2020-10-25 22:00:00 +0200 EET
2020-10-25 23:00:00 +0200 EET

statement ok
SET TIME ZONE +0
36 changes: 36 additions & 0 deletions pkg/sql/sem/builtins/generator_builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ var generators = map[string]builtinDefinition{
"Produces a virtual table containing the timestamp values from `start` to `end`, inclusive, by increment of `step`.",
tree.VolatilityImmutable,
),
makeGeneratorOverload(
tree.ArgTypes{{"start", types.TimestampTZ}, {"end", types.TimestampTZ}, {"step", types.Interval}},
seriesTSTZValueGeneratorType,
makeTSTZSeriesGenerator,
"Produces a virtual table containing the timestampTZ values from `start` to `end`, inclusive, by increment of `step`.",
tree.VolatilityImmutable,
),
),
// crdb_internal.testing_callback is a generator function intended for internal unit tests.
// You give it a name and it calls a callback that had to have been installed
Expand Down Expand Up @@ -522,6 +529,8 @@ var seriesValueGeneratorType = types.Int

var seriesTSValueGeneratorType = types.Timestamp

var seriesTSTZValueGeneratorType = types.TimestampTZ

var errStepCannotBeZero = pgerror.New(pgcode.InvalidParameterValue, "step cannot be 0")

func seriesIntNext(s *seriesValueGenerator) (bool, error) {
Expand Down Expand Up @@ -578,6 +587,14 @@ func seriesGenTSValue(s *seriesValueGenerator) (tree.Datums, error) {
return tree.Datums{ts}, nil
}

func seriesGenTSTZValue(s *seriesValueGenerator) (tree.Datums, error) {
ts, err := tree.MakeDTimestampTZ(s.value.(time.Time), time.Microsecond)
if err != nil {
return nil, err
}
return tree.Datums{ts}, nil
}

func makeSeriesGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
start := int64(tree.MustBeDInt(args[0]))
stop := int64(tree.MustBeDInt(args[1]))
Expand Down Expand Up @@ -617,6 +634,25 @@ func makeTSSeriesGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGen
}, nil
}

func makeTSTZSeriesGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
start := args[0].(*tree.DTimestampTZ).Time
stop := args[1].(*tree.DTimestampTZ).Time
step := args[2].(*tree.DInterval).Duration

if step.Compare(duration.Duration{}) == 0 {
return nil, errStepCannotBeZero
}

return &seriesValueGenerator{
origStart: start,
stop: stop,
step: step,
genType: seriesTSTZValueGeneratorType,
genValue: seriesGenTSTZValue,
next: seriesTSNext,
}, nil
}

// ResolvedType implements the tree.ValueGenerator interface.
func (s *seriesValueGenerator) ResolvedType() *types.T {
return s.genType
Expand Down

0 comments on commit 704e841

Please sign in to comment.