Repository navigation
Conversation
f05301a to
9972f31
Compare
9972f31 to
8079704
Compare
8df6ed4 to
85a8b03
Compare
79bf749 to
d47daba
Compare
d47daba to
d1b23d5
Compare
| class CurrentTimestampValueTest { | ||
|
|
||
| @Test | ||
| void correlationsAreEmpty() { |
There was a problem hiding this comment.
These tests feel superfluous if I am honest. I am ok with removing these test file, up to you.
There was a problem hiding this comment.
I only had them because of test gaps reported by team scale, but they are no longer needed and I replaced them with some basic tests that actually check the behaviour of the value.
| /** | ||
| * A fixed Unix epoch timestamp in milliseconds to use in current datetime value functions. | ||
| */ | ||
| FIXED_EPOCH_TIMESTAMP_MILLIS_FOR_CURRENT_DATETIME_FUNCTIONS |
There was a problem hiding this comment.
It looks like this is mainly used for testing purposes to make tests with time more deterministic, is my understanding correct?
If so, I wonder if there is a better way for doing this that does not necessitate adding a new option that could be (ab)used in prod.
There was a problem hiding this comment.
That is correct, I tried to think of other ways enable setting a fixed timestamp for testing other than options but I couldn't think of anything that is much better:
- We can add a new class
TestOnlyOptionsand introduce a new methodRelationalConnection.setTestOnlyOptionso at least it is more obvious if the option is used from test code. - We can make this a special clause in the query (something like
WITH FIXED TIMESTAMP <>), and add that to theQueryExecutionContext.
Or alternatively we can just remove this feature, if you think it doesn't buy us that much functionality (we should still be able to test everything we just won't be able to assert on the values of the timestamp column itself).
| : aggregateWindowedFunction #aggregateFunctionCall // done (supported) | ||
| | nonAggregateWindowedFunction #nonAggregateFunctionCall // done | ||
| | specificFunction #specificFunctionCall // | ||
| | datetimeValueFunction #datetimeValueFunctionCall // done |
There was a problem hiding this comment.
Is there a specific reason for moving the #dataTypeFunctionCall branch in specificFunction rule to a specific rule here?
Both representations are ok, but I find the previous representation more concise honestly. The functionCall rule is trying to define a taxonomy of functions "types", dateTime[Value]Function is an instance of specificFunction that is analogous to case and other built-in functions.
UPDATE: I think I see it, this is probably because you're resing the datetimeValueFunction parse rule to define the left part of date-time functions below.
There was a problem hiding this comment.
Yes that was the original motivation, since we can't enforce the arithmetic rules via ArithmeticValue.PhysicalOperator since all the types are just long. I am also making use of it now since datetimeValueFunction needs to create a CurrentTimestampValue with the ConstantObjectValue that corresponds to the evaluation timestamp constant.
| | functionNameKeyword | ||
| | ASCII | CURDATE | CURRENT_DATE | CURRENT_TIME | ||
| | CURRENT_TIMESTAMP | CURTIME | DATE_ADD | DATE_SUB | ||
| | ASCII | DATE_ADD | DATE_SUB |
There was a problem hiding this comment.
It is good that you removed CURRENT_TIMESTSAMP et al from here, I think this removes a source of ambiguity, (which was probably ok up until now, because we didn't support the removed functions anyway).
| * A value that evaluates to the evaluation timestamp of the current query, as the number of milliseconds since the | ||
| * Unix epoch. | ||
| * <p> | ||
| * The timestamp is not read from the system clock by this value, instead it is retrieved from the |
There was a problem hiding this comment.
Yes, I think having this value not reading the current time stamp directly from the machine is definitely the right call.
However, I do believe that we could have it read that particular timestamp constant from the constant box in the bindings instead of having a special binding. This means that the current timestamp will have a (constant) correlation that is provided by the execution context.
There was a problem hiding this comment.
This should be addressed now as mentioned in #4645 (comment)
| @Override | ||
| public Expression visitIntervalLiteral(final RelationalParser.IntervalLiteralContext ctx) { | ||
| final var intervalStringLiteralExpression = | ||
| getDelegate().getPlanGenerationContext().withDisabledLiteralProcessing(() -> visitStringLiteral(ctx.value)); |
There was a problem hiding this comment.
I hope we get to streamline this logic once we introduce a dedicated timestamp and interval types. We can discuss this later.
There was a problem hiding this comment.
Just to clarify the logic here a bit we are parsing the interval here to surface a syntax error to the user while generating the logical plan, instead of having something like IntervalValue which does the parsing on evaluation while executing the plan. I don't think the logic here will change much even when we have dedicated types if we are happy with this approach.
| public Expression visitIntervalLiteral(final RelationalParser.IntervalLiteralContext ctx) { | ||
| final var intervalStringLiteralExpression = | ||
| getDelegate().getPlanGenerationContext().withDisabledLiteralProcessing(() -> visitStringLiteral(ctx.value)); | ||
| final var intervalStringLiteralValue = |
There was a problem hiding this comment.
It looks like the ctx can have either a value or prepared parameter, in either case, I think we should strip it and create a CoV out of it.
It doesn't seem that we're handling the prepared parameter case here.
There was a problem hiding this comment.
This was a mistake in the RelationalParser, it shouldn't support prepared parameters here because I went for eagerly parsing the passed interval literals to an actual value while generating the logical plan. We do strip the parsed interval and create a CoV out of that at the end, hence why we disable the literal processing when we parse the string literal.
| private final PlanHashable.PlanHashMode planHashMode; | ||
|
|
||
| @Nonnull | ||
| private final Instant evaluationTimestamp; |
There was a problem hiding this comment.
It looks like we're always setting the evaluation timestamp which would translate to adding 8-bytes to query plan continuations.
There was a problem hiding this comment.
That is true, and I tried to change this to make it only added when it is used, but this doesn't work for SQL table functions which might be making use of CURRENT_TIMESTAMP, since at the AstNormalizer level there is no way to know what user-defined table functions are being used and to import the evaluation constants that are referenced in them (I think this is why we add all literals referenced in all temporary functions in the transaction while normalising the query as well).
📊 Metrics Diff Analysis ReportSummary
ℹ️ About this analysisThis automated analysis compares query planner metrics between the base branch and this PR. It categorizes changes into:
The last category in particular may indicate planner regressions that should be investigated. New QueriesCount of new queries by file:
|
This PR adds SQL support for the datetime value function
CURRENT_TIMESTAMPand for day-time INTERVAL literals as described in the SQL standard.
With the changes included in this PR, a following query would be possible:
This PR doesn't add dedicated TIMESTAMP or INTERVAL data types yet, which is covered by #4738, so both SQL constructs underneath return
longvalues:CURRENT_TIMESTAMPis the number of milliseconds since the Unix epoch as abigint/Type.TypeCode.LONG.bigint/Type.TypeCode.LONG, which can be negative to indicate a negative interval.The new
CURRENT_TIMESTAMPbuilt-in function and valueThe new
CURRENT_TIMESTAMPbuilt-in function added in this PR evaluates to a newCurrentTimestampValue, which always evaluates to the evaluation timestamp stored in the query'sEvalutionContext. This ensures that multiple invocations of theCURRENT_TIMESTAMPfunction in a single query return the same value, and that a continued query is continued with the same evaluation timestamp. The evaluation timestamp is derived from the system clock (truncated to milliseconds) while normalizing the query, unless the connection optionFIXED_EPOCH_TIMESTAMP_MILLIS_FOR_CURRENT_DATETIME_FUNCTIONSis set with a fixed timestamp to use for all current datetime value functions.The
CURRENT_TIMESTAMPfunction can also be used inINSERTqueries, and they will insert the same value for all records inserted in a single query.Interval literals
Interval literals are parsed during query parsing time (which means that interval literals can't use prepared statement parameters such as
INTERVAL ? DAY TO SECOND). The parsing is done according to SQL standard rules, as detailed here, and only day-time intervals (i.e.INTERVAL ... DAY TO SECOND) are currently supported. New SQL error codes are added to handle different cases of invalid interval literals:INVALID_INTERVAL_FORMAT(22006) andINTERVAL_FIELD_OVERFLOW(22015). See the tests added inParseHelpersTest.javafor some test-cases outlining how the parsing works.Queries with day-time interval literals are canonicalized to
SELECT .... INTERVAL ? DAY TO SECONDbefore the plans are stored in the plan cache, and the parsed interval literal string is stored as a scalar literal. SeeAstNormalizerTests.javafor tests that confirm this normalization works as expected.Supported operations involving interval literals and datetime value functions
It is possible to add or subtract an interval from the return value of a date-time value function as shown in the example above, the current operations are supported:
CURRENT_TIMESTAMP- | +INTERVALINTERVAL+CURRENT_TIMESTAMPThese rules are encoded in the grammar defined in
RelationalParser.g4as the new ruledatetimeIntervalMathExpression.Documentation
The SQL docs are intentionally not updated in this PR, and they will be updated once dedicated data types for TIMESTAMP and INTERVAL values exist, which is tracked in #4738.