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

Rework on now function implementation #113

Merged
merged 11 commits into from
Sep 15, 2022

Conversation

Yury-Fridlyand
Copy link

Description

Address opensearch-project#754 feedback link

Issues Resolved

now function value is calculated on AST analysis stage in ExpressionAnalyzer and value is cached in AnalysisContext. This happens with all synonyms of now too.

Limitations

Value of now was calculated in 2 stages: (1) get value, (2) format it. ExpressionAnalyzer is not capable of caching intermediate value and it shouldn't be overloaded by now function logic, so I have to remove formatting stage. now (and all synonyms) don't accept anymore fsp argument which describes formatting. Otherwise AnalysisContext stores different resulting values for now(), now(6) and now(0), which are different in scope of a query - that is incorrect.

Check List

  • New functionality includes testing.
    • All tests pass, including unit test, integration test and doctest
  • New functionality has been documented.
    • New functionality has javadoc added
    • New functionality has user manual doc added
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Signed-off-by: Yury-Fridlyand <[email protected]>
Signed-off-by: Yury-Fridlyand <[email protected]>
Signed-off-by: Yury-Fridlyand <[email protected]>
Signed-off-by: Yury-Fridlyand <[email protected]>
@Yury-Fridlyand
Copy link
Author

@penghuo, please, have a look on the proposed changes. If everything is OK, it will be merged into PR opensearch-project#754's branch and update it.

impl(() -> new ExprDatetimeValue(now((Integer)null)), DATETIME),
impl((v) -> new ExprDatetimeValue(now(v.integerValue())), DATETIME, INTEGER)
impl(() -> new ExprDatetimeValue(formatNow(null)), DATETIME)
//impl((v) -> new ExprDatetimeValue(formatNow(v.integerValue())), DATETIME, INTEGER)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remove the comment.

impl(() -> new ExprTimeValue(sysDate(null).toLocalTime()), TIME),
impl((v) -> new ExprTimeValue(sysDate(v.integerValue()).toLocalTime()), TIME, INTEGER)
impl(() -> new ExprTimeValue(formatNow(null).toLocalTime()), TIME)
//impl((v) -> new ExprTimeValue(formatNow(v.integerValue()).toLocalTime()), TIME, INTEGER)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably remove the comment.

+----------------------------+---------------------+
+----------------------------+----------------------------+
| value_1 | value_2 |
|----------------------------+----------------------------+

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be a vertical pipe (|) at the end of this line instead of +

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right! We don't have doctests running for these functions to validate.

| TIMESTAMP | TO_DAYS | YEAR | WEEK | DATE_FORMAT | NOW | CURDATE | CURRENT_DATE | CURTIME | CURRENT_TIME
| LOCALTIME | CURRENT_TIMESTAMP | LOCALTIMESTAMP | SYSDATE | UTC_TIMESTAMP | UTC_DATE | UTC_TIME
| MAKETIME | MAKEDATE
| TIMESTAMP | TO_DAYS | YEAR | WEEK | DATE_FORMAT | SYSDATE | MAKETIME | MAKEDATE

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add these functions in alphabetical order to remain consistent.

| TIMESTAMP | TO_DAYS | YEAR | WEEK | DATE_FORMAT | NOW | CURDATE | CURRENT_DATE | CURTIME | CURRENT_TIME
| LOCALTIME | CURRENT_TIMESTAMP | LOCALTIMESTAMP | SYSDATE | UTC_TIMESTAMP | UTC_DATE | UTC_TIME
| MAKETIME | MAKEDATE
| TIMESTAMP | TO_DAYS | YEAR | WEEK | DATE_FORMAT | SYSDATE | MAKETIME | MAKEDATE

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put in alphabetical order.

@Yury-Fridlyand Yury-Fridlyand changed the title Rework on now function implementation Rework on now function implementation Sep 6, 2022
@Bit-Quill Bit-Quill deleted a comment from codecov bot Sep 8, 2022
/**
* Storage for values of functions which return a constant value.
* We are storing the values there to use it in sequential calls to those functions.
* For example, `now` function should the same value during processing a query.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Constant" suggests that the return value is hard-coded.
I would re-word this as a cache for function return values.
Maybe something like functionToExpressionCache.
Note: It would be more useful if we could include arguments in the key, then we could use this cache to calculate and cache function calls with different arguments.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to rename it.

Regarding arguments - they are already included, but now function (and all synonyms) doesn't accept argument anymore. Otherwise there is bug, when now() and now(6) have different values, because were calculated twice, because they can't cross-use cached value.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. No arguments on now is fine.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming done in ce2e8bf.

@codecov

This comment was marked as spam.

@Override
public Expression visitFunctionWithCachedValue(FunctionWithCachedValue node,
AnalysisContext context) {
var valueName = node.toString();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's sufficient to use node.getFuncName here.

toString is not a great option to generate a hashmap key. All it guarantees is that the result is a string -- intended for logging and debugging. There is no requirement that it's unique for different object.

In the case of Function object, it happens to include name and parameters making it ok as a key but it would be just as valid for Function.toString to return "An unresolved function expression" or "Function object 0xDEADBEEF"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, fixed in 4008c75.

* [1] Constant at execution time.
*/
@EqualsAndHashCode(callSuper = false)
public class FunctionWithCachedValue extends Function {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are called constant functions in math.
ConstantFunction or ConstantValueFunction better explain what's special in this case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, renamed in 6ef778d.

@@ -307,6 +307,11 @@ functionCall
| aggregateFunction (orderByClause)? filterClause #filteredAggregationFunctionCall
| relevanceFunction #relevanceFunctionCall
| highlightFunction #highlightFunctionCall
| functionWithCachedValue #functionLikeConstantCall

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be cleaner if #functionLikeConstantCall matched the rule name.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, renamed in 6ef778d.

| functionWithCachedValue #functionLikeConstantCall
;

functionWithCachedValue

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constantValuedFunction or constantFunction are more appropriate names for this rule.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, renamed in 6ef778d.

Signed-off-by: Yury-Fridlyand <[email protected]>
…hedValue` to `ConstantFunction`.

Signed-off-by: Yury-Fridlyand <[email protected]>
@MitchellGale
Copy link

Unexpected result for now with number up to 6. Unsure what the standard is for warning messages for invalid inputs, but could also give a warning for values too high.

opensearchsql> select now(1);                                                                                                                                                                                                                               
{'reason': 'Invalid SQL query', 'details': 'now function expected {[]}, but get [INTEGER]', 'type': 'ExpressionEvaluationException'}

Invalid argument on now gives warning in MySQL. Should OpenSearchSQL match?

mysql> SELECT now(10);
ERROR 1426 (42000): Too-big precision 10 specified for 'now'. Maximum is 6.

@MitchellGale
Copy link

MitchellGale commented Sep 13, 2022

Results differ between current_timestamp in MySQL and OpenSearchSQL.

OpenSearchSQL:

opensearchsql> select current_timestamp();                                                                                                                                                                                                                  
fetched rows / total rows = 1/1
+----------------------------+
| current_timestamp()        |
|----------------------------|
| 2022-09-13 01:04:13.512658 |
+----------------------------+

MySQL:

+---------------------+
| current_timestamp() |
+---------------------+
| 2022-09-13 08:04:30 |
+---------------------+
1 row in set (0.00 sec)

Results differ between localtimestamp in MySQL and OpenSearchSQL.

OpenSearchSQL:

opensearchsql> select localtimestamp();                                                                                                                                                                                                                     
fetched rows / total rows = 1/1
+----------------------------+
| localtimestamp()           |
|----------------------------|
| 2022-09-13 01:06:39.647093 |
+----------------------------+

MySQL:

mysql> select localtimestamp();
+---------------------+
| localtimestamp()    |
+---------------------+
| 2022-09-13 08:07:07 |
+---------------------+
1 row in set (0.00 sec)

@Yury-Fridlyand
Copy link
Author

Unexpected result for now with number up to 6. Unsure what the standard is for warning messages for invalid inputs, but could also give a warning for values too high.

opensearchsql> select now(1);                                                                                                                                                                                                                               
{'reason': 'Invalid SQL query', 'details': 'now function expected {[]}, but get [INTEGER]', 'type': 'ExpressionEvaluationException'}

New implementation creates a cache entry for function and its arguments. There is no common cache for now() and now(6) calls - function executed twice which is completely incorrect.
I removed now(integer) signature, you can see it in DateTimeFunction.java, lines 108-115.

@Yury-Fridlyand
Copy link
Author

Results differ between current_timestamp in MySQL and OpenSearchSQL.

Nice catch! Fixed in 64ccf47.

if (fsp == null) {
return res;
fsp = 0;
}
var defaultPrecision = 9; // There are 10^9 nanoseconds in one second
if (fsp < 0 || fsp > 6) { // Check that the argument is in the allowed range [0, 6]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this if you are not having the values in now be handled?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sysdate() uses the same function under the hood and it has an argument.
Try

select sysdate(), sysdate(0), sysdate(6);

@Yury-Fridlyand Yury-Fridlyand merged commit 1e42e2b into integ-datetime-now Sep 15, 2022
@Yury-Fridlyand Yury-Fridlyand deleted the dev-datetime-now-rework branch September 15, 2022 02:20
Yury-Fridlyand added a commit that referenced this pull request Sep 15, 2022
Yury-Fridlyand added a commit that referenced this pull request Sep 24, 2022
…ions (opensearch-project#754)

* Add implementation of `now`, `sysdate`, `localtime` and similar functions (#92)

Signed-off-by: Yury-Fridlyand <[email protected]>

* Rework on `now` function implementation (#113)

Signed-off-by: Yury-Fridlyand <[email protected]>

* Minor SQL ANTLR clean-up.

Signed-off-by: Yury-Fridlyand <[email protected]>

Signed-off-by: Yury-Fridlyand <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants