Hi Maxim, The substitution is the right idea, but I would not put it in MappingTool.
addSequenceComponents only runs during schema tooling. It works at runtime only because it mutates the shared SequenceMetaData, so the rewritten plugin happens to stick if the same repository is used afterwards. Without the tool — a plain EMF against an existing schema — a named @SequenceGenerator still reaches NativeJDBCSeq and fails with the same message. Rewriting metadata as a side effect of tooling also assumes the tool's dictionary is the runtime's. Imho it belongs where the sequence is resolved, i.e. SequenceMapping / MappingRepository. Then both the tool and the runtime see it and MappingTool needs no change. I can sketch up an implementation under OPENJPA-3001 too, if you would prefer that way Gruß Richard > Am 12.10.2026 um 07:10 schrieb Maxim Solodovnik <[email protected]>: > > I've modified MappingTool as follows [1] > Do you feel it worth committing? :) > > so tests still failing due to there are methods like this: > > protected void createSequenceGenerator() { > try { > getEntityTransaction().begin(); > getEntityManager().createNativeQuery("CREATE SEQUENCE > SEQGENERATOR START WITH 10").executeUpdate(); > getEntityTransaction().commit(); > } catch (Exception e) { > logger.log(Logger.Level.ERROR, "Exception encountered while > creating seq:", e); > } > } > > not sure how it should work .... > > [1] > diff --git > a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java > b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java > index 91c769ade..aeff3bf62 100644 > --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java > +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java > @@ -738,30 +738,39 @@ public class MappingTool > SchemaGroup group) { > SequenceMetaData smd = mapping.getIdentitySequenceMetaData(); > Seq seq = null; > - if (smd != null) > + if (smd != null) { > seq = smd.getInstance(null); > - else if (mapping.getIdentityStrategy() == ValueStrategies.NATIVE > + } else if (mapping.getIdentityStrategy() == ValueStrategies.NATIVE > || (mapping.getIdentityStrategy() == ValueStrategies.NONE > && mapping.getIdentityType() == ClassMetaData.ID_DATASTORE)) > + { > seq = _conf.getSequenceInstance(); > + } > > - if (seq instanceof JDBCSeq) > - ((JDBCSeq) seq).addSchema(mapping, group); > + if (seq instanceof JDBCSeq jdbcSeq) { > + jdbcSeq.addSchema(mapping, group); > + } > > FieldMapping[] fmds; > - if (mapping.getEmbeddingMetaData() == null) > + if (mapping.getEmbeddingMetaData() == null) { > fmds = mapping.getDefinedFieldMappings(); > - else > + } else { > fmds = mapping.getFieldMappings(); > + } > for (FieldMapping fmd : fmds) { > smd = fmd.getValueSequenceMetaData(); > if (smd != null) { > + if > (SequenceMetaData.IMPL_NATIVE.equals(smd.getSequencePlugin()) && > _dict.nextSequenceQuery == null) { > + _log.warn(_loc.get("no-seq-sql", smd.getSequence())); > + smd.setSequencePlugin(SequenceMapping.IMPL_TABLE); > + } > seq = smd.getInstance(_loader); > - if (seq instanceof JDBCSeq) > - ((JDBCSeq) seq).addSchema(mapping, group); > - } > - else if (fmd.getEmbeddedMapping() != null) > + if (seq instanceof JDBCSeq jdbcSeq) { > + jdbcSeq.addSchema(mapping, group); > + } > + } else if (fmd.getEmbeddedMapping() != null) { > addSequenceComponents(fmd.getEmbeddedMapping(), group); > + } > } > } > > > On Fri, 9 Oct 2026 at 16:09, Maxim Solodovnik <[email protected]> wrote: >> >> Hello Richard, >> >> On Fri, 9 Oct 2026 at 14:58, Richard Zowalla <[email protected]> wrote: >>> >>> Hi Maxim, >>> >>> Good news: no emulation needed, and no growing table either. >>> >>> Neither MySQLDictionary nor MariaDBDictionary sets nextSequenceQuery, so >>> NativeJDBCSeq.endConfiguration() throws for any @SequenceGenerator. But >>> OpenJPA already ships a table-backed sequence: SequenceMapping.IMPL_TABLE / >>> IMPL_VALUE_TABLE, implemented by TableJDBCSeq, which keeps a single row per >>> sequence in OPENJPA_SEQUENCE_TABLE (column SEQUENCE_VALUE) and updates it >>> in place. That is the same approach Hibernate and EclipseLink take on >>> MySQL, so AUTO_INCREMENT is not required and nothing grows. >>> >>> I would split it in two, because the two dbms are different: >>> >>> MariaDB can do it natively. MariaDB 10.3 and later has real sequence >>> objects (CREATE SEQUENCE, NEXT VALUE FOR seq, NEXTVAL(seq)), and you are >>> running 11.8. So MariaDBDictionary.connectedConfiguration() can set >>> nextSequenceQuery once the server reports >= 10.3, following the >>> version-gated pattern PostgresDictionary already uses for >>> storeCharsAsNumbers, and leave the older versions alone. That should make >>> the sequence TCK tests pass on MariaDB without any mapping change. >>> >>> MySQL has no sequences at any version, so a @SequenceGenerator has to fall >>> back to the table sequence. Interestingly part of it is already there: >>> AnnotationPersistenceMetaDataParser does both GenerationType.TABLE and >>> GenerationType.SEQUENCE through the system openjpa.Sequence setting when >>> the generator is unnamed. The gap would be a named generator on a >>> dictionary without native sequences, which currently fails instead of >>> falling back. >>> >>> As a workaround for your branch right now, before any code change, you can >>> point the named generator at the table implementation, e.g. >>> >>> openjpa.Sequence: table(Table=OPENJPA_SEQUENCE_TABLE) >> >> this would be hard to implement for TCK :( >> we do pass params via >> <jpa.provider.implementation.specific.properties> which has `:` >> delimiter >> but inside the key it has `=` delimiter :( >> >> and we already passing `openjpa.Sequence=time` .... >> >> so the only options are: System property and code modification :) >> I'll try to modify the code >> >>> >>> for the unnamed case, or give the generator an explicit table >>> implementation in the mapping. >>> >>> The MariaDB version check would be low risk, the MySQL fallback changes >>> identity generation behaviour on a database people are using, so I would >>> keep them as separate commits (and probably separate review) even if they >>> share one issue. >>> >>> Hope it helps >>> Richard >>> >>> >>>> Am 09.10.2026 um 05:45 schrieb Maxim Solodovnik <[email protected]>: >>>> >>>> There is great progress :)) >>>> Failing list is reduced :)) >>>> >>>> Some tests are failing due to: >>>> >>>> ``` >>>> SEVERE: Exception encountered while creating seq: >>>> <openjpa-4.2.0-SNAPSHOT-r832b5cdM fatal user error> >>>> org.apache.openjpa.persistence.ArgumentException: Error instantiating >>>> named sequence "SEQGENERATOR": Your database dictionary does not >>>> support native sequences. To tell the dictionary how to select >>>> sequence values, use: >>>> openjpa.jdbc.DBDictionary: NextSequenceQuery="SELECT NEXT VALUE FOR >>>> "SEQGENERATOR" >>>> Where the above string is replaced with the proper SQL for your database. >>>> at >>>> org.apache.openjpa.jdbc.kernel.NativeJDBCSeq.endConfiguration(NativeJDBCSeq.java:190) >>>> ``` >>>> >>>> I guess SEQUENCE can be emulated with AUTOINCREMENT >>>> https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html >>>> But having growing table seems to be overkill .... >>>> >>>> On Thu, 8 Oct 2026 at 21:08, Maxim Solodovnik <[email protected]> wrote: >>>>> >>>>> It seems regular MySql tests are broken :( >>>>> >>>>> ``` >>>>> [ERROR] Failures: >>>>> [ERROR] >>>>> TestContainerSpecCompatibilityOptions>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testLegacyDefaultMapKeyColumnName:471->assertSQLFragnments:932 >>>>> None of the following 3 SQL >>>>> [ERROR] >>>>> TestBiDirectionalJoinTable>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testBulkDelete:138->SQLListenerTestCase.assertSQL:74 >>>>> Expected regular expression >>>>> [ERROR] >>>>> TestBulkDeleteCompositeId>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testCompositeKeyCandidateWithoutCriteria:65->SQLListenerTestCase.assertSQL:74 >>>>> Expected regular expression >>>>> [ERROR] >>>>> TestBulkDeleteDependentFields>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testUnfilteredDeleteCleansOwnedTablesOfDependentFields:140->SQLListenerTestCase.assertSQL:74 >>>>> Expected regular >>>>> [ERROR] >>>>> TestBulkDeleteJoinTable>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testBulkDeleteWithoutCriteriaEmptiesOwnedTables:58->SQLListenerTestCase.assertSQL:74 >>>>> Expected regular expression >>>>> [ERROR] >>>>> TestBulkDeleteSubclassJoinTable>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testBulkDeleteThroughBaseClass:51->SQLListenerTestCase.assertSQL:74 >>>>> Expected regular expression >>>>> >>>>> [INFO] OpenJPA Persistence JDBC ........................... FAILURE [ >>>>> 01:33 h] >>>>> >>>>> [ERROR] Tests run: 3761, Failures: 6, Errors: 0, Skipped: 0 >>>>> ``` >>>>> >>>>> On Thu, 8 Oct 2026 at 13:37, Maxim Solodovnik <[email protected]> >>>>> wrote: >>>>>> >>>>>> Hello Richard, >>>>>> >>>>>> On Thu, 8 Oct 2026 at 13:24, Richard Zowalla <[email protected]> wrote: >>>>>>> >>>>>>> Hi Maxim, >>>>>>> >>>>>>> the truncation is a consequence of it, not a separate problem. >>>>>>> >>>>>>> DBDictionary.storeCharsAsNumbers still defaults to true >>>>>>> (DBDictionary:327), and only DB2 (DB2Dictionary:124) and PostgreSQL >>>>>>> (PostgresDictionary:151) switch it off. >>>>>>> MySQL inherits the legacy default, so: >>>>>>> >>>>>>> - getPreferredType() maps JavaTypes.CHAR to Types.INTEGER >>>>>>> (DBDictionary:2006) — that is the "Given column: Type: integer" in your >>>>>>> warning, and >>>>>>> - setChar() takes the numeric branch because the mapped column reports >>>>>>> as INTEGER-compatible (DBDictionary:1285) and does setInt(stmnt, idx, >>>>>>> (int) val). >>>>>>> >>>>>>> So for >>>>>>> >>>>>>> @Column(name = "CHARDATA") >>>>>>> protected char characterData; >>>>>>> >>>>>>> we send 65 into the TCK's CHARDATA CHAR column, and two digits do not >>>>>>> fit one character: code 1406, "Data too long for column 'CHARDATA'". >>>>>>> >>>>>>> Workaround for your branch, no code change needed: >>>>>>> >>>>>>> openjpa.jdbc.DBDictionary=mysql(StoreCharsAsNumbers=false) >>>>>>> >>>>>>> However, I would fix it the way we did for PostgreSQL in OPENJPA-2971: >>>>>>> have MySQLDictionary set storeCharsAsNumbers = false in the >>>>>>> constructor, keep the isStoreCharsAsNumbersExplicit() >>>>>>> so a value a user set explicitly is never overwritten, and add a >>>>>>> migration note — existing MySQL schemas created by earlier OpenJPA >>>>>>> releases have INTEGER columns for >>>>>>> char fields and will need StoreCharsAsNumbers=true to keep working. >>>>>> >>>>>> I'll give it a try and will write back :) >>>>>> Thanks a million for your help! :) >>>>>> >>>>>>> >>>>>>> That is exactl OPENJPA-3001. >>>>>>> >>>>>>> On the schema generation: drop-and-create cannot help here, and the >>>>>>> error you get comes from a different place. >>>>>>> "Table ... has a foreign key to table ... that has not been generated" >>>>>>> is thrown by SchemaGenerator:885 while reading the >>>>>>> live database metadata; it fires when a foreign key in the existing >>>>>>> schema points at a table that is not part of the group being generated. >>>>>>> >>>>>>> With leftover tables from other TCK persistence units in the same >>>>>>> database, any subset run trips it. >>>>>>> >>>>>>> Since the TCK ships its own DDL, I would not let OpenJPA generate the >>>>>>> schema for a TCK run at all. >>>>>>> A clean database per run (DROP DATABASE / CREATE DATABASE, or a schema >>>>>>> per PU) is more reliable >>>>>>> than asking the schema tool to reconcile. Once the column type is >>>>>>> right, the incompatibility warning and the truncation, should disappear. >>>>>> >>>>>> Actually current script drops all local data at docker stop >>>>>> https://github.com/apache/openjpa/commit/db9c64be252643555803988f3330d8b32a09dd5a >>>>>> ``` >>>>>> <keepContainer>false</keepContainer> >>>>>> <removeVolumes>true</removeVolumes> >>>>>> ``` >>>>>> >>>>>>> >>>>>>> Best regards, >>>>>>> Richard >>>>>>> >>>>>>> On 2026-10-07 06:10 UTC Maxim Solodovnik wrote: >>>>>>>> Hello All, >>>>>>>> >>>>>>>> I'm trying to investigate TCK failures with Mysql DB >>>>>>>> >>>>>>>> I'm investigating 'Data truncation: Data too long for column' class of >>>>>>>> problems >>>>>>>> I've notices these errors are coupled with warnings like: >>>>>>>> ``` >>>>>>>> 19 WARN [main] openjpa.jdbc.Schema - Existing column "CHARDATA" on >>>>>>>> table "DATATYPES" is incompatible with the same column in the given >>>>>>>> schema definition. Existing column: >>>>>>>> Full Name: DATATYPES.CHARDATA >>>>>>>> Type: char >>>>>>>> Size: 1 >>>>>>>> Default: null >>>>>>>> Not Null: false >>>>>>>> Given column: >>>>>>>> Full Name: DATATYPES.CHARDATA >>>>>>>> Type: integer >>>>>>>> Size: 0 >>>>>>>> Default: null >>>>>>>> Not Null: false >>>>>>>> ``` >>>>>>>> >>>>>>>> So my guess was: schemaTool need to be instructed to drop/create >>>>>>>> existing table so column definition will be updated to have correct >>>>>>>> type >>>>>>>> >>>>>>>> I've tried to add >>>>>>>> `jakarta.persistence.schema-generation.database.action=drop-and-create` >>>>>>>> (as well as >>>>>>>> `:jakarta.persistence.schema-generation.database.action=drop-and-create:jakarta.persistence.schema-generation.scripts.action=drop-and-create`) >>>>>>>> >>>>>>>> But got `Table "{0}" has a foreign key to table "{1}" that has not >>>>>>>> been \ >>>>>>>> generated. You must run the schema generator on all inter-related >>>>>>>> tables \ >>>>>>>> at once.` errors instead :( >>>>>>>> >>>>>>>> Any help is appreciated :))) >>>>>>>> >>>>>>>> I'm playing at `tck-mysql` branch :)) >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> Best regards, >>>>>>>> Maxim >>>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Best regards, >>>>>> Maxim >>>>> >>>>> >>>>> >>>>> -- >>>>> Best regards, >>>>> Maxim >>>> >>>> >>>> >>>> -- >>>> Best regards, >>>> Maxim >>> >> >> >> -- >> Best regards, >> Maxim > > > > -- > Best regards, > Maxim
