Date   

Currently do not support adding restriction on discriminator for table

Chris Colman
 

We've just migrated to version 5 and occasionally get the following warning:

Query                      - >> Currently do not support adding restriction on discriminator for table=mytableA f0 to class MyClassB

where:
mytableA is the table used to store a hierarchy of classes with 'MyClassA' as the base class
MyClassB is a class that extends MyClassA

I've looked at the DN source code where this message is produced but I can't really understand what the meaning of this is and if it is severe or can be safely ignored.
I don't recall ever seeing this in DN 4.

We use integer discriminators.

The metadata for MyClassA:
    <class name="MyClassA" detachable="true" persistence-modifier="persistence-capable" table="mytableA">
        <datastore-identity column="MYCLASSA_ID" />
        <inheritance strategy="new-table">
            <discriminator strategy="value-map" indexed="true">
                <column name="classid" jdbc-type="INTEGER" />
            </discriminator>
        </inheritance>
        <version strategy="version-number" column="VERSION" />
        ...
  </class>


MyClassB metadata:

    <class name="MyClassB" detachable="true" persistence-modifier="persistence-capable">
        <inheritance strategy="superclass-table">
            <discriminator value="17300">
            </discriminator>
        </inheritance>
 
        ...
    </class>


Re: Currently do not support adding restriction on discriminator for table

Chris Colman
 

More details:

In a non trivial JDOQL query the candidate class extends a base class that has a reference to MyClassA called, say myClassA.

Part of the query filter contains:

myClassA instanceof MyClassB

I think this is what is causing the warning message to be generated.

Is it saying that this part of the filter will be ignored?

Could it just translate to SQL like:

myClassA.classId in (17300)

Or is there something I've done wrong that makes it not possible for DN to generate this filtering SQL?


Re: Currently do not support adding restriction on discriminator for table

Andy
 

The LOG message is a WARNING, not an ERROR. Warning the users that something in their query is (likely) not completely handled.
The user is the only person who knows what that query is. Somewhere there is a CAST to some other type. But the query mechanism has no way of passing a BooleanExpression (whether the cast is valid) across to the next part of the query compilation. So in 5.x it logs a warning, rather than blindly ignoring the potential issue.


Re: Currently do not support adding restriction on discriminator for table

Chris Colman
 

It's good to know that it's just extra logging rather than something working differently in DN 5.x compared to DN 4.x

I have a condition in the filter using an 'instanceof':

myClassA is a reference to MyClassA which MyClassB extends

myClassA instanceof MyClassB

and then I do cast ((MyClassB)myClassA) in later parts of the JDOQL.

I realized that I have not imported the base class MyClassA into the query - I'll try that.


Re: Currently do not support adding restriction on discriminator for table

Chris Colman
 

Adding an import of the MyClassA into the query didn't avoid the warning.


Delete query with IN clause having a single parameter

prashant.mr@...
 

In our project, a Delete query is showing an error when used with IN clause having a single parameter.

I've forked the test-jpa project [1] and updated the SimpleTest.java [2] to recreate this issue.

The following query shows an error message: "Exception thrown when executing query : DELETE FROM PERSON A0 WHERE A0."NAME" = ? AND A0.ID ="

Query query = em.createQuery("DELETE FROM Person AS p where p.name = ?1 AND p.id IN (?2)");
query.setParameter(1, "Person1");
query.setParameter(2, 1);
query.executeUpdate();
But the following two similar queries work:

DELETE FROM Person AS p where p.id IN (?1) AND p.name = ?2

DELETE FROM Person AS p where p.name = ?1 AND p.id IN (?2, ?3)

I'd really appreciate any help to resolve this issue. Thanks.

[1] https://github.com/prashantbhat/test-jpa
[2] https://github.com/prashantbhat/test-jpa/blob/master/src/test/java/org/datanucleus/test/SimpleTest.java


Re: Delete query with IN clause having a single parameter

Andy
 

Care to post the actual exception + stack trace because it will tell you the problem. The log also tells you what the query is compiled to ... generic query, as well as the SQL.


Re: Delete query with IN clause having a single parameter

prashant.mr@...
 

Sorry, when trying to edit, I deleted the last message posted here.

I'm attaching the complete log file with only single run, this time.

Thanks,


Re: Delete query with IN clause having a single parameter

Andy
 

Generic compilation looks fine to me so suggest that you get the code for datanucleus-rdbms and start debugging around QueryToSQLMapper.processInExpression
https://github.com/datanucleus/datanucleus-rdbms/blob/master/src/main/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java


Re: DataNucleus Forum deletion

Andy
 

This is now deleted. RIP.


Re: Delete query with IN clause having a single parameter

prashant.mr@...
 

Thanks for pointing to the code for debugging. I'm quite new to the internals of DataNucleus, so it may take some time.


PostGIS with geographic types

Kevin A. Roll
 

I am attempting to map a simple point field into a PostGIS database. I’ve configured package.jdo according to the example. Schema tool is generating something like the following:

CREATE TABLE "IMAGESOURCE" ();
ALTER TABLE "IMAGESOURCE" ADD COLUMN "IMAGESOURCE_ID" SERIAL;
SELECT AddGeometryColumn( '', 'IMAGESOURCE', 'LOCATION', 4326, 'POINT', 2 );

This creates a column of type geometry in the database. PostGIS supports two geospatial types: geometry (plane-based) and geography (sphere-based). My desire is to use the geography type in order to get true distance-based results; is this possible using DataNucleus? To further confuse the issue, the docs for AddGeometryColumn don’t show a way to create a geography column - this can only be done with a direct create table statement. If I can’t get schema tool to do this automatically, can I alter the table afterwards and expect everything else to still work OK? Thanks!


Re: PostGIS with geographic types

Andy
 
Edited

Hi,
I presume you mean your java type is com.vividsolutions.jts.geom.Point ? This is currently only supported for persisting to PostGIS "geometry", as per http://www.datanucleus.org:15080/products/accessplatform_5_1/jdo/mapping.html#_geospatial_types  (page down to that java type).

The two people who contributed this support (back in 2006) didn't add anything for "geography" (maybe it didn't exist back in 2006?). Ought to be doable to support it, but I have no time so you'd have to get the code and add it.

Specifically, if you forked the datanucleus-geospatial project, and then look at this package https://github.com/datanucleus/datanucleus-geospatial/tree/master/src/main/java/org/datanucleus/store/types/geospatial/rdbms/mapping/jts2postgis
Each java field in a class will have a "JavaTypeMapping".
In the case of a JTS Point (using Geometry) that will be a https://github.com/datanucleus/datanucleus-geospatial/blob/master/src/main/java/org/datanucleus/store/types/geospatial/rdbms/mapping/jts/PointMapping.java This JavaTypeMapping, in turn, has an RDBMS mapping (equivalent of the column) ... in that case https://github.com/datanucleus/datanucleus-geospatial/blob/master/src/main/java/org/datanucleus/store/types/geospatial/rdbms/mapping/jts2postgis/PointRDBMSMapping.java 
Likely you'd need to add GeographyRDBMSMapping, and equivalent subclasses.

Then, back in your application, specify the JDO metadata for that field to use that sql-type
i.e <column name="..." sql-type="geography"/>
Once basic persistence and retrieval works, then there are query functions that would maybe need modifications/updates


If the java type is instead org.postgis.Point then the referenced package/classes above will be different.


HTH


Re: PostGIS with geographic types

Kevin A. Roll
 

Thanks Andy, that helps a lot. I actually tried all 3 types and settled on org.postgis.Point, but that is not written in stone. Given the complexity of this I may approach it another way... I might be able to get by with the planar distance measurements, or even pull in the points and do the calculation in-memory as I don't expect to have a very large dataset. Now I know where to look if I want to support this. Thanks again!
 


Re: Delete query with IN clause having a single parameter

prashant.mr@...
 

After some debugging, following is my analysis and a possible solution:

1) The valueType is not set for the symbol in ParameterExpression for parameter ?2 [1]
2) So, the JavTypeMapping used for the parameter will be null [2]
3) Because the mapping is null, the exprFactory creates a ParameterLiteral [3] which doesn't contain any value in SQLText (which actually should contain "?")

So this results in the query without the "?" appended for the parameter as: "DELETE FROM PERSON A0 WHERE A0."NAME" = ? AND A0.ID ="

I noticed that the valueType is set when the same expression is used as first parameter,
like "DELETE FROM Person AS p where p.id IN (?1) AND p.name = ?2".

A possible solution:

With the following change in DyadicExpression to detect the valueType for IN and NOTIN operators, the query works properly.

|| op == Expression.OP_IN || op == Expression.OP_NOTIN

Although the above change solves this particular use case, I'd like your review and feedback. And I'm not sure if this has any impact on other parts of library.
Please let me know, if I can send a pull request with the above change. Thanks.

[1] https://github.com/datanucleus/datanucleus-core/blob/59e3939509cf72c26e3459ef7ea02b4ea052aa13/src/main/java/org/datanucleus/query/expression/DyadicExpression.java#L194
[2] https://github.com/datanucleus/datanucleus-rdbms/blob/16e5d4cab0d4555c351d9cbc1b3cdd113aeb1431/src/main/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java#L4039
[3] https://github.com/datanucleus/datanucleus-rdbms/blob/16e5d4cab0d4555c351d9cbc1b3cdd113aeb1431/src/main/java/org/datanucleus/store/rdbms/sql/expression/SQLExpressionFactory.java#L389


Re: Delete query with IN clause having a single parameter

Andy
 
Edited

Updating DyadicExpression (or even updating general code in datanucleus-core) is not an option because it may affect other databases handling (and then would mean having to re-run ALL tests on all databases), and also because if the right expression is a LIST parameter then it is wrong.


Re: Delete query with IN clause having a single parameter

prashant.mr@...
 

Ok, I've now reworked on this, by making changes only to QueryToSQLMapper#processInExpression.

As in the processEqExpression, replacing the parameterLiteral with the left/right JavaTypeMapping is working for queries, listed in my original SimpleTest.java

I've included the diff here below for your review.

diff --git a/src/main/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java b/src/main/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java
index 5c4bdab9..fa8f6c2c 100644
--- a/src/main/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java
+++ b/src/main/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java
@@ -4761,7 +4761,14 @@ public class QueryToSQLMapper extends AbstractExpressionEvaluator implements Que
         else if (right.getParameterName() != null)
         {
             setNotPrecompilable();
-
+            if (left instanceof ParameterLiteral && !(right instanceof ParameterLiteral))
+            {
+                left = replaceParameterLiteral((ParameterLiteral)left, right.getJavaTypeMapping());
+            }
+            else if (right instanceof ParameterLiteral && !(left instanceof ParameterLiteral))
+            {
+                right = replaceParameterLiteral((ParameterLiteral)right, left.getJavaTypeMapping());
+            }
             // Single valued parameter, so use equality
             SQLExpression inExpr = new BooleanExpression(left, Expression.OP_EQ, right);
             stack.push(inExpr);


Re: Delete query with IN clause having a single parameter

Andy
 

I've added a variant of that to GitHub master that caters for single-valued parameter at left hand side or right hand side.


Re: Delete query with IN clause having a single parameter

prashant.mr@...
 

Thanks a lot


update/merge of transient object using allowAttachOfTransient in datanucleus(JDO) not working

bharani.s@...
 

Datanucleus document says...


datanucleus.allowAttachOfTransient

When you call PM.makePersistent with a transient object (with PK fields set), if you enable this feature then it will first check for existence of an object in the datastore with the same identity and, if present, will merge into that object (rather than just trying to persist a new object). {true, false} URL: http://www.datanucleus.org/products/datanucleus/jdo/persistence.html

However when executed results in unique constraint violation, as datanucleus tries to insert a record, instead of updating..

Code snippet..

    Account account = new account();
    account.setAccountNo(12345); //primary key - existing account in db
    account.setOtherAttribute("other attrib");
    persist (account);
    ......

    persist(account)
    {
    PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("Account");

        PersistenceManager pm = pmf.getPersistenceManager();
       pm.setProperty("datanucleus.allowAttachOfTransient", true);
       Transaction tx=pm.currentTransaction();
       try
       {
                tx.begin();
                pm.makePersistent(account);
                tx.commit();
        }
}


Can someone help?

Thanks & Regards
Bharani