[
https://issues.apache.org/jira/browse/OPENJPA-2966?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18106352#comment-18106352
]
ASF subversion and git services commented on OPENJPA-2966:
----------------------------------------------------------
Commit 46bed3f60fd376f15a82521450bb0ee68076e36f in openjpa's branch
refs/heads/OPENJPA-2966 from Richard Zowalla
[ https://gitbox.apache.org/repos/asf?p=openjpa.git;h=46bed3f60 ]
[OPENJPA-2966] Use a dedicated cast target type for long values
CAST(x AS LONG) was rendered with dict.decimalTypeName. An unsized DECIMAL is
not a 64 bit type on most databases: it is DECIMAL(10,0) on MySQL/MariaDB
(values above 9999999999 are silently clamped, only a SQL warning is raised),
DECIMAL(5,0) on Derby and precision 18 on SQL Server (both raise a range
error). So the current code either truncates or fails for ordinary long values.
bigintTypeName cannot simply be reused, and it must not be redefined either:
it is a DDL type name. DBDictionary.getTypeName(int) returns it for
Types.BIGINT, which drives CREATE TABLE/ADD COLUMN and the schema comparison in
Column.equalsColumn(). Changing it (for instance to DECIMAL(30) on
MySQL/MariaDB) would change the column type of every long mapping, break
AUTO_INCREMENT identity columns and report every existing BIGINT column as
incompatible. The dictionaries that do override bigintTypeName do so because
their database has no BIGINT column type at all (DB2 z/OS v8, Sybase, Informix).
Instead this follows the cast hook idiom already present in DBDictionary
(castFunction, typecastToStringTypeName, supportsUnsizedCharOnCast,
integerCastTypeName):
* new DBDictionary.longCastTypeName, defaulting to null. It is resolved lazily
through getLongCastTypeName() to bigintTypeName. It is deliberately not
initialised as "= bigintTypeName": field initializers run before subclass
constructors, so such a default would freeze to "BIGINT" and ignore
dictionaries that assign bigintTypeName in their constructor or in
connectedConfiguration() (DB2Dictionary does the latter for z/OS v8).
* new DBDictionary.getNumberCastTypeName(Class) and getStringCastTypeName(),
which is where the private sanitize() of TypecastAsNumber now lives; both
strip the DDL size marker {0} via the existing insertSize() helper.
TypecastAsNumber and TypecastAsString both use them, so the two siblings no
longer diverge.
* MySQLDictionary and MariaDBDictionary set longCastTypeName = "SIGNED".
Neither accepts BIGINT as a CAST target; SIGNED [INTEGER] is their 64 bit
signed cast target, mirroring the existing integerCastTypeName = "SIGNED".
Rendering changes: long casts now use BIGINT instead of DECIMAL on every
dictionary that does not override the field (SIGNED on MySQL/MariaDB, unchanged
NUMBER on Oracle since its bigintTypeName is NUMBER{0} as well). Applying the
size marker stripping to the string path also changes one dictionary
deliberately: FoxPro leaves supportsUnsizedCharOnCast at true while its
varcharTypeName is "CHARACTER{0}", so it emitted the literal
CAST(x AS CHARACTER{0}); it now emits CAST(x AS CHARACTER). No other dictionary
carries a marker in that branch, so no other string cast changes.
Not changed, reported instead: integerCastTypeName has the same field
initializer problem and is frozen to "INTEGER" for all dictionaries, ignoring
the integerTypeName overrides of Oracle, SQL Server and others. Making it lazy
would change the emitted int cast on those databases, which is out of scope
here.
Tested by openjpa-jdbc TestCastTypeNames, a dictionary level assertion on the
rendered cast target that needs no database, so MySQL, MariaDB, Oracle and DB2
are covered by the normal build. Against the previous code the long cases
render DECIMAL (and FoxPro CHARACTER{0}), so the test fails without the fix.
> Long cast uses decimalTypeName instead of bigint
> ------------------------------------------------
>
> Key: OPENJPA-2966
> URL: https://issues.apache.org/jira/browse/OPENJPA-2966
> Project: OpenJPA
> Issue Type: Sub-task
> Components: jpa
> Affects Versions: 4.2.0
> Reporter: Maxim Solodovnik
> Assignee: Maxim Solodovnik
> Priority: Major
> Fix For: 4.2.0
>
>
> Discussion thread:
> https://github.com/apache/openjpa/pull/144#discussion_r3683002577
> **(medium)** Casting to Long uses {{dict.decimalTypeName}}; on MySQL {{CAST(x
> AS DECIMAL)}} defaults to DECIMAL(10,0), so large long values
> overflow/truncate - why not {{bigintTypeName}} for the long case?
> Also {{getDbNumberTargetTypeName}} sanitizes the {{{0}}} size suffix while
> the sibling {{TypecastAsString.java:152}} appends {{dict.varcharTypeName}}
> raw - the two siblings should share the same sanitize logic.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)