persistence@glassfish.java.net

Re: Code changes relevant to Issue 283 - PostgreSQL database and SERIAL field

From: Andrei Ilitchev <andrei.ilitchev_at_oracle.com>
Date: Mon, 28 Aug 2006 10:13:59 -0400

Hi Pramod,

Looks good to me.

Thanks,
Andrei
----- Original Message -----
From: "Pramod Gopinath" <Pramod.Gopinath_at_Sun.COM>
To: <persistence_at_glassfish.dev.java.net>; <andrei.ilitchev_at_oracle.com>;
<tom.ware_at_oracle.com>
Sent: Saturday, August 26, 2006 3:57 PM
Subject: Code changes relevant to Issue 283 - PostgreSQL database and SERIAL
field


> Hi Andrei
> The changes that are attached to this email are related to Issue 283.
> https://glassfish.dev.java.net/issues/show_bug.cgi?id=283
>
> We had discussed this back in March timeframe. Since the issue was
> marked as an Enhancement, I had stopped working on this issue. But
> lately there was an issue 805 filed that was related to the same area.
> After I had sent the code changes to Tom and updated the Issue 805 in
> glassfish, thought that it would be great to finally solve this issue
> once and for all.
> Hence using the code changes that we had worked on, I have finally got
> this issue resolved.
>
> All the changes are in the entity-persistence module. The files that
> were changed are:
>
> src/java/oracle/toplink/essentials/internal/databaseaccess/DatasourcePlatform.java
> src/java/oracle/toplink/essentials/internal/databaseaccess/Platform.java
> src/java/oracle/toplink/essentials/internal/sequencing/SequencingManager.java
> src/java/oracle/toplink/essentials/platform/database/PostgreSQLPlatform
>
> With these changes a user wanting to use the SERIAL field of PostgreSQL
> database would just have to define the following in their entity class
> @Id
> @GeneratedValue(strategy=GenerationType.IDENTITY)
>
>
> The field that would be created would be of type "SERIAL" and the
> implicit native sequence associated with this field would be of the form
> fullyQualifiedName_IdFieldColumeName_SEQ. This would ensure that if the
> user has defined the table in a different schema we would use the
> "schemaName".Table_name correctly. Thus we would also solve scenarios
> like those defined in issue 805.
>
> Thanks
> Pramod
>


--------------------------------------------------------------------------------


> Index:
> src/java/oracle/toplink/essentials/internal/databaseaccess/Platform.java
> ===================================================================
> RCS file:
> /cvs/glassfish/entity-persistence/src/java/oracle/toplink/essentials/internal/databaseaccess/Platform.java,v
> retrieving revision 1.6
> diff -r1.6 Platform.java
> 30a31
>> import oracle.toplink.essentials.sessions.DatabaseSession;
> 223a225,231
>>
>> /**
>> * INTERNAL:
>> * Platform specific sequencing initialization.
>> * This internal method should only be called by SequencingManager.
>> */
>> public void platformSpecificSequencingInitialization(DatabaseSession
>> session);
> Index:
> src/java/oracle/toplink/essentials/internal/databaseaccess/DatasourcePlatform.java
> ===================================================================
> RCS file:
> /cvs/glassfish/entity-persistence/src/java/oracle/toplink/essentials/internal/databaseaccess/DatasourcePlatform.java,v
> retrieving revision 1.9
> diff -r1.9 DatasourcePlatform.java
> 31a32
>> import oracle.toplink.essentials.sessions.DatabaseSession;
> 595a597,605
>>
>> /**
>> * INTERNAL:
>> * Platform specific sequencing initialization.
>> * This internal method should only be called by SequencingManager.
>> * By default does nothing.
>> */
>> public void platformSpecificSequencingInitialization(DatabaseSession
>> session) {
>> }
> Index:
> src/java/oracle/toplink/essentials/internal/sequencing/SequencingManager.java
> ===================================================================
> RCS file:
> /cvs/glassfish/entity-persistence/src/java/oracle/toplink/essentials/internal/sequencing/SequencingManager.java,v
> retrieving revision 1.5
> diff -r1.5 SequencingManager.java
> 567a568,569
>>
>> getOwnerSession().getDatasourcePlatform().platformSpecificSequencingInitialization(getOwnerSession());
>>
> Index:
> src/java/oracle/toplink/essentials/platform/database/PostgreSQLPlatform.java
> ===================================================================
> RCS file:
> /cvs/glassfish/entity-persistence/src/java/oracle/toplink/essentials/platform/database/PostgreSQLPlatform.java,v
> retrieving revision 1.7
> diff -r1.7 PostgreSQLPlatform.java
> 39a40,43
>> import oracle.toplink.essentials.sequencing.Sequence;
>> import oracle.toplink.essentials.sequencing.DefaultSequence;
>> import oracle.toplink.essentials.sequencing.NativeSequence;
>> import oracle.toplink.essentials.sessions.DatabaseSession;
> 161c165
> < selectQuery.setSQLString("select currval(current_schema()" + "||
> \'." + seqName + "\')");
> ---
>> selectQuery.setSQLString("select currval(\'" + seqName + "\')");
> 375c379,445
> < }
> ---
>> }
>>
>> protected String getDBSequenceName(String tableName, String
>> pkFieldName) {
>> StringBuffer seqName = new StringBuffer(tableName);
>> seqName.append("_").append(pkFieldName).append("_seq");
>> return seqName.toString();
>> }
>>
>> /**
>> * INTERNAL:
>> * Platform specific sequencing initialization.
>> * This internal method should only be called by SequencingManager.
>> *
>> * For PostgreSQL database for id fields that are defined as "SERIAL"
>> the database creates
>> * an implicit sequence. The name of the sequence provided by the
>> database is of the form
>> * <table_name>_<id_field_name>_seq.
>> * As part of the insert statement we need to get the correct
>> sequence to be able to get
>> * the next value. This code ensures that we have our internal
>> structures pointing to the
>> * correct sequence name for the runtime code to work correctly.
>> * The current version of postgresql allows only 1 SERIAL field to be
>> defined per table.
>> */
>> public void platformSpecificSequencingInitialization(DatabaseSession
>> session) {
>> Boolean isDefaultSequenceNative = null;
>>
>> // We need to iterate over all the entities
>> Iterator iterator =
>> session.getProject().getDescriptors().values().iterator();
>> Sequence sequence;
>>
>> while (iterator.hasNext()) {
>> ClassDescriptor descriptor =
>> (ClassDescriptor)iterator.next();
>>
>> // Ensure that the entity uses sequencing
>> if (descriptor.usesSequenceNumbers()) {
>> String currSequenceName =
>> descriptor.getSequenceNumberName();
>> sequence =
>> (Sequence)getSequences().get(currSequenceName);
>>
>> boolean shouldVerifySequenceName;
>>
>> boolean usesDefaultSequence = sequence == null ||
>> sequence instanceof DefaultSequence;
>> if(usesDefaultSequence) {
>> // is defaultSequence is a NativeSequence?
>> if(isDefaultSequenceNative == null) {
>> isDefaultSequenceNative = new
>> Boolean(getDefaultSequence() instanceof NativeSequence);
>> }
>> shouldVerifySequenceName =
>> isDefaultSequenceNative.booleanValue();
>> } else {
>> shouldVerifySequenceName = sequence instanceof
>> NativeSequence;
>> }
>>
>> if(shouldVerifySequenceName) {
>> DatabaseTable tbl =
>> (DatabaseTable)descriptor.getTables().firstElement();
>> String tableName = tbl.getQualifiedName();
>> String pkFieldName =
>> descriptor.getSequenceNumberField().getName();
>> String seqName = getDBSequenceName(tableName,
>> pkFieldName);
>> if(!currSequenceName.equals(seqName)) {
>> descriptor.setSequenceNumberName(seqName);
>> if(sequence != null) {
>> removeSequence(currSequenceName);
>> sequence.setName(seqName);
>> addSequence(sequence);
>> }
>> }
>> }
>> }
>> }
>> }
>>
>