Compare commits

..
24 Commits
Author SHA1 Message Date
Rob Bygrave d051bba71f Version 13.20.1 2023-07-04 12:05:30 +12:00
Rob Bygrave f414f04033 Add note on lack of support for InTuples with SQLServer and DB2 2023-07-04 12:05:10 +12:00
Rob Bygrave ac466ecd79 #3125 Add query.usingMaster() for query beans 2023-07-03 23:30:02 +12:00
Rob Bygrave 262a7f9bab Bump ebean-agent version 2023-07-03 22:57:55 +12:00
Rob BygraveandGitHub bb02d74005 Merge pull request #3125 from ebean-orm/feature/query-usingMaster
Add query.usingMaster() to explicitly choose master data source
2023-07-03 22:48:47 +12:00
Rob BygraveandGitHub e9b2b8d266 Merge pull request #3017 from ebean-orm/feature/db2luw9
Initial DB2Luw9Platform using row_number() for row limiting sql
2023-07-03 22:43:55 +12:00
Rob Bygrave fc16bde227 Modify ImplicitReadOnlyTransaction, call deactivate in finally 2023-07-03 22:43:13 +12:00
Rob Bygrave d1775dfcc4 #3017 Change DB2LegacyPlatform to also use the row_number limiters 2023-07-03 22:35:46 +12:00
3d5937f6da Update platforms/db2/src/main/java/io/ebean/platform/db2/DB2RowNumberBasicLimiter.java
Bump StringBuilder to use 120

Co-authored-by: Roland Praml <roland.praml@foconis.de>
2023-07-03 22:31:01 +12:00
Rob BygraveandGitHub adca8cd8fa Merge branch 'master' into feature/db2luw9 2023-07-03 22:28:43 +12:00
Rob BygraveandGitHub 6d30e6310b Merge pull request #3127 from ebean-orm/feature/3126
#3126 - Incorrect complex indexes generation
2023-07-03 22:22:32 +12:00
Rob Bygrave 79ed0a5f8e #3126 - Incorrect complex indexes generation 2023-07-03 22:19:38 +12:00
Rob Bygrave 94b3a020d5 Modify ImplicitReadOnlyTransaction useCommit to check connection.getAutoCommit() 2023-07-03 21:40:21 +12:00
Rob Bygrave 3e241907e6 Modify internal ImplicitReadOnlyTransaction to also support calling commit()
Originally, ImplicitReadOnlyTransaction was built to support read-only DataSource where the connections are using autoCommit true. This change modified ImplicitReadOnlyTransaction to also support use with the main DataSource where the connection are not using autoCommit true.

This is also now needed for the query.usingMaster() case where we have an implicit read only transaction but use the main DataSource with underlying connection requiring explicit commit() at the end of the transaction.
2023-07-03 21:27:58 +12:00
Rob Bygrave c4af1d9b23 Add query.usingMaster() to explicitly choose master data source
When we have a read replica with potential for replication lag, and config a read only DataSource to use that read replica, by default a query executed without a current transaction will use the read replica.

We specify usingMaster() when we explicitly want to execute a query and use the master data source.
2023-07-03 16:41:22 +12:00
Rob BygraveandGitHub 7702169762 Merge pull request #3124 from ebean-orm/feature/InTuples
Add InTuples expression for multi-column IN expression
2023-07-03 12:48:21 +12:00
Rob Bygrave 8209d9e229 Add SpiInTuples to hide more details from InTuples 2023-07-03 12:41:31 +12:00
Rob Bygrave 664120f369 Add InTuples expression for multi-column IN expression 2023-07-03 11:54:38 +12:00
Rob Bygrave e952b555e0 Add InTuples expression for multi-column IN expression 2023-07-03 11:49:53 +12:00
Rob BygraveandGitHub d99c50da75 Merge pull request #3122 from ebean-orm/feature/3109-jta-txn-fix
#3109 Fix for JtaTransactionManager when no active transaction
2023-06-26 21:30:55 +12:00
Rob Bygrave d4bec166f7 #3109 Fix for JtaTransactionManager when no active transaction
The call to registry() can throw an exception so
pulling that inside the try catch block and handle
that as no active transaction returning null.
2023-06-26 21:30:01 +12:00
Rob Bygrave 9a4b9d4bec Bump to next snapshot version 2023-06-21 07:08:13 +12:00
Rob Bygrave 63a23904ac Update for DB2Luw9 with rn column as last column 2023-04-13 21:52:09 +12:00
Rob Bygrave 1807fc201e Initial DB2Luw9Platform using row_number() for row limiting sql 2023-03-30 22:56:55 +13:00
103 changed files with 908 additions and 244 deletions
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-clickhouse</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-cockroach</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-db2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-h2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-hana</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-mariadb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-mysql</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-nuodb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-oracle</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-postgres</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-sqlite</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-sqlserver</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean-yugabyte</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -41,13 +41,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean (all platforms)</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -40,7 +40,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -59,13 +59,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>composites</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean api</name>
@@ -0,0 +1,49 @@
package io.ebean;
import io.ebean.service.SpiInTuples;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Default implementation of SpiInTuples.
*/
final class DInTuples implements SpiInTuples {
private final String[] properties;
private final int propertyCount;
private final List<Object[]> entries = new ArrayList<>();
DInTuples(String[] properties) {
this.properties = properties;
this.propertyCount = properties.length;
}
@Override
public InTuples add(Object... values) {
if (values.length != propertyCount) {
throw new IllegalArgumentException("Require " + propertyCount + " values but got " + values.length);
}
entries.add(values);
return this;
}
/**
* Return the first property name.
*/
@Override
public String[] properties() {
return properties;
}
/**
* Return all the value pairs.
*/
@Override
public List<Object[]> entries() {
return Collections.unmodifiableList(entries);
}
}
@@ -205,4 +205,16 @@ public interface DtoQuery<T> extends CancelableQuery {
* Use the explicit transaction to execute the query.
*/
DtoQuery<T> usingTransaction(Transaction transaction);
/**
* Ensure that the master DataSource is used if there is a read only data source
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
DtoQuery<T> usingMaster();
}
@@ -369,6 +369,11 @@ public interface ExpressionFactory {
*/
Expression inPairs(Pairs pairs);
/**
* In expression using multiple columns.
*/
Expression inTuples(InTuples pairs);
/**
* In - property has a value in the array of values.
*/
@@ -1131,6 +1131,11 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> inPairs(Pairs pairs);
/**
* In expression using multiple columns.
*/
ExpressionList<T> inTuples(InTuples pairs);
/**
* EXISTS a raw SQL SubQuery.
*
@@ -0,0 +1,36 @@
package io.ebean;
/**
* IN expression using multiple columns.
* <p>
* Currently this is not supported with SQLServer or DB2.
* <p>
* Produces SQL expression in the form of (A,B,C) IN ((a0,b0,c0), (a1,b1,c1), ... )
* where A,B,C are the properties in the tuples.
*/
public interface InTuples {
/**
* Create given the properties in the tuples.
*/
static InTuples of(String... properties) {
return new DInTuples(properties);
}
/**
* Create given the properties in the tuples.
*/
static InTuples of(Query.Property<?>... properties) {
String[] props = new String[properties.length];
for (int i = 0; i < properties.length; i++) {
props[i] = properties[i].toString();
}
return new DInTuples(props);
}
/**
* Add a tuple entry. All values must be non-null.
*/
InTuples add(Object... values);
}
@@ -4,6 +4,7 @@ import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import javax.persistence.NonUniqueResultException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.List;
@@ -685,6 +686,18 @@ public interface Query<T> extends CancelableQuery {
*/
Query<T> usingDatabase(Database database);
/**
* Ensure that the master DataSource is used if there is a read only data source
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
Query<T> usingMaster();
/**
* Execute the query returning the list of Id's.
* <p>
@@ -45,6 +45,18 @@ public interface SqlQuery extends Serializable, CancelableQuery {
*/
SqlQuery usingTransaction(Transaction transaction);
/**
* Ensure that the master DataSource is used if there is a read only data source
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
SqlQuery usingMaster();
/**
* Execute the query returning a list.
*/
@@ -135,7 +135,7 @@ public class DbConstraintNaming {
*/
protected String joinColumnNames(String[] columns) {
if (columns.length == 1) {
return normaliseColumn(columns[0]);
return normaliseColumn(columns[0]).replace(" ", "_");
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < columns.length; i++) {
@@ -0,0 +1,22 @@
package io.ebean.service;
import io.ebean.InTuples;
import java.util.List;
/**
* Internal extension to InTuples.
*/
public interface SpiInTuples extends InTuples {
/**
* Return the properties of the tuples.
*/
String[] properties();
/**
* Return all the tuple entries.
*/
List<Object[]> entries();
}
+25 -25
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean bom</name>
@@ -89,25 +89,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -125,13 +125,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -155,46 +155,46 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<!-- platforms -->
@@ -202,67 +202,67 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
+6 -6
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -46,7 +46,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -159,21 +159,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
@@ -135,8 +135,9 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, BeanCollectio
* Create a ServerTransaction for query purposes.
*
* @param tenantId For multi-tenant lazy loading provide the tenantId to use.
* @param useMaster Set to true when the query should use the master data source.
*/
SpiTransaction createReadOnlyTransaction(Object tenantId);
SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster);
/**
* An event from another server in the cluster used to notify local
@@ -235,6 +235,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
String planLabel();
/**
* Return true if this query should not use the read only data source.
*/
boolean isUseMaster();
/**
* Return true if this is a "find by id" query. This includes a check for a single "equal to" expression for the Id.
*/
@@ -5,6 +5,11 @@ package io.ebeaninternal.api;
*/
public interface SpiSqlBinding extends SpiCancelableQuery {
/**
* Return true if this query should not use the read only data source.
*/
boolean isUseMaster();
/**
* Return the named or positioned parameters.
*/
@@ -48,7 +48,7 @@ public abstract class AbstractSqlQueryRequest implements CancelableQuery {
transaction = server.currentServerTransaction();
if (transaction == null || !transaction.isActive()) {
// create a local readOnly transaction
transaction = server.createReadOnlyTransaction(null);
transaction = server.createReadOnlyTransaction(null, query.isUseMaster());
createdTransaction = true;
}
}
@@ -137,7 +137,7 @@ final class DefaultBeanLoader {
private List<?> executeQuery(LoadRequest loadRequest, SpiQuery<?> query) {
if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) {
// MySql - we need a different transaction to execute the secondary query
SpiTransaction extraTxn = server.createReadOnlyTransaction(query.tenantId());
SpiTransaction extraTxn = server.createReadOnlyTransaction(query.tenantId(), query.isUseMaster());
try {
return server.findList(query, extraTxn);
} finally {
@@ -2123,8 +2123,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
return transactionManager.createReadOnlyTransaction(tenantId);
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
return transactionManager.createReadOnlyTransaction(tenantId, useMaster);
}
/**
@@ -56,7 +56,10 @@ final class MultiTenantDbCatalogSupplier implements DataSourceSupplier {
}
@Override
public Connection readOnlyConnection(Object tenantId) throws SQLException {
public Connection readOnlyConnection(Object tenantId, boolean useMaster) throws SQLException {
if (readOnly == null || useMaster) {
return catalogDataSource.getConnectionForTenant(tenantId);
}
return readOnly.getConnectionForTenant(tenantId);
}
@@ -103,7 +106,6 @@ final class MultiTenantDbCatalogSupplier implements DataSourceSupplier {
*/
@Override
public Connection getConnection() throws SQLException {
Connection connection = dataSource.getConnection();
connection.setCatalog(tenantCatalog());
return connection;
@@ -56,8 +56,12 @@ final class MultiTenantDbSchemaSupplier implements DataSourceSupplier {
}
@Override
public Connection readOnlyConnection(Object tenantId) throws SQLException {
return readOnly.getConnectionForTenant(tenantId);
public Connection readOnlyConnection(Object tenantId, boolean useMaster) throws SQLException {
if (readOnly == null || useMaster) {
return schemaDataSource.getConnectionForTenant(tenantId);
} else {
return readOnly.getConnectionForTenant(tenantId);
}
}
@Override
@@ -106,7 +110,6 @@ final class MultiTenantDbSchemaSupplier implements DataSourceSupplier {
*/
@Override
public Connection getConnection() throws SQLException {
Connection connection = dataSource.getConnection();
connection.setSchema(tenantSchema());
return connection;
@@ -43,8 +43,8 @@ final class MultiTenantDbSupplier implements DataSourceSupplier {
}
@Override
public Connection readOnlyConnection(Object tenantId) throws SQLException {
throw new SQLException("Not currently supported");
public Connection readOnlyConnection(Object tenantId, boolean useMaster) throws SQLException {
return dataSourceProvider.dataSource(tenantId).getConnection();
}
@Override
@@ -220,7 +220,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
} else {
// create an implicit transaction to execute this query
// potentially using read-only DataSource with autoCommit
transaction = server.createReadOnlyTransaction(query.tenantId());
transaction = server.createReadOnlyTransaction(query.tenantId(), query.isUseMaster());
}
createdTransaction = true;
}
@@ -41,8 +41,12 @@ final class SimpleDataSourceProvider implements DataSourceSupplier {
}
@Override
public Connection readOnlyConnection(Object tenantId) throws SQLException {
return readOnlyDataSource.getConnection();
public Connection readOnlyConnection(Object tenantId, boolean useMaster) throws SQLException {
if (readOnlyDataSource == null || useMaster) {
return dataSource.getConnection();
} else {
return readOnlyDataSource.getConnection();
}
}
@Override
@@ -471,6 +471,11 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
return new InPairsExpression(pairs, false);
}
@Override
public Expression inTuples(InTuples pairs) {
return new InTuplesExpression(pairs, false);
}
/**
* In - property has a value in the array of values.
*/
@@ -902,6 +902,10 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return add(expr.inPairs(pairs));
}
@Override
public ExpressionList<T> inTuples(InTuples pairs) {
return add(expr.inTuples(pairs));
}
@Override
public ExpressionList<T> exists(String sqlSubQuery, Object... bindValues) {
@@ -0,0 +1,116 @@
package io.ebeaninternal.server.expression;
import io.ebean.InTuples;
import io.ebean.service.SpiInTuples;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.util.List;
import static java.util.Objects.requireNonNull;
final class InTuplesExpression extends AbstractExpression {
private final boolean not;
private final String[] properties;
private final List<Object[]> entries;
InTuplesExpression(InTuples pairs, boolean not) {
super("");
SpiInTuples inTuples = (SpiInTuples)pairs;
this.properties = inTuples.properties();
// the entries might be modified on cache hit.
this.entries = inTuples.entries();
this.not = not;
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
return false;
}
@Override
public void writeDocQuery(DocQueryContext context) {
throw new RuntimeException("Not supported with document query");
}
@Override
public void addBindValues(SpiExpressionRequest request) {
for (Object[] entry : entries) {
for (Object value : entry) {
requireNonNull(value);
request.addBindValue(value);
}
}
}
@Override
public void addSql(SpiExpressionRequest request) {
if (entries.isEmpty()) {
request.append(not ? SQL_TRUE : SQL_FALSE);
return;
}
request.append("(");
for (int i = 0; i < properties.length; i++) {
if (i > 0) {
request.append(",");
}
request.property(properties[i]);
}
request.append(") in (");
final String eb = entryBinding();
for (int i = 0; i < entries.size(); i++) {
if (i > 0) {
request.append(",");
}
request.append(eb);
}
request.append(")");
}
private String entryBinding() {
StringBuilder sb = new StringBuilder();
sb.append('(');
for (int i = 0; i < properties.length; i++) {
if (i > 0) {
sb.append(',');
}
sb.append('?');
}
return sb.append(')').toString();
}
/**
* Based on the number of values in the in clause.
*/
@Override
public void queryPlanHash(StringBuilder builder) {
if (not) {
builder.append("Not");
}
builder.append("InTuple[");
for (String property : properties) {
builder.append(property).append("-");
}
builder.append(entries.size()).append("]");
}
@Override
public void queryBindKey(BindValuesKey key) {
key.add(entries.size());
for (Object[] entry : entries) {
for (Object value : entry) {
key.add(value);
}
}
}
@Override
public boolean isSameByBind(SpiExpression other) {
InTuplesExpression that = (InTuplesExpression) other;
return this.entries.size() == that.entries.size() && entries.equals(that.entries);
}
}
@@ -710,6 +710,11 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.inPairs(pairs);
}
@Override
public ExpressionList<T> inTuples(InTuples pairs) {
return exprList.inTuples(pairs);
}
@Override
public ExpressionList<T> in(String propertyName, Collection<?> values) {
return exprList.in(propertyName, values);
@@ -234,6 +234,11 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public Query<T> usingMaster() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public <A> List<A> findIds() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -18,6 +18,7 @@ public class AbstractQuery implements SpiCancelableQuery {
private final ReentrantLock lock = new ReentrantLock();
private boolean cancelled;
private CancelableQuery cancelableQuery;
protected boolean useMaster;
@Override
public final void cancel() {
@@ -48,6 +48,7 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
this.server = server;
this.descriptor = descriptor;
this.ormQuery = ormQuery;
this.useMaster = ormQuery.isUseMaster();
this.label = ormQuery.label();
this.profileLocation = ormQuery.profileLocation();
}
@@ -88,6 +89,17 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
return this;
}
@Override
public DtoQuery<T> usingMaster() {
this.useMaster = true;
return this;
}
@Override
public boolean isUseMaster() {
return useMaster;
}
@Override
public void findEach(Consumer<T> consumer) {
server.findDtoEach(this, consumer);
@@ -715,6 +715,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
// forUpdate is NOT copied - see #2762
DefaultOrmQuery<T> copy = new DefaultOrmQuery<>(beanDescriptor, server, expressionFactory);
copy.transaction = transaction;
copy.useMaster = useMaster;
copy.m2mIncludeJoin = m2mIncludeJoin;
copy.profilingListener = profilingListener;
copy.profileLocation = profileLocation;
@@ -1396,6 +1397,17 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return this;
}
@Override
public Query<T> usingMaster() {
this.useMaster = true;
return this;
}
@Override
public boolean isUseMaster() {
return useMaster;
}
@Override
public final int delete() {
return server.delete(this, transaction);
@@ -49,6 +49,17 @@ public final class DefaultRelationalQuery extends AbstractQuery implements SpiSq
return this;
}
@Override
public SqlQuery usingMaster() {
this.useMaster = true;
return this;
}
@Override
public boolean isUseMaster() {
return useMaster;
}
private void transaction(Transaction transaction) {
this.transaction = transaction;
}
@@ -43,10 +43,11 @@ public interface DataSourceSupplier {
/**
* Return a connection from the read only DataSource taking into account a tenantId for multi-tenant lazy loading.
*
* @param tenantId Most often null but well supplied indicates a multi-tenant lazy loading query
* @param tenantId Most often null but well supplied indicates a multi-tenant lazy loading query
* @param useMaster When true use the master data source
* @return the connection to use
*/
Connection readOnlyConnection(Object tenantId) throws SQLException;
Connection readOnlyConnection(Object tenantId, boolean useMaster) throws SQLException;
/**
* Shutdown the datasource de-registering the JDBC driver if requested.
@@ -24,7 +24,7 @@ public final class DocStoreTransactionManager extends TransactionManager {
}
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
return new DocStoreOnlyTransaction(false, this);
}
@@ -32,6 +32,10 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
private static final String illegalStateMessage = "Transaction is Inactive";
private static final String notExpectedMessage = "Not expected on read only transaction";
/**
* Set false when using autoCommit (as a performance optimisation for the read-only case).
*/
private final boolean useCommit;
private final TransactionManager manager;
private final SpiTxnLogger logger;
private final boolean logSql;
@@ -60,7 +64,7 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
/**
* Create without a tenantId.
*/
ImplicitReadOnlyTransaction(TransactionManager manager, Connection connection) {
ImplicitReadOnlyTransaction(boolean useCommit, TransactionManager manager, Connection connection) {
this.manager = manager;
this.logger = manager.loggerReadOnly();
this.logSql = logger.isLogSql();
@@ -69,13 +73,18 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
this.connection = connection;
this.persistenceContext = new DefaultPersistenceContext();
this.startNanos = System.nanoTime();
try {
this.useCommit = useCommit && !connection.getAutoCommit();
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
/**
* Create with a tenantId.
*/
ImplicitReadOnlyTransaction(TransactionManager manager, Connection connection, Object tenantId) {
this(manager, connection);
this(true, manager, connection);
this.tenantId = tenantId;
}
@@ -505,16 +514,22 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
// do nothing, expect AutoCommit
}
/**
* Commit the transaction.
*/
@Override
public void commit() {
if (!active) {
throw new IllegalStateException(illegalStateMessage);
}
// expect AutoCommit so just deactivate / put back into pool
deactivate();
try {
if (useCommit) {
try {
connection.commit();
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
} finally {
deactivate();
}
}
/**
@@ -556,8 +571,17 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
if (!active) {
throw new IllegalStateException(illegalStateMessage);
}
// expect AutoCommit so it really has already committed
deactivate();
try {
if (useCommit) {
try {
connection.rollback();
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
} finally {
deactivate();
}
}
/**
@@ -565,7 +589,7 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
*/
@Override
public void end() throws PersistenceException {
if (isActive()) {
if (active) {
rollback();
}
}
@@ -78,8 +78,9 @@ public final class JtaTransactionManager implements ExternalTransactionManager {
*/
@Override
public Object getCurrentTransaction() {
TransactionSynchronizationRegistry syncRegistry = registry();
TransactionSynchronizationRegistry syncRegistry;
try {
syncRegistry = registry();
SpiTransaction t = (SpiTransaction) syncRegistry.getResource(EBEAN_TXN_RESOURCE);
if (t != null) {
// we have already seen this transaction
@@ -21,9 +21,10 @@ abstract class TransactionFactory {
/**
* Return a new query only transaction.
*
* @param tenantId The tenantId for lazy loading queries.
* @param tenantId The tenantId for lazy loading queries.
* @param useMaster Explicitly use the master data source rather than read only data source
*/
abstract SpiTransaction createReadOnlyTransaction(Object tenantId);
abstract SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster);
/**
* Return a new transaction.
@@ -13,7 +13,7 @@ import java.sql.SQLException;
*/
class TransactionFactoryBasic extends TransactionFactory {
private final DataSource dataSource;
protected final DataSource dataSource;
TransactionFactoryBasic(TransactionManager manager, DataSourceSupplier dataSourceSupplier) {
super(manager);
@@ -21,12 +21,11 @@ class TransactionFactoryBasic extends TransactionFactory {
}
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
Connection connection = null;
try {
connection = dataSource.getConnection();
return create(false, connection);
return new ImplicitReadOnlyTransaction(true, manager, connection);
} catch (PersistenceException ex) {
JdbcClose.close(connection);
throw ex;
@@ -26,11 +26,11 @@ final class TransactionFactoryBasicWithRead extends TransactionFactoryBasic {
}
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
Connection connection = null;
try {
connection = readOnlyDataSource.getConnection();
return new ImplicitReadOnlyTransaction(manager, connection);
connection = useMaster ? dataSource.getConnection() : readOnlyDataSource.getConnection();
return new ImplicitReadOnlyTransaction(useMaster, manager, connection);
} catch (PersistenceException ex) {
JdbcClose.close(connection);
throw ex;
@@ -11,7 +11,6 @@ final class TransactionFactoryBuilder {
* Build and return based on multi-tenancy and read only DataSource.
*/
static TransactionFactory build(TransactionManager manager, DataSourceSupplier dataSourceSupplier, CurrentTenantProvider tenantProvider) {
boolean hasReadOnlyDataSource = dataSourceSupplier.readOnlyDataSource() != null;
if (tenantProvider == null) {
if (hasReadOnlyDataSource) {
@@ -24,7 +24,7 @@ class TransactionFactoryTenant extends TransactionFactory {
}
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
return create(false, tenantId);
}
@@ -23,14 +23,14 @@ final class TransactionFactoryTenantWithRead extends TransactionFactoryTenant {
}
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
Connection connection = null;
try {
if (tenantId == null) {
// obtain the tenantId if the DataSource requires it
tenantId = dataSourceSupplier.currentTenantId();
}
connection = dataSourceSupplier.readOnlyConnection(tenantId);
connection = dataSourceSupplier.readOnlyConnection(tenantId, useMaster);
return new ImplicitReadOnlyTransaction(manager, connection, tenantId);
} catch (PersistenceException ex) {
JdbcClose.close(connection);
@@ -274,7 +274,7 @@ public class TransactionManager implements SpiTransactionManager {
private SpiTransaction createTransaction(TxScope txScope) {
if (txScope.isReadonly()) {
return createReadOnlyTransaction(null);
return createReadOnlyTransaction(null, false);
} else {
return createTransaction(true, txScope.getIsolationLevel());
}
@@ -290,8 +290,8 @@ public class TransactionManager implements SpiTransactionManager {
/**
* Create a new Transaction for query only purposes (can use read only datasource).
*/
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
return transactionFactory.createReadOnlyTransaction(tenantId);
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
return transactionFactory.createReadOnlyTransaction(tenantId, useMaster);
}
/**
@@ -0,0 +1,62 @@
package io.ebeaninternal.server.transaction;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiTxnLogger;
import org.junit.jupiter.api.Test;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
class TransactionFactoryBasicWithReadTest {
@Test
void createReadOnlyTransaction_expect_usesMasterDataSource() throws SQLException {
var connection = mock(Connection.class);
var tm = mockTransactionManager();
var dataSource = mockDataSource(connection);
var dss = mock(DataSourceSupplier.class);
when(dss.dataSource()).thenReturn(dataSource);
var txnFactory = new TransactionFactoryBasicWithRead(tm, dss);
// act
SpiTransaction txn = txnFactory.createReadOnlyTransaction(null, true);
assertThat(txn).isNotNull();
verify(dataSource).getConnection(); // used the 'master' dataSource
}
@Test
void createReadOnlyTransaction_expect_usesReadOnlyDataSource() throws SQLException {
var tm = mockTransactionManager();
var connection = mock(Connection.class);
var readOnlyDataSource = mockDataSource(connection);
var dss = mock(DataSourceSupplier.class);
when(dss.readOnlyDataSource()).thenReturn(readOnlyDataSource);
var txnFactory = new TransactionFactoryBasicWithRead(tm, dss);
// act
SpiTransaction txn = txnFactory.createReadOnlyTransaction(null, false);
assertThat(txn).isNotNull();
verify(readOnlyDataSource).getConnection(); // used the 'read only' dataSource
}
private static DataSource mockDataSource(Connection dsConnection) throws SQLException {
var readOnlyDataSource = mock(DataSource.class);
when(readOnlyDataSource.getConnection()).thenReturn(dsConnection);
return readOnlyDataSource;
}
private static TransactionManager mockTransactionManager() {
var tm = mock(TransactionManager.class);
when(tm.loggerReadOnly()).thenReturn(mock(SpiTxnLogger.class));
return tm;
}
}
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
@@ -72,7 +72,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean postgis</name>
@@ -22,14 +22,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
@@ -65,7 +65,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
@@ -63,21 +63,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
@@ -12,6 +12,7 @@ import io.ebean.text.PathProperties;
import io.ebeaninternal.api.SpiQueryFetch;
import io.ebeaninternal.server.util.ArrayStack;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.*;
@@ -1219,6 +1220,14 @@ public abstract class TQRootBean<T, R> {
return root;
}
/**
* In expression using multiple columns.
*/
public R inTuples(InTuples inTuples) {
peekExprList().inTuples(inTuples);
return root;
}
/**
* Marker that can be used to indicate that the order by clause is defined after this.
* <p>
@@ -1552,6 +1561,21 @@ public abstract class TQRootBean<T, R> {
return root;
}
/**
* Ensure that the master DataSource is used if there is a read only data source
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
public R usingMaster() {
query.usingMaster();
return root;
}
/**
* Execute the query returning true if a row is found.
* <p>
@@ -1,12 +1,35 @@
package org.querytest;
import io.ebean.InTuples;
import org.example.domain.query.QContact;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import static org.assertj.core.api.Assertions.assertThat;
public class QContactTest {
@Test
void findInTuples() {
var c = QContact.alias();
InTuples inTuples = InTuples.of(c.firstName, c.lastName)
.add("Rob", "B")
.add("Bob", "C")
.add("Mob", "D");
var query = new QContact()
.firstName.isNotNull()
.email.isNotNull()
.inTuples(inTuples)
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("(t0.first_name,t0.last_name) in ((?,?),(?,?),(?,?))");
}
@Test
public void test_oneToManyMap() {
findThem();
@@ -276,8 +276,15 @@ public class QCustomerTest {
}
@Test
public void usingTransaction() {
public void usingMaster() {
new QCustomer()
.registered.isNull()
.usingMaster()
.findList();
}
@Test
public void usingTransaction() {
try (Transaction transaction = DB.getDefault().createTransaction()) {
new QCustomer()
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,35 +22,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-spring-txn</artifactId>
@@ -28,7 +28,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
@@ -77,7 +77,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>ebean test</name>
@@ -28,20 +28,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
@@ -132,14 +132,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
@@ -117,6 +117,44 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
// assertSql(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name, ISO_WEEK(?)) lastName from contact");
// }
@Test
public void asDto_usingMaster() {
ResetBasicData.reset();
LoggedSql.start();
DtoQuery<ContactDto> query = DB.find(Contact.class)
.select("id, email")
.where().isNotNull("email")
.asDto(ContactDto.class)
.usingMaster();
List<ContactDto> dtos = query.findList();
assertThat(dtos).isNotEmpty();
for (ContactDto dto : dtos) {
assertThat(dto.getEmail()).isNotNull();
}
}
@Test
public void asDto_usingMaster2() {
ResetBasicData.reset();
LoggedSql.start();
DtoQuery<ContactDto> query = DB.find(Contact.class)
.select("id, email")
.usingMaster()
.where().isNotNull("email")
.asDto(ContactDto.class);
List<ContactDto> dtos = query.findList();
assertThat(dtos).isNotEmpty();
for (ContactDto dto : dtos) {
assertThat(dto.getEmail()).isNotNull();
}
}
@Test
public void asDto_withExplicitId() {
@@ -34,6 +34,7 @@ public class DbConstraintNamingTest {
@Test
public void testIndexNameWithSpaces() {
assertThat(naming.indexName("foo", new String[]{"name", "other desc"})).isEqualTo("ix_foo_name_other_desc");
assertThat(naming.indexName("foo", new String[]{"name desc"})).isEqualTo("ix_foo_name_desc");
}
@Test
@@ -215,7 +215,7 @@ public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer {
}
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
public SpiTransaction createReadOnlyTransaction(Object tenantId, boolean useMaster) {
return null;
}
@@ -66,10 +66,12 @@ public class TestQueryUsingConnection extends BaseTestCase {
.findCount();
final int otherCount = DB.find(Country.class).findCount();
final int masterCount = DB.find(Country.class).usingMaster().findCount();
transaction.rollback();
assertThat(count).isEqualTo(otherCount + 1);
assertThat(otherCount).isEqualTo(masterCount);
}
}
@@ -9,7 +9,9 @@ import javax.persistence.Table;
@Cache(readOnly = true)
@Entity
@Table(name = "feature_desc", indexes = @Index(columnList = "name, description desc"))
@Table(name = "feature_desc", indexes = {
@Index(columnList = "name, description desc"),
@Index(columnList = "name desc")})
public class FeatureDescription {
@Id
@@ -1,5 +1,8 @@
package org.tests.model.basic.cache;
import io.ebean.InTuples;
import io.ebean.annotation.Platform;
import io.ebean.service.SpiInTuples;
import io.ebean.xtest.BaseTestCase;
import io.ebean.CacheMode;
import io.ebean.DB;
@@ -8,6 +11,7 @@ import io.ebean.cache.ServerCache;
import io.ebean.cache.ServerCacheManager;
import io.ebean.cache.ServerCacheStatistics;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.IgnorePlatform;
import org.junit.jupiter.api.Test;
import java.util.List;
@@ -419,6 +423,34 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase {
} else {
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo')");
}
}
@IgnorePlatform({Platform.SQLSERVER, Platform.DB2})
@Test
public void findList_inTuples_noCache() {
setup();
InTuples tuples = InTuples.of("sku", "code")
.add("2", 1000)
.add("2", 1001)
.add("3", 1000);
LoggedSql.start();
List<OCachedNatKeyBean3> list = DB.find(OCachedNatKeyBean3.class)
.where()
.eq("store", "def")
.inTuples(tuples)
.setUseCache(false)
.orderBy("sku desc")
.findList();
List<String> sql = LoggedSql.stop();
SpiInTuples spiTuples = (SpiInTuples)tuples;
assertThat(spiTuples.properties()).containsOnly("sku", "code");
assertThat(spiTuples.entries()).hasSize(3);
assertThat(list).hasSize(3);
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku,t0.code) in ((?,?),(?,?),(?,?)) order by t0.sku desc;");
}
}
@@ -252,6 +252,19 @@ class SqlQueryTests extends BaseTestCase {
return null;
}
@Test
void queryUsingMaster() {
ResetBasicData.reset();
String sql = "select id, name, status from o_customer where name is not null";
List<CustDto> custDtos = DB.sqlQuery(sql)
.usingMaster()
.mapTo(CUST_MAPPER)
.findList();
assertThat(custDtos).isNotEmpty();
}
@Test
void queryUsingTransaction() throws SQLException {
ResetBasicData.reset();
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>kotlin querybean generator</name>
@@ -29,7 +29,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
@@ -43,7 +43,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
@@ -64,14 +64,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<scope>test</scope>
</dependency>
+14 -14
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-all</artifactId>
@@ -14,67 +14,67 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hsqldb</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlanywhere</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-clickhouse</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-db2</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
@@ -18,5 +18,7 @@ public class DB2LegacyPlatform extends BaseDB2Platform {
this.maxTableNameLength = 18;
this.maxConstraintNameLength = 18;
this.persistBatchOnCascade = PersistBatch.NONE;
this.basicSqlLimiter = new DB2RowNumberBasicLimiter();
this.sqlLimiter = new DB2RowNumberSqlLimiter();
}
}
@@ -0,0 +1,15 @@
package io.ebean.platform.db2;
import io.ebean.annotation.Platform;
/**
* DB2 platform for Linux/Unix/Windows version 9.x.
*/
public class DB2Luw9Platform extends BaseDB2Platform {
public DB2Luw9Platform() {
super();
this.platform = Platform.DB2LUW9;
this.basicSqlLimiter = new DB2RowNumberBasicLimiter();
this.sqlLimiter = new DB2RowNumberSqlLimiter();
}
}
@@ -0,0 +1,31 @@
package io.ebean.platform.db2;
import io.ebean.config.dbplatform.BasicSqlLimiter;
/**
* Row limiter for Oracle 9,10,11 using rownum.
*/
final class DB2RowNumberBasicLimiter implements BasicSqlLimiter {
@Override
public String limit(String dbSql, int firstRow, int maxRows) {
if (firstRow < 1 && maxRows < 1) {
return dbSql;
}
StringBuilder sb = new StringBuilder(120 + dbSql.length());
int lastRow = maxRows;
if (lastRow > 0) {
lastRow += firstRow;
}
sb.append("select * from (select row_number() over() a.*, rn from (");
sb.append(dbSql).append(") a ");
if (lastRow > 0) {
sb.append(" where rn <= ").append(lastRow);
}
sb.append(") ");
if (firstRow > 0) {
sb.append(" where rn_ > ").append(firstRow);
}
return sb.toString();
}
}
@@ -0,0 +1,38 @@
package io.ebean.platform.db2;
import io.ebean.config.dbplatform.SqlLimitRequest;
import io.ebean.config.dbplatform.SqlLimitResponse;
import io.ebean.config.dbplatform.SqlLimiter;
final class DB2RowNumberSqlLimiter implements SqlLimiter {
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(120 + dbSql.length());
int firstRow = request.getFirstRow();
int lastRow = request.getMaxRows();
if (lastRow > 0) {
lastRow += firstRow;
}
sb.append("select * from (select row_number() over() a.*, rn from (select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(dbSql).append(") a ");
if (lastRow > 0) {
sb.append(" where rn <= ").append(lastRow);
}
sb.append(") ");
if (firstRow > 0) {
sb.append(" where rn > ").append(firstRow);
}
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
return new SqlLimitResponse(sql);
}
}
@@ -39,6 +39,9 @@ public class Db2PlatformProvider implements DatabasePlatformProvider {
if (name.equals("db2luw")) {
return new DB2LuwPlatform();
}
if (name.equals("db2luw9")) {
return new DB2Luw9Platform();
}
throw new IllegalArgumentException("Unknown DB2 platform, expecting db2luw/db2zos/db2fori but got "+ name);
}
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-h2</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-hana</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-hsqldb</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-mariadb</artifactId>
@@ -14,13 +14,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-mysql</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-nuodb</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-oracle</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>platforms</artifactId>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-postgres</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-sqlanywhere</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-sqlite</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>platforms</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<artifactId>ebean-platform-sqlserver</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
</dependency>
<dependency>
+5 -4
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId>
<version>13.20.0</version>
<version>13.20.1</version>
<packaging>pom</packaging>
<name>ebean parent</name>
@@ -46,14 +46,15 @@
<h2database.version>2.1.214</h2database.version>
<ebean-persistence-api.version>3.0</ebean-persistence-api.version>
<ebean-types.version>3.0</ebean-types.version>
<ebean-annotation.version>8.3</ebean-annotation.version>
<ebean-annotation.version>8.4</ebean-annotation.version>
<ebean-ddl-runner.version>2.3</ebean-ddl-runner.version>
<ebean-migration-auto.version>1.2</ebean-migration-auto.version>
<ebean-migration.version>13.9.0</ebean-migration.version>
<ebean-test-containers.version>7.1</ebean-test-containers.version>
<ebean-datasource.version>8.5</ebean-datasource.version>
<ebean-agent.version>13.20.0</ebean-agent.version>
<ebean-maven-plugin.version>13.20.0</ebean-maven-plugin.version>
<ebean-agent.version>13.20.1</ebean-agent.version>
<ebean-maven-plugin.version>13.20.1</ebean-maven-plugin.version>
<surefire.useModulePath>false</surefire.useModulePath>
</properties>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.20.0</version>
<version>13.20.1</version>
</parent>
<name>querybean generator</name>

Some files were not shown because too many files have changed in this diff Show More