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

[CALCITE-6198] Add TO_TIMESTAMP_LTZ function (enabled in Snowflake li… #3631

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tanclary
Copy link
Contributor

…brary)

@JiajunBernoulli
Copy link
Contributor

@mihaibudiu
Copy link
Contributor

Seems that the "Error Prone" check is unhappy.

@@ -1610,6 +1610,36 @@ private static RelDataType deriveTypeMapFromEntries(SqlOperatorBinding opBinding
OperandTypes.STRING_STRING,
SqlFunctionCategory.TIMEDATE);

/** The "TO_TIMESTAMP_LTZ" function returns a Calcite
Copy link
Contributor

Choose a reason for hiding this comment

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

It's worth spelling out that a TIMESTAMP WITH LOCAL TIME ZONE is stored as millis since UTC epoch.

Describe which time zone is used for conversion from DATE and TIMESTAMP.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

* <ul>
* <li>{@code TO_TIMESTAMP_LTZ(numeric[, scale)]}
* <li>{@code TO_TIMESTAMP_LTZ(date)}
* <li>{@code TO_TIMESTAMP_LTZ(datetime)}
Copy link
Contributor

Choose a reason for hiding this comment

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

datetime is not a Calcite type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -2746,7 +2746,7 @@ In the following:
| h s | FORMAT_NUMBER(value, decimalVal) | Formats the number *value* like '#,###,###.##', rounded to decimal places *decimalVal*. If *decimalVal* is 0, the result has no decimal point or fractional part
| h s | FORMAT_NUMBER(value, format) | Formats the number *value* to MySQL's FORMAT *format*, like '#,###,###.##0.00'
| b | FORMAT_TIME(string, time) | Formats *time* according to the specified format *string*
| b | FORMAT_TIMESTAMP(string timestamp) | Formats *timestamp* according to the specified format *string*
| b | FORMAT_TIMESTAMP(string, timestamp) | Formats *timestamp* according to the specified format *string*
Copy link
Contributor

Choose a reason for hiding this comment

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

remove space before bar

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -457,6 +457,9 @@ public enum SqlKind {
/** {@code TIME_SUB} function (BigQuery). */
TIME_SUB,

/** {@code TIMESTAMP} function (BigQuery). */
TIMESTAMP,
Copy link
Contributor

Choose a reason for hiding this comment

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

not a good name, since TIMESTAMP is a type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, didn't need to add that anyways I don't think.

return timestamp(timestamp);
}

/** SQL {@code TO_TIMESTAMP_LTZ(timestamp)} function
Copy link
Contributor

Choose a reason for hiding this comment

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

be explicit what the argument means. millis since local epoch? millis since UTC epoch?

using 'timestamp' in the function name would by default mean a Calcite timestamp, i.e. ltz. But then the function would be a no-op.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was under the impression a Calcite TIMESTAMP did not have a LTZ but TIMESTAMP WITH LOCAL TIME ZONE did. So if you provide the function a Calcite TIMESTAMP it would return a TIMESTAMP WITH LOCAL TIME ZONE (not a no-op).

/** SQL {@code TO_TIMESTAMP_LTZ(date)} function
* for a date values. */
public static long toTimestampLtzDate(int days) {
return timestamp(days);
Copy link
Contributor

Choose a reason for hiding this comment

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

having overloaded timestamp(int) and timestamp(long) functions with different semantics is error-prone

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I just was not sure how else to handle the fact that you can provide the function a DATE which gets converted to an int or you can provide the function with a numeric value (which could be a long).

@@ -2480,6 +2484,32 @@ private static class RegexpReplaceImplementor extends AbstractRexCallImplementor
}
}

/** Implementor for the {@code TO_TIMESTAMP_LTZ} function. */
Copy link
Contributor

Choose a reason for hiding this comment

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

is an implementor necessary? it would be better if calls to TO_TIMESTAMP_LTZ were translated to existing functions. Then we would not need new methods in SqlFunctions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The main reason I added the implementor was to avoid the "error proneness" you mentioned in your above comment. It checks the type of the first argument (i.e. DATE, TIMESTAMP, etc.) to ensure it does not call the wrong method via reflection.

Before I added the implementor, when I was trying to use TO_TIMESTAMP_LTZ(numeric), it would end up using the method for DATE arguments since dates are represented as integers. This way, that confusion is avoided.

}

/** SQL {@code TO_TIMESTAMP_LTZ(timestampSeconds, scale)}
* function for long values with a specified scale. */
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add examples? Does toTimestampLtz(86_400L, 0) mean TIMESTAMP '1970-01-02 00:00:00'?

What would toTimestampLtz(86_400L, 3) mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a longer comment that explains the scale parameter better. Added an example too. Let me know what you think.

Copy link

sonarcloud bot commented Jan 19, 2024

Quality Gate Passed Quality Gate passed

The SonarCloud Quality Gate passed, but some issues were introduced.

4 New issues
0 Security Hotspots
100.0% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarCloud

f.checkScalar("to_timestamp_ltz(12345689.123, 2)",
"1970-01-02 10:17:36",
"TIMESTAMP_WITH_LOCAL_TIME_ZONE(0) NOT NULL");
f.checkNull("to_timestamp_ltz(null, 2)");
Copy link
Member

Choose a reason for hiding this comment

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

Hello,to_timestamp_ltz(null, null) will report an error?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants