-
Notifications
You must be signed in to change notification settings - Fork 7
SQL Server to Postgres Migration #7547
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
base: release26.3-SNAPSHOT
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1117,6 +1117,8 @@ public SQLFragment formatJdbcFunction(String fn, SQLFragment... arguments) | |
| return formatFunction(call, nativeFn, arguments); | ||
| else if (fn.equalsIgnoreCase("timestampdiff")) | ||
| return timestampdiff(arguments); | ||
| else if (fn.equalsIgnoreCase("timestampdiff2")) | ||
| return timestampdiff2(arguments); | ||
| else | ||
| return super.formatJdbcFunction(fn, arguments); | ||
| } | ||
|
|
@@ -1157,6 +1159,53 @@ private SQLFragment timestampdiff(SQLFragment... arguments) | |
| return super.formatJdbcFunction("timestampdiff", arguments); | ||
| } | ||
|
|
||
| /* Native PostgreSQL implementation for all 9 SQL_TSI intervals. | ||
| * This returns INTEGER for all intervals and never falls back to the JDBC escape. | ||
| * | ||
| * This was specifically created as a work around for PG JDBC parameter swapping issue. This does not use the JDBC | ||
| * timestampdiff function. | ||
| */ | ||
| private SQLFragment timestampdiff2(SQLFragment... arguments) | ||
| { | ||
| String interval = arguments[0].getSQL(); | ||
| SQLFragment start = arguments[1]; | ||
| SQLFragment end = arguments[2]; | ||
| // Compute whole elapsed months first, then derive quarter/year from that value so all larger | ||
| // intervals use the same truncation-toward-zero semantics as the epoch-based branches below. | ||
| SQLFragment wholeMonths = getWholeElapsedMonths(start, end); | ||
|
|
||
| return switch (interval) | ||
| { | ||
| case "SQL_TSI_YEAR" -> | ||
| new SQLFragment("TRUNC((").append(wholeMonths).append(")::NUMERIC / 12)::INT"); | ||
| case "SQL_TSI_QUARTER" -> | ||
| new SQLFragment("TRUNC((").append(wholeMonths).append(")::NUMERIC / 3)::INT"); | ||
| case "SQL_TSI_MONTH" -> | ||
| wholeMonths; | ||
| case "SQL_TSI_WEEK" -> | ||
| new SQLFragment("TRUNC(EXTRACT(EPOCH FROM (").append(end).append(") - (").append(start).append(")) / 604800)::INT"); | ||
| case "SQL_TSI_DAY" -> | ||
| new SQLFragment("TRUNC(EXTRACT(EPOCH FROM (").append(end).append(") - (").append(start).append(")) / 86400)::INT"); | ||
| case "SQL_TSI_HOUR" -> | ||
| new SQLFragment("TRUNC(EXTRACT(EPOCH FROM (").append(end).append(") - (").append(start).append(")) / 3600)::INT"); | ||
| case "SQL_TSI_MINUTE" -> | ||
| new SQLFragment("TRUNC(EXTRACT(EPOCH FROM (").append(end).append(") - (").append(start).append(")) / 60)::INT"); | ||
| case "SQL_TSI_SECOND" -> | ||
| new SQLFragment("TRUNC(EXTRACT(EPOCH FROM (").append(end).append(") - (").append(start).append(")))::INT"); | ||
| case "SQL_TSI_FRAC_SECOND" -> | ||
| new SQLFragment("TRUNC(EXTRACT(EPOCH FROM (").append(end).append(") - (").append(start).append(")) * 1000)::BIGINT"); | ||
| default -> throw new IllegalArgumentException("Unsupported interval for timestampdiff2: " + interval); | ||
| }; | ||
| } | ||
|
|
||
| private SQLFragment getWholeElapsedMonths(SQLFragment start, SQLFragment end) | ||
| { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method assumes that |
||
| // AGE() normalizes the symbolic year/month/day components for both positive and negative spans. | ||
| SQLFragment age = new SQLFragment("AGE((").append(end).append("), (").append(start).append("))"); | ||
| return new SQLFragment("((EXTRACT(YEAR FROM ").append(age).append(") * 12) + EXTRACT(MONTH FROM ").append(age) | ||
| .append("))::INT"); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsBatchGeneratedKeys() | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -777,6 +777,32 @@ d,seven,twelve,day,month,date,duration,guid | |
| new MethodSqlTest("SELECT CAST(TIMESTAMPDIFF(SQL_TSI_DAY, CAST('31 Jan 2004' AS TIMESTAMP), CAST('01 Jan 2003' AS TIMESTAMP)) AS INTEGER)", JdbcType.INTEGER, -395), | ||
| // NOTE: SQL_TSI_WEEK, SQL_TSI_MONTH, SQL_TSI_QUARTER, and SQL_TSI_YEAR are NYI in PostsgreSQL TIMESTAMPDIFF | ||
|
|
||
| // timestampdiff2 - native PostgreSQL implementation for all intervals, returns INTEGER | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_SECOND, CAST('01 Jan 2004 5:00' AS TIMESTAMP), CAST('01 Jan 2004 6:00' AS TIMESTAMP))", JdbcType.INTEGER, 3600), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_MINUTE, CAST('01 Jan 2003' AS TIMESTAMP), CAST('01 Jan 2004' AS TIMESTAMP))", JdbcType.INTEGER, 525600), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_MINUTE, CAST('01 Jan 2004' AS TIMESTAMP), CAST('01 Jan 2005' AS TIMESTAMP))", JdbcType.INTEGER, 527040), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_HOUR, CAST('01 Jan 2003' AS TIMESTAMP), CAST('01 Jan 2004' AS TIMESTAMP))", JdbcType.INTEGER, 8760), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_HOUR, CAST('01 Jan 2004' AS TIMESTAMP), CAST('01 Jan 2005' AS TIMESTAMP))", JdbcType.INTEGER, 8784), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_DAY, CAST('01 Jan 2003' AS TIMESTAMP), CAST('31 Jan 2004' AS TIMESTAMP))", JdbcType.INTEGER, 395), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_DAY, CAST('31 Jan 2004' AS TIMESTAMP), CAST('01 Jan 2003' AS TIMESTAMP))", JdbcType.INTEGER, -395), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_WEEK, CAST('01 Jan 2003' AS TIMESTAMP), CAST('22 Jan 2003' AS TIMESTAMP))", JdbcType.INTEGER, 3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_WEEK, CAST('22 Jan 2003' AS TIMESTAMP), CAST('01 Jan 2003' AS TIMESTAMP))", JdbcType.INTEGER, -3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_MONTH, CAST('01 Jan 2003' AS TIMESTAMP), CAST('01 Apr 2003' AS TIMESTAMP))", JdbcType.INTEGER, 3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_MONTH, CAST('01 Feb 2003 00:00' AS TIMESTAMP), CAST('31 Jan 2003 23:59' AS TIMESTAMP))", JdbcType.INTEGER, 0), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_MONTH, CAST('15 Jan 2003' AS TIMESTAMP), CAST('14 Apr 2003' AS TIMESTAMP))", JdbcType.INTEGER, 2), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_MONTH, CAST('15 Jan 2003' AS TIMESTAMP), CAST('15 Apr 2003' AS TIMESTAMP))", JdbcType.INTEGER, 3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_MONTH, CAST('15 Apr 2003' AS TIMESTAMP), CAST('14 Jan 2003' AS TIMESTAMP))", JdbcType.INTEGER, -3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_QUARTER, CAST('01 Jan 2003' AS TIMESTAMP), CAST('01 Oct 2003' AS TIMESTAMP))", JdbcType.INTEGER, 3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_QUARTER, CAST('15 Jan 2003' AS TIMESTAMP), CAST('14 Oct 2003' AS TIMESTAMP))", JdbcType.INTEGER, 2), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_QUARTER, CAST('15 Jan 2003' AS TIMESTAMP), CAST('15 Oct 2003' AS TIMESTAMP))", JdbcType.INTEGER, 3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_QUARTER, CAST('15 Oct 2003' AS TIMESTAMP), CAST('14 Jan 2003' AS TIMESTAMP))", JdbcType.INTEGER, -3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_YEAR, CAST('01 Jan 2003' AS TIMESTAMP), CAST('01 Jan 2006' AS TIMESTAMP))", JdbcType.INTEGER, 3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_YEAR, CAST('15 Jan 2003' AS TIMESTAMP), CAST('14 Jan 2006' AS TIMESTAMP))", JdbcType.INTEGER, 2), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_YEAR, CAST('15 Jan 2003' AS TIMESTAMP), CAST('15 Jan 2006' AS TIMESTAMP))", JdbcType.INTEGER, 3), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_YEAR, CAST('14 Jan 2006' AS TIMESTAMP), CAST('15 Jan 2003' AS TIMESTAMP))", JdbcType.INTEGER, -2), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_FRAC_SECOND, CAST('01 Jan 2004 5:00:00' AS TIMESTAMP), CAST('01 Jan 2004 5:00:01' AS TIMESTAMP))", JdbcType.BIGINT, 1000), | ||
| new MethodSqlTest("SELECT TIMESTAMPDIFF2(SQL_TSI_FRAC_SECOND, CAST('01 Jan 2004' AS TIMESTAMP), CAST('31 Jan 2004' AS TIMESTAMP))", JdbcType.BIGINT, 2592000000L), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add test for
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And new |
||
|
|
||
| new MethodSqlTest("SELECT UCASE('Fred')", JdbcType.VARCHAR, "FRED"), | ||
| new MethodSqlTest("SELECT UPPER('fred')", JdbcType.VARCHAR, "FRED"), | ||
| new MethodSqlTest("SELECT USERID()", JdbcType.INTEGER, () -> TestContext.get().getUser().getUserId()), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude is complaining about this
BIGINTvs.Methoddefiningtimestampdiff2as returningJdbcType.INTEGER.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In limited local testing, I didn't see any problem with very large values, though.