[ 
https://issues.apache.org/jira/browse/OPENJPA-3014?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18139474#comment-18139474
 ] 

ASF subversion and git services commented on OPENJPA-3014:
----------------------------------------------------------

Commit 06d91ea4de18cd81ce894f6a6dc8768bffa027c1 in openjpa's branch 
refs/heads/master from Richard Zowalla
[ https://gitbox.apache.org/repos/asf?p=openjpa.git;h=06d91ea4d ]

[OPENJPA-3034] Native sequences on Derby/SQL Server, delete order, timestamp 
version precision (#271)

* [OPENJPA-3034] Use real sequences on Derby and SQL Server

Apache Derby (10.6+) and SQL Server (2012+) have sequence objects, but
neither dictionary declared a NextSequenceQuery, so a @SequenceGenerator
was backed by a row of the OpenJPA sequence table (OPENJPA-3014) and the
schema tool generated no CREATE/DROP SEQUENCE for it. The TCK tests
jpa22.se.generators.sequencegenerators and
se.schemaGeneration.annotations.sequenceGenerator expect those statements
in the generated scripts.

DerbyDictionary: NEXT VALUE FOR from 10.6 on, sequences created AS BIGINT,
DROP SEQUENCE ... RESTRICT as Derby requires, sequence reflection from
SYS.SYSSEQUENCES scoped to the current schema.

Derby has no ALTER SEQUENCE, so the INCREMENT BY of a sequence cannot be
adjusted to the allocation size of its generator, and the dictionary sets
disableAlterSeqenceIncrementBy. With that set, NativeJDBCSeq used to trust
the increment of the sequence: one that already existed with a smaller
INCREMENT BY than the allocation size made it hand out values the database
hands out as well. DBDictionary.getSequenceIncrement() now reads the
increment of a sequence (DerbyDictionary: from SYS.SYSSEQUENCES), and
NativeJDBCSeq only caches a block of values if the increment covers the
allocation size; otherwise, or if the sequence cannot be found, it draws
every value from the sequence and logs a warning saying so. Dictionaries
that cannot read the increment keep the previous behaviour, including the
warning about the disableAlterSeqenceIncrementBy property.

SQLServerDictionary: NEXT VALUE FOR from 2012 (major version 11) on,
sequence reflection from sys.sequences scoped to the default schema, and
an explicit START WITH 0 since a sequence otherwise starts at the minimum
of its type.

An explicitly configured NextSequenceQuery is left alone on both.

MySQL has no sequence objects, so the two TCK tests keep failing there on
the missing CREATE/DROP SEQUENCE statements. The TCK runner is not changed
to pass db.supports.sequence=false for MySQL: that would turn eleven tests
into passes without running them, nine of which do pass for real through
the sequence table fallback of OPENJPA-3014.

* [OPENJPA-3034] Order deletes by logical foreign keys

A schema not created by OpenJPA can have foreign key constraints the
mapping does not know of; a relation is then mapped to a logical foreign
key. Inserts are ordered by such keys since OPENJPA-2940, deletes were
not: removing the referenced entity before the referencing one in the
same flush issued the DELETEs in that order and violated the constraint
(TCK core.entitytest.persist.manyXone persistMX1Test2 and
cascadeall.manyXone cascadeAllMX1Test2 on Derby and SQL Server, whose
TCK DDL has no ON DELETE CASCADE).

RelationFieldStrategy.delete() and PrimaryRow now record a logical
foreign key of a deleted row to another deleted row, so that the
referencing row is deleted first, as for restrict and cascade keys.

Behaviour change: rows deleted in one flush that reference each other in
a cycle of nullable logical foreign keys are now ordered like rows with
restrict keys, i.e. the cycle is broken by one UPDATE setting a key to
null before the DELETEs. That is the statement a database enforcing the
keys needs, and what inserts of such a cycle issue since OPENJPA-2940;
deletes without a cycle issue no extra statement.

A logical key is ordered only on the chance that the database enforces
it. If such keys close a cycle that no nullable key can break, the
ConstraintUpdateManager now drops the ordering of a logical key instead
of throwing "no-nullable-fk"; that also covers inserts, which failed so
since OPENJPA-2940.

* [OPENJPA-3034] Keep timestamp versions at the precision of the column

A timestamp version column of a schema not created by OpenJPA may keep
fewer fractional digits of a second than the dictionary assumes. The TCK
creates the version column of core.annotations.version.Client4 as a
MySQL/MariaDB TIMESTAMP without fractional seconds and as a SQL Server
DATETIME (1/300 s granularity). The version kept in memory (and bound in
the WHERE clause of the next UPDATE) then never matched the stored value,
and timestampFieldTest/timestampPropertyTest failed with an
OptimisticLockException.

TimestampVersionStrategy generates the versions at the precision of the
column when that is coarser than the dictionary's datePrecision. A
precision declared in the mapping, the JPA 3.2 @Column(secondPrecision),
is used as it is. Otherwise the precision is read from the database
metadata on the first insert or update, and if coarser recorded on the
column. The result is kept per column, so entities mapped to the same table
share one lookup and the same precision, and later flushes do not query the
metadata.
The lookup is skipped for dictionaries that need auto-commit for metadata
operations, as it would end the transaction.

DBDictionary.getTimestampPrecision(Column) maps a known column precision
(0-9 fractional digits) to the rounding granularity used by
setTimestamp(). SQLServerDictionary rounds to 10 ms for a DATETIME column,
the granularity that DATETIME stores exactly and that compares equal to
the DATETIME2 parameter the driver sends; other three digit columns such
as DATETIME2(3) keep whole milliseconds.

Column.copy() did not carry secondPrecision, so it never reached the
column of a @Version field (neither its DDL nor the version strategy);
it does now.

NanoPrecisionTimestampVersionStrategy now supplies the current time
through currentTimestamp() so that the rounding applies to it as well.

* [OPENJPA-3034] Use pattern matching for the logical foreign key check

---------

Co-authored-by: Maxim Solodovnik <[email protected]>

> A named @SequenceGenerator fails where the database has no sequences
> --------------------------------------------------------------------
>
>                 Key: OPENJPA-3014
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-3014
>             Project: OpenJPA
>          Issue Type: Bug
>          Components: jpa
>            Reporter: Richard Zowalla
>            Assignee: Richard Zowalla
>            Priority: Major
>             Fix For: 4.2.0
>
>
> A named @SequenceGenerator fails on any database whose dictionary has no 
> nextSequenceQuery, for example MySQL:
>   org.apache.openjpa.persistence.ArgumentException: Error instantiating named 
> sequence "SEQGENERATOR": Your database dictionary does not support native 
> sequences.
>       at 
> org.apache.openjpa.jdbc.kernel.NativeJDBCSeq.endConfiguration(NativeJDBCSeq.java:190)
> Found by Maxim Solodovnik while running the TCK against MySQL.
> Cause: AnnotationPersistenceMetaDataParser sets the plugin of a 
> @SequenceGenerator to SequenceMetaData.IMPL_NATIVE unless the sequenceName is 
> itself a plugin string, and JDBCSeqValue maps that alias to NativeJDBCSeq, 
> which refuses to configure when dict.nextSequenceQuery is null. The 
> openjpa.Sequence setting does not help: SequenceMetaData.instantiate() 
> consults the configured system sequence only for the system sequence name, so 
> a named generator always takes the plugin path. No configuration property can 
> therefore avoid the failure.
> Two independent parts.
> 1. Fall back to a table backed sequence where the database has none. OpenJPA 
> already ships SequenceMapping.IMPL_TABLE and IMPL_VALUE_TABLE (TableJDBCSeq, 
> ValueTableJDBCSeq), which keep the current value in a row of a sequence table 
> and update it in place, the same approach other providers take on MySQL. A 
> named generator resolved against a dictionary without nextSequenceQuery 
> should use that instead of failing, with a warning, gated on 
> nextSequenceQuery being null rather than on a dictionary class so every such 
> dictionary benefits. The substitution belongs where the sequence is resolved 
> (SequenceMapping / MappingRepository) so the runtime and the mapping tool 
> behave the same; a patch that only changes MappingTool.addSequenceComponents 
> fixes the tool and leaves a plain EntityManagerFactory failing, besides 
> relying on a mutation of shared metadata.
> Two details to decide: IMPL_TABLE keys its rows per class, so entities 
> sharing one generator would get independent counters, whereas 
> IMPL_VALUE_TABLE keys by sequence name and matches @SequenceGenerator 
> semantics more closely; and initialValue and allocationSize travel on the 
> SequenceMetaData rather than in the plugin string, so they must survive the 
> substitution.
> 2. Use the real thing on MariaDB. MariaDB 10.3 and later has sequence objects 
> (CREATE SEQUENCE, NEXT VALUE FOR, NEXTVAL()), so 
> MariaDBDictionary.connectedConfiguration() should set nextSequenceQuery when 
> the server reports 10.3 or later, in the version gated manner 
> PostgresDictionary already uses for storeCharsAsNumbers, and leave older 
> servers on the fallback from part 1.
> Note for the TCK: its setup method issues CREATE SEQUENCE SEQGENERATOR START 
> WITH 10 through a native query and logs the failure on MySQL. That logged 
> error is expected there and harmless; what matters is that identifiers can 
> still be allocated afterwards, which part 1 provides. On MariaDB the 
> statement succeeds, which part 2 then uses.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to