Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 529602 - ORA-00932: inconsistent datatypes: expected - got CLOB
Summary: ORA-00932: inconsistent datatypes: expected - got CLOB
Status: RESOLVED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows 7
: P3 normal with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: Will Dazey CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-01-09 21:27 EST by Will Dazey CLA
Modified: 2022-06-09 10:10 EDT (History)
4 users (show)

See Also:


Attachments
master patch (15.72 KB, patch)
2018-01-17 16:01 EST, Will Dazey CLA
no flags Details | Diff
2.7 patch (15.72 KB, patch)
2018-01-17 16:02 EST, Will Dazey CLA
no flags Details | Diff
2.6_WAS patch (15.71 KB, patch)
2018-01-17 16:04 EST, Will Dazey CLA
no flags Details | Diff
master patch v2 (16.28 KB, patch)
2018-01-31 13:08 EST, Will Dazey CLA
no flags Details | Diff
2.7 patch v2 (16.76 KB, patch)
2018-01-31 13:09 EST, Will Dazey CLA
no flags Details | Diff
2.6_WAS patch v2 (17.42 KB, patch)
2018-01-31 13:10 EST, Will Dazey CLA
no flags Details | Diff
working change in ObjectBuilder (1.72 KB, patch)
2018-02-12 22:01 EST, Lukas Jungmann CLA
no flags Details | Diff
master patch v3 (16.36 KB, patch)
2018-02-14 15:32 EST, Will Dazey CLA
lukas.jungmann: review+
Details | Diff
2.7 patch v3 (16.36 KB, patch)
2018-02-14 15:32 EST, Will Dazey CLA
no flags Details | Diff
2.6_WAS patch v3 (17.11 KB, patch)
2018-02-14 15:33 EST, Will Dazey CLA
no flags Details | Diff
master/2.7 patch v3 pt2 (6.88 KB, patch)
2018-02-21 11:20 EST, Will Dazey CLA
lukas.jungmann: review+
Details | Diff
2.6_WAS patch v3 pt2 (4.77 KB, patch)
2018-02-21 11:33 EST, Will Dazey CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Will Dazey CLA 2018-01-09 21:27:50 EST
When elements of a CollectionTable are modified and merged back to the EntityManager, EclipseLink issues a DELETE statement to remove the previous values from the DB. If one of the fields is a CLOB, Oracle throws an exception since you cannot have a CLOB in the WHERE clause. 

Doing some research, I see that this problem has been around for quite some time. The problem is that for the collection table, there is no primary key column. The JPA specification does not directly address this limitation and other JPA providers have their own implementation specific methods of dealing with it. After some digging around I found the following post from James Sutherland:

https://dev.eclipse.org/mhonarc/lists/eclipselink-users/msg05047.html

I followed the steps he suggested and there seems to be further bugs in EclipseLink. Since I do not see any existing tests for this scenario, I am going to assume that this never worked. 

Entity mappings:

@Embeddable
public class CollectedEntityPdo {
    @Lob
    @Column(name = "content", nullable = false)
    private String content;
}

@Entity
public class ParentEntityPdo {
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(
        joinColumns = {
            @JoinColumn(name = "parent_id", referencedColumnName = "id"),
            @JoinColumn(name = "parent_version", referencedColumnName = "version")
        })
    private Set<CollectedEntityPdo> subs;
}

Exception:

Exception [EclipseLink-4002] (Eclipse Persistence Services - 3.0.0.qualifier): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00932: inconsistent datatypes: expected - got CLOB

Error Code: 932
Call: DELETE FROM ParentEntityPdo_SUBS WHERE ((((content = ?) AND (label = ?)) AND (parent_id = ?)) AND (parent_version = ?))
Comment 1 Benjamin Marwell CLA 2018-01-10 02:48:08 EST
This scenario (oracle database, embeddedables, LOB fields) is highly likely in enterprise scenarios. Therefore I voted for this issue.

A sufficient solution might be to fix the provider to not include @Lob fields for Oracle, if it is not the only field. Due to performance reasons, I would like to see providers to avoid calls to lob fields at all costs, where reasonable.

As Will pointed out, you can find similar issues on stack overflow. Either they are not resolved, or contain provider-specific solutions.
Comment 2 Will Dazey CLA 2018-01-17 16:01:27 EST
Created attachment 272312 [details]
master patch
Comment 3 Will Dazey CLA 2018-01-17 16:02:44 EST
Created attachment 272313 [details]
2.7 patch
Comment 4 Will Dazey CLA 2018-01-17 16:04:22 EST
Created attachment 272314 [details]
2.6_WAS patch
Comment 5 Lukas Jungmann CLA 2018-01-30 15:13:26 EST
Comment on attachment 272312 [details]
master patch

- I'm missing javadoc for methods added to DatabasePlatform

- you can avoid 'if' in 'shouldPrintCustomSQLForField' and directly 'return ClassConstants.BLOB.equals(type) || ClassConstants.CLOB.equals(type)' there

- all 'if' checks in 'printCustomSQLForField' can be removed - it looks (..and should be documented in javadoc somewhere...) that the method is called after 'shouldPrintCustomSQLForField' which does almost the same checks;
I'm also not sure if the platform needs to know the expression (first/second), it should be enough to pass DatabaseField and ExpressionSQLPrinter to this method
Comment 6 Lukas Jungmann CLA 2018-01-30 16:11:42 EST
(In reply to Lukas Jungmann from comment #5)
btw: you should also be able to replace 'ClassConstants.BLOB.equals(type)' with 'ClassConstants.BLOB == type' (same for CLOB)
Comment 7 Will Dazey CLA 2018-01-31 11:32:23 EST
Thanks for the review Lukas! 

> I'm missing javadoc for methods added to DatabasePlatform

Your right, I did miss the javadoc that I should have added to these new methods, Ill update the patches to include proper documentation.

> you can avoid 'if' in 'shouldPrintCustomSQLForField' and directly 'return ClassConstants.BLOB.equals(type) || ClassConstants.CLOB.equals(type)' there

Yes, I can rewrite the 'if' check here to make the logic a bit more streamlined. 

> all 'if' checks in 'printCustomSQLForField' can be removed - it looks (..and should be documented in javadoc somewhere...) that the method is called after 'shouldPrintCustomSQLForField' which does almost the same checks;

I added redundant checks to 'printCustomSQLForField' due to the possibility of multiple field types needing custom SQL operations in the future and the checks seemed safe enough to redo. I will document the method to only be used if the 'shouldPrintCustomSQLForField' returns a true value, but I'd like to keep the other checks.

> I'm also not sure if the platform needs to know the expression (first/second), it should be enough to pass DatabaseField and ExpressionSQLPrinter to this method

I am not sure how I can write the SQL as I do without passing in both the first & second Expression objects. I suppose I could just pass in 'this' CompoundExpression and obtain the first/second children to print from that Expression... Let me know if you have any other ideas.

Thanks!
Comment 8 Will Dazey CLA 2018-01-31 13:08:33 EST
Created attachment 272480 [details]
master patch v2
Comment 9 Will Dazey CLA 2018-01-31 13:09:27 EST
Created attachment 272481 [details]
2.7 patch v2
Comment 10 Will Dazey CLA 2018-01-31 13:10:10 EST
Created attachment 272482 [details]
2.6_WAS patch v2
Comment 11 Lukas Jungmann CLA 2018-02-05 15:49:54 EST
I'm thinking whether solving this by platform specific expressionoperator extending functionoperator wouldn't be better/cleaner solution. WDYT?
Comment 12 Will Dazey CLA 2018-02-05 19:20:12 EST
@Lukas
I had tried something very similar to this at first. The issue I was having was how to determine when the new expressionoperation applied. From my understanding, ExpressionOperators have a selector id (key) that identifies them in their map (DatasourcePlatform.platformOperators). From here I took a look at CompoundExpression.initializePlatformOperator(), however the issue is the operator is already '='.

-------------
Consider the following WHERE clause LogicalExpression:

Logical operator [ AND ]
   Logical operator [ AND ]
      Logical operator [ AND ]
         Relation operator [ = ]
            Field ParentEntityPdo_SUBS.content
               Base QUERY OBJECT
            Parameter ParentEntityPdo_SUBS.content
         Relation operator [ = ]
            Field ParentEntityPdo_SUBS.label
               Base QUERY OBJECT
            Parameter ParentEntityPdo_SUBS.label
      Relation operator [ = ]
         Field ParentEntityPdo_SUBS.parent_id
            Base QUERY OBJECT
         Parameter ParentEntityPdo_SUBS.parent_id
   Relation operator [ = ]
      Field ParentEntityPdo_SUBS.parent_version
         Base QUERY OBJECT
      Parameter ParentEntityPdo_SUBS.parent_version

This is the expression for the following query:
DELETE FROM ParentEntityPdo_SUBS WHERE ((((content = ?) AND (label = ?)) AND (parent_id = ?)) AND (parent_version = ?)))

The portion that matters here is the RelationExpression:

Relation operator [ = ]
   Field ParentEntityPdo_SUBS.content
      Base QUERY OBJECT
   Parameter ParentEntityPdo_SUBS.content

NOTE: 'ParentEntityPdo_SUBS.content' is of type CLOB

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

I first looked at ObjectBuilder.createPrimaryKeyExpression() because I figured this is where I would insert a new expressionoperation. EclipseLink creates the LogicalExpression I pasted above here by looking at the primaryKey fields and using the generic Expression.equal() operator. Unfortunately, at this point, DatasourcePlatform.platformOperators == null, so the platform operators haven't been initialized yet. I think this means the LogicalExpression has to be created with the '=' operator and not a custom operator.

If there is a cleaner way to make this work, I will look into it and I am open to suggestion. Thanks for reading.
Comment 13 Lukas Jungmann CLA 2018-02-12 22:01:27 EST
Created attachment 272654 [details]
working change in ObjectBuilder

I tried an experiment in ObjectBuilder.createPrimaryKeyExpression (thanks for this pointer btw!) which seems to fix the problem as well and looks a bit cleaner to me - it tries to fix the bug itself, not the buggy behaviour later... This is really quick and dirty but it should not be difficult to "hide" the 'if clob' behind some 'session.getPlatform().createExpressionFor(DatabaseField...)' call. WDYT?
Comment 14 Will Dazey CLA 2018-02-14 15:32:04 EST
Created attachment 272675 [details]
master patch v3

Thanks for the advice Lukas! I went ahead and created a new patch taking into account your suggestion. Id appreciate any further thoughts and a review.
Comment 15 Will Dazey CLA 2018-02-14 15:32:45 EST
Created attachment 272676 [details]
2.7 patch v3
Comment 16 Will Dazey CLA 2018-02-14 15:33:22 EST
Created attachment 272677 [details]
2.6_WAS patch v3
Comment 17 Lukas Jungmann CLA 2018-02-14 17:29:14 EST
Comment on attachment 272675 [details]
master patch v3

yes, this is better. Looks good to me now. Thanks!
Comment 19 Will Dazey CLA 2018-02-20 18:43:21 EST
I ran the DBWS tests and I see that some tests were now failing:
  LoadAndSaveWithOptionsTestCases.testLoadFromInputStreamSaveDocumentToOutputStream
LoadAndSaveWithOptionsTestCases.testLoadFromInputStreamWithURIAndOptionsSaveDataObjectToOutputStream
LoadAndSaveWithOptionsTestCases.testLoadFromFileReaderWithURIAndOptionsStreamSaveDataObjectToWriter
LoadAndSaveWithOptionsTestCases.testLoadFromAndSaveAfterDefineMultipleSchemas
LoadAndSaveWithOptionsTestCases.testLoadFromInputStreamWithURIAndOptionsSaveDataObjectToStreamResult
LoadAndSaveWithOptionsTestCases.testLoadFromDomSourceWithURIAndOptionsSaveDataObjectToStreamResult
LoadAndSaveWithOptionsTestCases.testLoadFromSAXSourceWithURIAndOptionsSaveDataObjectToStreamResult
LoadAndSaveWithOptionsTestCases.testLoadFromStreamSourceWithURIAndOptionsSaveDataObjectToStreamResult

Taking a look at the error I am getting:

[junit] Error: 
    [junit] java.lang.ClassCastException: org.eclipse.persistence.oxm.platform.SAXPlatform incompatible with org.eclipse.persistence.platform.database.DatabasePlatform
    [junit] 	at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.getPlatform(DatabaseSessionImpl.java:509)
    [junit] 	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.createPrimaryKeyExpression(ObjectBuilder.java:2914)
    [junit] 	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.initializePrimaryKey(ObjectBuilder.java:3881)
    [junit] 	at org.eclipse.persistence.internal.oxm.XMLObjectBuilder.initialize(XMLObjectBuilder.java:615)
    [junit] 	at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.initialize(TreeObjectBuilder.java:94)
    [junit] 	at org.eclipse.persistence.oxm.XMLDescriptor.initialize(XMLDescriptor.java:774)
    [junit] 	at org.eclipse.persistence.sdo.helper.delegates.SDOXMLHelperDelegate.initializeDescriptor(SDOXMLHelperDelegate.java:648)

It seems my change introduced a failure in this test bucket. I am working on fixing this.
Comment 20 Will Dazey CLA 2018-02-21 10:57:38 EST
Tests in SDO are failing due to this change, reopening to fix
Comment 21 Will Dazey CLA 2018-02-21 11:19:36 EST
Taking a look at the failure, it seems my change was not taking into account org.eclipse.persistence.oxm.platform.SAXPlatform, which does not extend DatabasePlatform, but instead extends DatasourcePlatform.

I created a new patch that fixes this issue. I ran this fix against the sdo testing and they passed without failure.
Comment 22 Will Dazey CLA 2018-02-21 11:20:30 EST
Created attachment 272793 [details]
master/2.7 patch v3 pt2

Patch to fix SDO failing tests
Comment 23 Will Dazey CLA 2018-02-21 11:33:30 EST
Created attachment 272794 [details]
2.6_WAS patch v3 pt2
Comment 24 Lukas Jungmann CLA 2018-02-22 11:53:14 EST
Comment on attachment 272793 [details]
master/2.7 patch v3 pt2

I'm fine with this. Alternative would be to "fallback" to the original in ObjectBuilder if platform. createExpressionFor returns null... But I'll leave that up to you..
Comment 26 Joe Grassel CLA 2019-05-09 11:08:02 EDT
Master: https://github.com/eclipse-ee4j/eclipselink/pull/430
Comment 27 Joe Grassel CLA 2019-05-09 11:08:54 EDT
Disregard previous comment, wrong bug.
Comment 28 Eclipse Webmaster CLA 2022-06-09 10:10:46 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink