Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

builtins: add CURRENT_TIME functionality #42928

Merged
merged 1 commit into from
Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/generated/sql/bnf/stmt_block.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,7 @@ func_expr_common_subexpr ::=
| 'CURRENT_SCHEMA'
| 'CURRENT_CATALOG'
| 'CURRENT_TIMESTAMP'
| 'CURRENT_TIME'
| 'CURRENT_USER'
| 'CURRENT_ROLE'
| 'SESSION_USER'
Expand Down Expand Up @@ -2310,6 +2311,8 @@ special_function ::=
| 'CURRENT_SCHEMA' '(' ')'
| 'CURRENT_TIMESTAMP' '(' ')'
| 'CURRENT_TIMESTAMP' '(' a_expr ')'
| 'CURRENT_TIME' '(' ')'
| 'CURRENT_TIME' '(' a_expr ')'
| 'CURRENT_USER' '(' ')'
| 'EXTRACT' '(' extract_list ')'
| 'EXTRACT_DURATION' '(' extract_list ')'
Expand Down
15 changes: 15 additions & 0 deletions docs/generated/sql/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,21 @@ SELECT * FROM crdb_internal.check_consistency(true, ‘\x02’, ‘\x04’)</p>
</span></td></tr></tbody>
</table>

### TIMETZ functions

<table>
<thead><tr><th>Function &rarr; Returns</th><th>Description</th></tr></thead>
<tbody>
<tr><td><a name="current_time"></a><code>current_time() &rarr; <a href="time.html">time</a></code></td><td><span class="funcdesc"><p>Returns the current transaction’s time with no time zone.</p>
</span></td></tr>
<tr><td><a name="current_time"></a><code>current_time() &rarr; timetz</code></td><td><span class="funcdesc"><p>Returns the current transaction’s time with time zone.</p>
</span></td></tr>
<tr><td><a name="current_time"></a><code>current_time(precision: <a href="int.html">int</a>) &rarr; <a href="time.html">time</a></code></td><td><span class="funcdesc"><p>Returns the current transaction’s time with no time zone.</p>
</span></td></tr>
<tr><td><a name="current_time"></a><code>current_time(precision: <a href="int.html">int</a>) &rarr; timetz</code></td><td><span class="funcdesc"><p>Returns the current transaction’s time with time zone.</p>
</span></td></tr></tbody>
</table>

### TUPLE functions

<table>
Expand Down
1 change: 0 additions & 1 deletion pkg/cmd/roachtest/hibernate_blacklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ var hibernateBlacklists = blacklistsForVersion{
// After a failed run, an updated version of this blacklist should be available
// in the test log.
var hibernateBlackList20_1 = blacklist{
"org.hibernate.jpa.test.criteria.QueryBuilderTest.testDateTimeFunctions": "31708",
"org.hibernate.jpa.test.criteria.basic.PredicateTest.testQuotientConversion": "26732",
"org.hibernate.jpa.test.lock.LockTest.testFindWithTimeoutHint": "40476",
"org.hibernate.jpa.test.lock.LockTest.testUpdateWithPessimisticReadLockSkipLocked": "40476",
Expand Down
48 changes: 48 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/time
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,51 @@ query T
SELECT '2001-01-01 01:24:00'::time
----
0000-01-01 01:24:00 +0000 UTC

subtest current_time_tests

statement ok
CREATE TABLE current_time_test (
id INTEGER PRIMARY KEY,
a TIME(3) DEFAULT CURRENT_TIME,
b TIME DEFAULT CURRENT_TIME
)

statement ok
INSERT INTO current_time_test (id) VALUES (1)

statement ok
INSERT INTO current_time_test (id, a, b) VALUES
(2, current_time, current_time),
(3, current_time, current_time(3))

query I
SELECT id FROM current_time_test WHERE
('1970-01-01 ' || b::string)::timestamp -
('1970-01-01 ' || a::string)::timestamp
> '1ms'::interval ORDER BY id ASC
----

# test that current_time is correct in different timezones.

statement ok
set time zone +3

statement ok
create table current_time_tzset_test (id integer, a time, b time)

statement ok
insert into current_time_tzset_test (id, a) values (1, current_time)

statement ok
set time zone 0

statement ok
update current_time_tzset_test set b = current_time

# a was written at an interval 3 hours ahead, and should persist that way.
# make sure they're roughly 3 hours apart.
query I
select id from current_time_tzset_test WHERE interval '2h59m' < a - b and a - b < interval '3h'
----
1
45 changes: 45 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/timetz
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,51 @@ SELECT '2001-01-01 11:00+04:00'::timestamptz::timetz
statement ok
SET TIME ZONE UTC

subtest current_time_tests

# current_time cannot be subtracted, but can as a timestamp.
query B
select
('1970-01-01 ' || current_time(3)::string)::timestamp -
('1970-01-01 ' || current_time::string)::timestamp
<= '1ms'::interval
----
true

statement ok
CREATE TABLE current_time_test (
id INTEGER PRIMARY KEY,
a TIMETZ(3) DEFAULT CURRENT_TIME,
b TIMETZ DEFAULT CURRENT_TIME
)

statement ok
INSERT INTO current_time_test (id) VALUES (1)

statement ok
INSERT INTO current_time_test (id, a, b) VALUES
(2, current_time, current_time),
(3, current_time, current_time(3))

query I
SELECT id FROM current_time_test WHERE
('1970-01-01 ' || b::string)::timestamp -
('1970-01-01 ' || a::string)::timestamp
> '1ms'::interval ORDER BY id ASC
----

# switching timezones should make current_time() change timezones too.
statement ok
set time zone +4

query B
select current_time() + current_timestamp()::date = current_timestamp()
----
true

statement ok
set time zone UTC

subtest precision_tests

query error precision 7 out of range
Expand Down
6 changes: 4 additions & 2 deletions pkg/sql/parser/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,10 @@ func TestParse2(t *testing.T) {
`SELECT current_timestamp()`},
{`SELECT current_timestamp(6)`,
`SELECT current_timestamp(6)`},
{`SELECT CURRENT_TIME`,
`SELECT current_time()`},
{`SELECT current_time(6)`,
`SELECT current_time(6)`},
{`SELECT CURRENT_DATE`,
`SELECT current_date()`},
{`SELECT POSITION(a IN b)`,
Expand Down Expand Up @@ -3144,8 +3148,6 @@ func TestUnimplementedSyntax(t *testing.T) {
{`SELECT GROUPING (a,b,c)`, 0, `d_expr grouping`},
{`SELECT a(VARIADIC b)`, 0, `variadic`},
{`SELECT a(b, c, VARIADIC b)`, 0, `variadic`},
{`SELECT CURRENT_TIME`, 26097, `current_time`},
{`SELECT CURRENT_TIME()`, 26097, `current_time`},
{`SELECT TREAT (a AS INT8)`, 0, `treat`},
{`SELECT a(b) WITHIN GROUP (ORDER BY c)`, 0, `within group`},

Expand Down
8 changes: 6 additions & 2 deletions pkg/sql/parser/sql.y
Original file line number Diff line number Diff line change
Expand Up @@ -8201,7 +8201,7 @@ func_expr_common_subexpr:
}
| CURRENT_TIME
{
return unimplementedWithIssueDetail(sqllex, 26097, "current_time")
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_USER
{
Expand Down Expand Up @@ -8285,7 +8285,11 @@ special_function:
| CURRENT_TIMESTAMP '(' error { return helpWithFunctionByName(sqllex, $1) }
| CURRENT_TIME '(' ')'
{
return unimplementedWithIssueDetail(sqllex, 26097, "current_time")
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_TIME '(' a_expr ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1), Exprs: tree.Exprs{$3.expr()}}
}
| CURRENT_TIME '(' error { return helpWithFunctionByName(sqllex, $1) }
| CURRENT_USER '(' ')'
Expand Down
47 changes: 46 additions & 1 deletion pkg/sql/sem/builtins/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -1674,7 +1674,52 @@ CockroachDB supports the following flags:
},
),

"now": txnTSImpl,
"now": txnTSImpl,
"current_time": makeBuiltin(
tree.FunctionProperties{Impure: true},
tree.Overload{
Types: tree.ArgTypes{},
ReturnType: tree.FixedReturnType(types.TimeTZ),
PreferredOverload: true,
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
return ctx.GetTxnTime(time.Microsecond), nil
},
Info: "Returns the current transaction's time with time zone.",
},
tree.Overload{
Types: tree.ArgTypes{},
ReturnType: tree.FixedReturnType(types.Time),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
return ctx.GetTxnTimeNoZone(time.Microsecond), nil
},
Info: "Returns the current transaction's time with no time zone.",
},
tree.Overload{
Types: tree.ArgTypes{{"precision", types.Int}},
ReturnType: tree.FixedReturnType(types.TimeTZ),
PreferredOverload: true,
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
prec := int32(tree.MustBeDInt(args[0]))
if prec < 0 || prec > 6 {
return nil, pgerror.Newf(pgcode.NumericValueOutOfRange, "precision %d out of range", prec)
}
return ctx.GetTxnTime(tree.TimeFamilyPrecisionToRoundDuration(prec)), nil
},
Info: "Returns the current transaction's time with time zone.",
},
tree.Overload{
Types: tree.ArgTypes{{"precision", types.Int}},
ReturnType: tree.FixedReturnType(types.Time),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
prec := int32(tree.MustBeDInt(args[0]))
if prec < 0 || prec > 6 {
return nil, pgerror.Newf(pgcode.NumericValueOutOfRange, "precision %d out of range", prec)
}
return ctx.GetTxnTimeNoZone(tree.TimeFamilyPrecisionToRoundDuration(prec)), nil
},
Info: "Returns the current transaction's time with no time zone.",
},
),
"current_timestamp": txnTSWithPrecisionImpl,
"transaction_timestamp": txnTSImpl,

Expand Down
22 changes: 22 additions & 0 deletions pkg/sql/sem/tree/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2946,6 +2946,28 @@ func (ctx *EvalContext) GetTxnTimestampNoZone(precision time.Duration) *DTimesta
return MakeDTimestamp(ctx.TxnTimestamp, precision)
}

// GetTxnTime retrieves the current transaction time as per
// the evaluation context.
func (ctx *EvalContext) GetTxnTime(precision time.Duration) *DTimeTZ {
// TODO(knz): a zero timestamp should never be read, even during
// Prepare. This will need to be addressed.
if !ctx.PrepareOnly && ctx.TxnTimestamp.IsZero() {
panic(errors.AssertionFailedf("zero transaction timestamp in EvalContext"))
}
return NewDTimeTZFromTime(ctx.GetRelativeParseTime().Round(precision))
}

// GetTxnTimeNoZone retrieves the current transaction time as per
// the evaluation context.
func (ctx *EvalContext) GetTxnTimeNoZone(precision time.Duration) *DTime {
// TODO(knz): a zero timestamp should never be read, even during
// Prepare. This will need to be addressed.
if !ctx.PrepareOnly && ctx.TxnTimestamp.IsZero() {
panic(errors.AssertionFailedf("zero transaction timestamp in EvalContext"))
}
return MakeDTime(timeofday.FromTime(ctx.GetRelativeParseTime().Round(precision)))
}

// SetTxnTimestamp sets the corresponding timestamp in the EvalContext.
func (ctx *EvalContext) SetTxnTimestamp(ts time.Time) {
ctx.TxnTimestamp = ts
Expand Down