JPA Exception "lastval() not supported" in Greenplum - jpa

My code is running fine in Postgres, but when I switched to Greenplum, the following exception occurs:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: lastval() not supported
Error Code: 0
Call: select lastval()
Query: ValueReadQuery(name="SEQ_GEN_IDENTITY" sql="select lastval()")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1620)
...
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:874)
at org.eclipse.persistence.internal.jpa.QueryImpl.performPreQueryFlush(QueryImpl.java:967)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:207)
at org.eclipse.persistence.internal.jpa.QueryImpl.getSingleResult(QueryImpl.java:521)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getSingleResult(EJBQueryImpl.java:400)
at module.AuthREST.login(AuthREST.java:103)
...
Caused by: org.postgresql.util.PSQLException: ERROR: lastval() not supported
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2157)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1886)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:555)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:302)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeSelect(DatabaseAccessor.java:1009)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:644)
This is User model class:
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id", nullable = false)
private Long id;
...
}
This is the code in AuthREST class:
...
#POST
#Path("login")
#Consumes({"application/x-www-form-urlencoded"})
public Response login(#Context HttpServletRequest request,
#Context HttpServletResponse response,
#FormParam("username") String username,
#FormParam("password") String password) {
request.login(username, password);
...
}
...
So how should i do avoid the exception in Greenplum?

The way sequences work in Greenplum:
the master has a "sequence server" running (if you look into the process list, you see a separate process)
every time a segment needs the next value from a sequence, it connects to the master and asks for the next value (this is overhead, by the way: http://engineering.pivotal.io/post/SERIAL_Datatype_Performance_in_Greenplum_Database/ )
The underlaying problem: the sequence server does not keep tab on the requests from the segment servers, therefore it does not know the last value (or values) per segment. Hence lastval() cannot be answered.
Even if the sequence server keeps a log of assigned sequence values: the way your query works, lastval() is executed on the master - but the master never actually inserted any data.
tl;dr: Retrieving the last value of a sequence in Greenplum is problematic. Even if lastval() is supported, the returned answer is likely not what you are looking for.

Reference your sequence table using sql last_value column. You can create your own last value function.
Example:
Select last_value from wcdl_dictionary.sq_dic_table_definition_table_id

Related

Spring Boot transactional test allows to violate unique constraint on update

I have a DB (Postgres) table with a unique constraint for one column. I have a test marked with #Transactional annotation, that updates that unique column value to a not unique value. I expect that the update operation should fail, but it executes successfully. Moreover, when I get updated object from the database (inside the same transaction), the column value is updated there.
The simplified version of JPA entity:
#Entity
#Table(name = "entities")
public class Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// The unique column
#Column(name = "name", unique = true)
#NotNull
private String name;
...
}
The simplified version for the test:
#Test
#Transactional
public void test() {
Entity firstEntity = new Entity();
firstEntity.setName("First Entity Name");
// This just calls corresponding JPA repository .save method
entityService.create(firstEntity);
Entity secondEntity = new Entity();
secondEntity.setName("Second Entity Name");
entityService.create(secondEntity);
// Update name to a not unique value
secondEntity.setName(firstEntity.getName);
// This calls corresponding JPA repository .save method.
// It also catches DataIntegrityViolationException and throws
// a more user friendly exception instead
entityService.update(secondEntity);
}
This code works as I expect, if #Transactional annotation is removed or transaction is committed. I also tried to call EntityManager.flush(), as advised here, but this code throws ConstraintViolationException after resulting data is flushed, so I can't test that my entityService.update method works correctly and throws proper exception.
Please also note that if I try to create a new entry with not unique data in transactional test (not update), then test works as expected -
DataIntegrityViolationException is thrown when not unique entity is created.
Could somebody clarify if it is possible to make update scenario work as expected keeping test transactional so I don't need to care about data clean up?

Postgres insert record with Sequence generates error - org.postgresql.util.PSQLException: ERROR: relation "dual" does not exist

I am new to Postgres database.
I have a Java Entity class with the below column for ID:
#Entity
#Table(name = "THE_RULES")
public class TheRulesEntity {
/** The id. */
#Column(name = "TEST_NO", precision = 8)
#SequenceGenerator(name = "test_no_seq", sequenceName = "TEST_NO_SEQ")
#GeneratedValue(generator = "test_no_seq", strategy = GenerationType.AUTO)
#Id
private Long id;
/** The test val. */
#Column(name = "TEST_VAL", nullable = false, length = 3)
private String testVal;
Code:
rulesRepository.saveAndFlush(theRulesEntity)
Table:
CREATE TABLE THE_RULES
(
TEST_NO INT NOT NULL,
TEST_VAL VARCHAR(3) NOT NULL
)
CREATE SEQUENCE "TEST_NO_SEQ" START WITH 1000 INCREMENT BY 1;
When I try to insert a new record into the postgres database from my application (the ID value is null in Java code during Debug mode), then I get the below error:
Caused by: org.postgresql.util.PSQLException: ERROR: relation "dual" does not exist
But If I insert the record manually into database table and then update the record from my application, then the record is updated successfully (Probably because the application uses the same ID value so no need to refer to the Sequence TEST_NO_SEQ value anymore)
Looks like the database is not able to access the sequence from dual table.
Could anyone help me how to fix this?
Thanks.
Thanks to Joop and a_horse_with_no_name, the issue is resolved
I have used Oracle driver which is wrong. I have updated my code to use Postgres driver
I created the Sequence again in the database with same name but without the Quotes
I used all capital-case letters in my Java entity class to refer to the sequence correctly

JPA and Postgres sequence pre-allocation size setup incorrectly

I am not able to perist any Entity because of a problem with sequence. I use Glssfish 4, Postgres 9.3 + JPA + EJB3 and Netbeans 8.
Below the excpeption:
Finest: persist() operation called on: MyUser{id=null, email=a#e.it, password=test, firstname=test, lastname=test, company=Test}.
Finest: Execute query ValueReadQuery(sql="select nextval('mom_seq_id')")
Finest: Connection acquired from connection pool [read].
Finest: reconnecting to external connection pool
Fine: select nextval(mom_seq_id)
Finest: Connection released to connection pool [read].
Warning: Local Exception Stack:
Exception [EclipseLink-7027] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The sequence named [mom_seq_id] is setup incorrectly. Its increment does not match its pre-allocation size.
at org.eclipse.persistence.exceptions.ValidationException.sequenceSetupIncorrectly(ValidationException.java:1604)
at org.eclipse.persistence.sequencing.StandardSequence.createVector(StandardSequence.java:96)
...
The sequence on Postgres:
CREATE SEQUENCE my_seq_id
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 27
CACHE 1;
ALTER TABLE my_seq_id
OWNER TO postgres;
COMMENT ON SEQUENCE my_seq_id
IS 'Sequence for autoincrement id on MyClass';
And an extract of my Entity:
#Entity
#Table(name = "myuser")
#XmlRootElement
public class MyUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="MYSEQ",
sequenceName="my_seq_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="MYSEQ")
#Basic(optional = false)
#Column(name = "id")
private Integer id;
Can anyone explain what is wrong?
Thanks
I resolved my issue but I don't know why! I saw that the default value of allocationSize() is 50:
package javax.persistence;
#Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
public #interface SequenceGenerator {
public String name();
public String sequenceName() default "";
public String catalog() default "";
public String schema() default "";
public int initialValue() default 1;
public int allocationSize() default 50;
}
And I have updated my Postgres sequence increment_by value from 1 to 50 and now it works!
For reasons beyond my understanding, the JPA spec picked 50 as the default increment for a sequence generator.
PostgreSQL defaults to 1.
If the two don't match, things get ugly, because JPA thinks it can use values that someone else also thinks they have assigned. At least EclipseLink detects this; Hibernate just goes on merrily trying to re-use already assigned keys.
If your sequence is:
CREATE SEQUENCE my_seq_id
INCREMENT 1
then your mapping must reflect that:
#SequenceGenerator(name="MYSEQ",
sequenceName="my_seq_id", allocationSize=1)
I strongly suggest being explicit about the increment, even if you leave it at the default of 50 and alter the PostgreSQL sequence instead. It'll save your and others' sanity when debugging later.
Changing the value of INCREMENT from 1 to 50 into my Postgres sequence resolved the issue. As suggested by #unwichtich it is a good idea to specify allocationSize=50 attribute through the #SequenceGenerator annotation.

ORACLE AUTO INCREMENT jpa

i have prob with mapping sequence auto increment
#GeneratedValue(strategy=GenerationType.SEQUENCE)
i'm using on sql developer it work but when i try on netbeans i get the message
Caused by: java.lang.NullPointerException
Create a sequence named SOME_SEQ in your db for this particular table. And use the annotations above your id field. allocationSize=1 means increment the value by 1. And some_seq_gen_name is for unique labeling.
#Id
#Column(name = "id")
#GeneratedValue(generator="some_seq_gen_name")
#SequenceGenerator(name="some_seq_gen_name", sequenceName="SOME_SEQ", allocationSize=1)
private Long id;
UPDATE: Based on your comment, for commit try this one:
EntityTransaction et = em.getTransaction();
et.begin();
// write persist code here
et.commit();

JPA Using sequences as auto increment postgres

I have this code:
#Entity
#Table(name = "table")
#SequenceGenerator(name="table_id_seq", sequenceName="table_id_seq", allocationSize=1)
public class TableExample extends BaseEntity implements Serializable {
/**
* The auto-generated primary key.
*/
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="table_id_seq")
#Column(name = "table_id")
private long id;
}
And I have this SEQUENCE in my database:
CREATE SEQUENCE table_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 2000
CACHE 1;
ALTER TABLE table_id_seq OWNER TO postgres;
When I am trying to persist a new object, I get this error:
org.apache.openjpa.persistence.PersistenceException: ERROR: current
transaction is aborted, commands ignored until end of transaction
block {prepstmnt 642363 SELECT NEXTVAL('table_id_seq')} [code=0,
state=25P02]
Am I missing something??
Thanks in advance
The error arose before that code; there's another problem earlier else that caused the transaction to be aborted. Examine your PostgreSQL server error logs or Hibernate/JPA logs to see where the FIRST error occurred, that'll be the real problem.