Compare commits

..
Author SHA1 Message Date
Rob Bygrave b6b666013e ClickHouse: Support optimised inserts for ClickHouse 2024-04-17 22:50:28 +12:00
141 changed files with 974 additions and 1181 deletions
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -16,18 +16,18 @@ jobs:
strategy:
fail-fast: false
matrix:
java_version: [GA,EA,23]
java_version: [GA,EA]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: oracle-actions/setup-java@v1
with:
website: jdk.java.net
release: ${{ matrix.java_version }}
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -17,14 +17,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -17,14 +17,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
cache-name: maven-cache
with:
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -41,7 +41,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -60,13 +60,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<artifactId>composites</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<name>ebean api</name>
+29 -67
View File
@@ -186,15 +186,15 @@ public class OrderBy<T> implements Serializable {
if (list.isEmpty()) {
return null;
}
var append = new StringAppend();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
Property property = list.get(i);
if (i > 0) {
append.append(", ");
sb.append(", ");
}
property.toStringFormat(append);
sb.append(property.toStringFormat());
}
return append.toString();
return sb.toString();
}
@Override
@@ -231,55 +231,6 @@ public class OrderBy<T> implements Serializable {
return this;
}
/**
* Append the order by clause.
*/
public interface Append {
/**
* Append a property expression.
*/
Append property(String property);
/**
* Append a literal.
*/
Append append(String literal);
/**
* Parse and append an expression.
*/
Append parse(String expression);
}
private static final class StringAppend implements Append {
private final StringBuilder builder = new StringBuilder();
@Override
public String toString() {
return builder.toString();
}
@Override
public Append property(String property) {
builder.append(property);
return this;
}
@Override
public Append append(String literal) {
builder.append(literal);
return this;
}
@Override
public Append parse(String raw) {
builder.append(raw);
return this;
}
}
/**
* A property and its ascending descending order.
*/
@@ -358,25 +309,36 @@ public class OrderBy<T> implements Serializable {
@Override
public String toString() {
return property;
return toStringFormat();
}
public void toStringFormat(Append append) {
if (collation != null) {
if (collation.contains("${}")) {
// this is a complex collation, e.g. DB2 - we must replace the property
append.parse(collation.replace("${}", property));
public String toStringFormat() {
if (nulls == null && collation == null) {
if (ascending) {
return property;
} else {
append.property(property).append(" collate ").append(collation);
return property + " desc";
}
} else {
append.property(property);
}
if (!ascending) {
append.append(" desc");
}
if (nulls != null) {
append.append(" ").append(nulls).append(" ").append(highLow);
StringBuilder sb = new StringBuilder();
if (collation != null) {
if (collation.contains("${}")) {
// this is a complex collation, e.g. DB2 - we must replace the property
sb.append(collation.replace("${}", property));
} else {
sb.append(property);
sb.append(" collate ").append(collation);
}
} else {
sb.append(property);
}
if (!ascending) {
sb.append(' ').append("desc");
}
if (nulls != null) {
sb.append(' ').append(nulls).append(' ').append(highLow);
}
return sb.toString();
}
}
@@ -40,13 +40,6 @@ public interface QueryBuilderProjection<SELF, T> {
*/
SELF select(String fetchProperties);
/**
* Set DISTINCT ON clause. This is a Postgres only SQL feature.
*
* @param distinctOn The properties to include in the DISTINCT ON clause.
*/
SELF distinctOn(String distinctOn);
/**
* Apply the fetchGroup which defines what part of the object graph to load.
*/
@@ -129,7 +129,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
* When true then include a sql comment in generated SELECT queries with the query
* label or profile location label.
*/
private boolean includeLabelInSql = true;
private boolean includeLabelInSql;
/**
* Interesting classes such as entities, embedded, ScalarTypes,
@@ -4,8 +4,22 @@ public final class AnsiSqlRowsLimiter implements SqlLimiter {
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
final var ansiSql = request.ansiOffsetRows();
final var sql = request.getDbPlatform().completeSql(ansiSql, request.getOrmQuery());
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(dbSql);
int firstRow = request.getFirstRow();
if (firstRow > 0) {
sb.append(" offset ").append(firstRow).append(" rows");
}
int maxRows = request.getMaxRows();
if (maxRows > 0) {
sb.append(" fetch next ").append(maxRows).append(" rows only");
}
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
return new SqlLimitResponse(sql);
}
}
@@ -199,12 +199,21 @@ public class DatabasePlatform {
protected SqlExceptionTranslator exceptionTranslator = new SqlCodeTranslator();
protected InsertSqlSyntaxExtension insertSqlSyntaxExtension = new StandardInsertSqlSyntax();
/**
* Instantiates a new database platform.
*/
public DatabasePlatform() {
}
/**
* Return the Insert SQL syntax helper.
*/
public InsertSqlSyntaxExtension insertSqlSyntaxExtension() {
return insertSqlSyntaxExtension;
}
/**
* Translate the SQLException into a specific persistence exception if possible.
*/
@@ -0,0 +1,32 @@
package io.ebean.config.dbplatform;
/**
* Insert SQL syntax to allow support for ClickHouse type optimisation for inserts.
*/
public interface InsertSqlSyntaxExtension {
/**
* Start the columns.
*/
String startColumns();
/**
* End of the columns.
*/
String endColumns();
/**
* Return true for insert to use standard binding.
*/
boolean useBinding();
/**
* Start types for non-standard binding (e.g. ClickHouse).
*/
String startTypes();
/**
* End types for non-standard binding (e.g. ClickHouse).
*/
String endTypes();
}
@@ -7,16 +7,23 @@ public final class LimitOffsetSqlLimiter implements SqlLimiter {
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
final var buffer = request.selectDistinctOnSql();
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(dbSql);
int maxRows = request.getMaxRows();
if (maxRows > 0) {
buffer.append(" limit ").append(maxRows);
sb.append(" limit ").append(maxRows);
}
int firstRow = request.getFirstRow();
if (firstRow > 0) {
buffer.append(" offset ").append(firstRow);
sb.append(" offset ").append(firstRow);
}
return new SqlLimitResponse(request.getDbPlatform().completeSql(buffer.toString(), request.getOrmQuery()));
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
return new SqlLimitResponse(sql);
}
}
@@ -8,21 +8,6 @@ import io.ebean.Query;
*/
public interface SqlLimitRequest {
/**
* Return ANSI SQL Offset and next rows.
*/
String ansiOffsetRows();
/**
* Create and return buffer including the select distinct clause.
*/
StringBuilder selectDistinct();
/**
* Create and return buffer including the select distinct on clause.
*/
StringBuilder selectDistinctOnSql();
/**
* Return true if the query uses distinct.
*/
@@ -0,0 +1,32 @@
package io.ebean.config.dbplatform;
/**
* Standard Insert SQL syntax.
*/
public final class StandardInsertSqlSyntax implements InsertSqlSyntaxExtension {
@Override
public String startColumns() {
return " (";
}
@Override
public String endColumns() {
return ") values (";
}
@Override
public boolean useBinding() {
return true;
}
@Override
public String startTypes() {
throw new IllegalStateException();
}
@Override
public String endTypes() {
throw new IllegalStateException();
}
}
@@ -76,7 +76,7 @@ class DatabaseConfigTest {
props.setProperty("skipDataSourceCheck", "true");
props.setProperty("readOnlyDatabase", "true");
props.setProperty("lengthCheck", "ON");
props.setProperty("includeLabelInSql", "false");
props.setProperty("includeLabelInSql", "true");
props.setProperty("queryPlan.enable", "true");
props.setProperty("queryPlan.thresholdMicros", "10000");
@@ -97,7 +97,7 @@ class DatabaseConfigTest {
assertTrue(settings.isLoadModuleInfo());
assertTrue(settings.skipDataSourceCheck());
assertTrue(settings.readOnlyDatabase());
assertFalse(settings.isIncludeLabelInSql());
assertTrue(settings.isIncludeLabelInSql());
assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON);
assertTrue(settings.isIdGeneratorAutomatic());
@@ -183,7 +183,7 @@ class DatabaseConfigTest {
assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis());
assertEquals(10, config.getQueryPlanCaptureMaxCount());
assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF);
assertTrue(config.isIncludeLabelInSql());
assertFalse(config.isIncludeLabelInSql());
config.setLoadModuleInfo(false);
assertFalse(config.isAutoLoadModuleInfo());
+26 -26
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<name>ebean bom</name>
@@ -89,25 +89,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -125,13 +125,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -155,37 +155,37 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<!-- platforms -->
@@ -193,79 +193,79 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
+6 -7
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -46,7 +46,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<dependency>
@@ -159,21 +159,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
@@ -211,7 +211,6 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dnet.bytebuddy.experimental=true</argLine>
<useSystemClassLoader>false</useSystemClassLoader>
<trimStackTrace>false</trimStackTrace>
<failIfNoTests>false</failIfNoTests>
@@ -84,17 +84,10 @@ public final class LoadBeanRequest extends LoadRequest {
return idList;
}
public SpiQuery<?> createQuery(SpiEbeanServer server) {
final SpiQuery<?> query = server.createQuery(beanType());
query.usingTransaction(transaction);
configureQuery(query);
return query;
}
/**
* Configure the query for lazy loading execution.
*/
private void configureQuery(SpiQuery<?> query) {
public void configureQuery(SpiQuery<?> query) {
query.setMode(Mode.LAZYLOAD_BEAN);
query.setPersistenceContext(loadBuffer.persistenceContext());
query.setLoadDescription(mode(), description());
@@ -94,7 +94,6 @@ public final class LoadManyRequest extends LoadRequest {
public SpiQuery<?> createQuery(SpiEbeanServer server) {
BeanPropertyAssocMany<?> many = many();
SpiQuery<?> query = many.newQuery(server);
query.usingTransaction(transaction);
String orderBy = many.lazyFetchOrderBy();
if (orderBy != null) {
query.orderBy(orderBy);
@@ -439,11 +439,6 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
@Override
SpiQuery<T> copy();
/**
* Return the distinct on clause.
*/
String distinctOn();
/**
* Return a copy of the query attaching to a different EbeanServer.
*/
@@ -554,6 +549,7 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
* Return true if the query should include the Id property.
* <p>
* distinct and single attribute queries exclude the Id property.
* </p>
*/
boolean isWithId();
@@ -357,8 +357,4 @@ public interface SpiTransaction extends Transaction {
*/
void postRollback(Throwable cause);
/**
* Set the transaction to be inactive via external transaction manager.
*/
void deactivateExternal();
}
@@ -447,9 +447,4 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
public void postRollback(Throwable cause) {
transaction.postRollback(cause);
}
@Override
public void deactivateExternal() {
transaction.deactivateExternal();
}
}
@@ -126,7 +126,9 @@ final class DefaultBeanLoader {
if (loadRequest.checkEmpty()) {
throw new RuntimeException("Nothing in batch?");
}
final SpiQuery<?> query = loadRequest.createQuery(server);
final SpiQuery<?> query = server.createQuery(loadRequest.beanType());
query.usingTransaction(loadRequest.transaction());
loadRequest.configureQuery(query);
loadRequest.postLoad(executeQuery(loadRequest, query));
}
@@ -449,9 +449,6 @@ public final class InternalConfiguration {
*/
private DataTimeZone initDataTimeZone() {
String tz = config.getDataTimeZone();
if ("NoTimeZone".equals(tz)) {
return new NoDataTimeZone();
}
if (tz == null) {
if (isMySql(getPlatform())) {
return new MySqlDataTimeZone();
@@ -514,7 +514,7 @@ final class BeanDescriptorCacheHelp<T> {
if (natKeys != null && !natKeys.isEmpty()) {
if (natLog.isLoggable(DEBUG)) {
natLog.log(DEBUG, " MPUT {0}({1}, {2})", cacheName, Arrays.toString(naturalKey), natKeys.keySet());
natLog.log(DEBUG, " MPUT {0}({1}, {2})", cacheName, naturalKey, natKeys.keySet());
}
naturalKeyCache.putAll(natKeys);
}
@@ -5,6 +5,7 @@ import io.ebean.DatabaseBuilder;
import io.ebean.Model;
import io.ebean.RawSqlBuilder;
import io.ebean.annotation.ConstraintMode;
import io.ebean.annotation.Platform;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.config.*;
@@ -632,6 +633,8 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
private void registerDescriptor(DeployBeanInfo<?> info) {
platformUsesColumnDefinitions(info);
BeanDescriptor<?> desc = new BeanDescriptor<>(this, info.getDescriptor());
descMap.put(desc.type().getName(), desc);
if (desc.isDocStoreMapped()) {
@@ -644,6 +647,23 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private void platformUsesColumnDefinitions(DeployBeanInfo<?> info) {
if (databasePlatform.isPlatform(Platform.CLICKHOUSE) && !DbOffline.isGenerateMigration()) {
// ClickHouse uses column definition to optimise JDBC bulk inserts
DbPlatformTypeMapping typeMapping = databasePlatform.dbTypeMap();
for (DeployBeanProperty property : info.getDescriptor().propertiesAll()) {
if (property.getDbColumnDefn() == null) {
DbPlatformType dbPlatformType = typeMapping.get(property.getDbType());
String columnDefn = dbPlatformType.renderType(property.getDbLength(), property.getDbScale());
if (property.isNullable()) {
columnDefn = "Nullable(" + columnDefn + ")";
}
property.setDbColumnDefn(columnDefn);
}
}
}
}
/**
* Read the initial deployment information for the entities.
* <p>
@@ -43,6 +43,11 @@ public interface ImportedId {
*/
void dmlAppend(GenerateDmlRequest request);
/**
* Append column and type for Insert (ClickHouse).
*/
void dmlType(GenerateDmlRequest request);
/**
* Bind the value from the bean.
*/
@@ -66,6 +66,16 @@ public final class ImportedIdEmbedded implements ImportedId {
}
}
@Override
public void dmlType(GenerateDmlRequest request) {
boolean update = request.isUpdate();
for (ImportedIdSimple anImported : imported) {
if (anImported.isInclude(update)) {
anImported.dmlType(request);
}
}
}
@Override
public String importedIdClause() {
StringBuilder sb = new StringBuilder();
@@ -37,6 +37,7 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
final BeanPropertyAssoc<?> owner;
final String localDbColumn;
private final String localColumnDefn;
private final String localSqlFormula;
final BeanProperty foreignProperty;
private final int position;
@@ -49,6 +50,7 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
this.localDbColumn = InternString.intern(localDbColumn);
this.localSqlFormula = InternString.intern(localSqlFormula);
this.foreignProperty = foreignProperty;
this.localColumnDefn = foreignProperty.dbColumnDefn();
this.position = position;
this.insertable = insertable;
this.updateable = updateable;
@@ -143,6 +145,11 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
request.appendColumn(localDbColumn);
}
@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(localDbColumn, localColumnDefn);
}
@Override
public String importedIdClause() {
return localDbColumn + " = ?";
@@ -75,7 +75,7 @@ final class SubQueryExpression extends AbstractExpression implements Unsupported
@Override
public void addSql(SpiExpressionRequest request) {
request.property(propName).append(op.expression).append('(').append(sql).append(')');
request.property(propName).append(op.expression).append('(').parse(sql).append(')');
}
@Override
@@ -15,14 +15,26 @@ public final class GenerateDmlRequest {
private String prefix2;
private int insertMode;
private int bindColumnCount;
private boolean hasColumnDefn;
GenerateDmlRequest append(String s) {
sb.append(s);
return this;
}
/**
* Append column and type for Insert (ClickHouse).
*/
public void appendColumnDefn(String columnName, String columnDefn) {
if (hasColumnDefn) {
sb.append(", ");
} else {
hasColumnDefn = true;
}
sb.append(columnName).append(' ').append(columnDefn);
}
public void appendColumn(String column) {
//String bind = (insertMode > 0) ? "?" : "=?";
appendColumn(column, "?");
}
@@ -4,6 +4,7 @@ import io.ebean.InsertOptions;
import io.ebean.annotation.Platform;
import io.ebean.bean.EntityBean;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.InsertSqlSyntaxExtension;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.InheritInfo;
@@ -37,10 +38,13 @@ final class InsertMeta {
private final Bindable shadowFKey;
private final String[] identityDbColumns;
private final Platform platform;
private final InsertSqlSyntaxExtension insertMetaSql;
private final InsertMetaOptions options;
InsertMeta(DatabasePlatform dbPlatform, BeanDescriptor<?> desc, Bindable shadowFKey, BindableId id, BindableList all) {
this.platform = dbPlatform.platform();
this.insertMetaSql = dbPlatform.insertSqlSyntaxExtension();
this.options = InsertMetaPlatform.create(platform, desc, this);
this.discriminator = discriminator(desc);
this.id = id;
@@ -174,7 +178,7 @@ final class InsertMeta {
request.append(defaultValues());
return;
}
request.append(" (");
request.append(insertMetaSql.startColumns());
if (!nullId) {
id.dmlAppend(request);
}
@@ -189,9 +193,28 @@ final class InsertMeta {
} else {
allExcludeDraftOnly.dmlAppend(request);
}
request.append(") values (");
request.append(request.insertBindBuffer());
request.append(")");
request.append(insertMetaSql.endColumns());
if (insertMetaSql.useBinding()) {
request.append(request.insertBindBuffer());
request.append(")");
} else {
request.append(insertMetaSql.startTypes());
if (!nullId) {
id.dmlType(request);
}
if (shadowFKey != null) {
shadowFKey.dmlType(request);
}
if (discriminator != null) {
discriminator.dmlType(request);
}
if (draftTable) {
all.dmlType(request);
} else {
allExcludeDraftOnly.dmlType(request);
}
request.append(insertMetaSql.endTypes());
}
}
private String defaultValues() {
@@ -33,6 +33,11 @@ public interface Bindable {
*/
void dmlAppend(GenerateDmlRequest request);
/**
* Append column and type for Insert (ClickHouse).
*/
void dmlType(GenerateDmlRequest request);
/**
* Bind given the request and bean. The bean could be the oldValues bean
* when binding a update or delete where clause with ALL concurrency mode.
@@ -40,6 +40,11 @@ class BindableAssocOne implements Bindable {
importedId.dmlAppend(request);
}
@Override
public void dmlType(GenerateDmlRequest request) {
importedId.dmlType(request);
}
@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
EntityBean assocBean = (EntityBean) assocOne.getValue(bean);
@@ -39,6 +39,11 @@ public final class BindableDiscriminator implements Bindable {
request.appendColumn(columnName);
}
@Override
public void dmlType(GenerateDmlRequest request) {
throw new IllegalArgumentException("Not supported");
}
@Override
public void dmlBind(BindableRequest bindRequest, EntityBean bean) throws SQLException {
bindRequest.bind(discValue, sqlType);
@@ -35,6 +35,13 @@ final class BindableEmbedded implements Bindable {
}
}
@Override
public void dmlType(GenerateDmlRequest request) {
for (Bindable item : items) {
item.dmlType(request);
}
}
@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
if (request.isAddToUpdate(embProp)) {
@@ -41,6 +41,11 @@ final class BindableEncryptedProperty implements Bindable {
request.appendColumn(prop.dbColumn(), prop.dbBind());
}
@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(prop.dbColumn(), prop.dbColumnDefn());
}
@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
Object value = null;
@@ -81,6 +81,13 @@ final class BindableIdEmbedded implements BindableId {
}
}
@Override
public void dmlType(GenerateDmlRequest request) {
for (BeanProperty prop : props) {
request.appendColumn(prop.dbColumnDefn());
}
}
@Override
public boolean deriveConcatenatedId(PersistRequestBean<?> persist) {
if (matches == null) {
@@ -28,6 +28,11 @@ final class BindableIdEmpty implements BindableId {
// nothing
}
@Override
public void dmlType(GenerateDmlRequest request) {
// nothing
}
@Override
public void dmlBind(BindableRequest request, EntityBean bean) {
// nothing
@@ -58,17 +58,18 @@ final class BindableIdScalar implements BindableId {
@Override
public void dmlAppend(GenerateDmlRequest request) {
request.appendColumn(uidProp.dbColumn());
}
@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(uidProp.dbColumn(), uidProp.dbColumnDefn());
}
@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
Object value = uidProp.getValue(bean);
request.bind(value, uidProp);
// used for summary logging
request.setIdValue(value);
}
@@ -60,6 +60,13 @@ public final class BindableList implements Bindable {
}
}
@Override
public void dmlType(GenerateDmlRequest request) {
for (Bindable item : items) {
item.dmlType(request);
}
}
@Override
public void dmlBind(BindableRequest bindRequest, EntityBean bean) throws SQLException {
for (Bindable item : items) {
@@ -36,6 +36,11 @@ class BindableProperty implements Bindable {
request.appendColumn(prop.dbColumn());
}
@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(prop.dbColumn(), prop.dbColumnDefn());
}
/**
* Normal binding of a property value from the bean.
*/
@@ -41,6 +41,11 @@ final class BindablePropertyVersion implements Bindable {
request.appendColumn(prop.dbColumn());
}
@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(prop.dbColumn(), prop.dbColumnDefn());
}
/**
* Normal binding of a property value from the bean.
*/
@@ -45,6 +45,11 @@ public final class BindableUnidirectional implements Bindable {
importedId.dmlAppend(request);
}
@Override
public void dmlType(GenerateDmlRequest request) {
importedId.dmlType(request);
}
@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
PersistRequestBean<?> persistRequest = request.persistRequest();
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.query;
import io.ebean.*;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.SqlLimitRequest;
import io.ebean.config.dbplatform.SqlLimitResponse;
import io.ebean.config.dbplatform.SqlLimiter;
import io.ebean.event.readaudit.ReadAuditQueryPlan;
@@ -532,7 +533,7 @@ final class CQueryBuilder {
private final boolean distinct;
private final boolean countSingleAttribute;
private final String dbOrderBy;
private final boolean useSqlLimiter;
private boolean useSqlLimiter;
private boolean hasWhere;
private BuildReq(String selectClause, OrmQueryRequest<?> request, CQueryPredicates predicates, SqlTree select) {
@@ -549,15 +550,13 @@ final class CQueryBuilder {
this.distinct = query.isDistinct() || select.isSqlDistinct();
this.dbOrderBy = predicates.dbOrderBy();
this.countSingleAttribute = query.isCountDistinct() && query.isSingleAttribute();
this.useSqlLimiter = selectClause == null
&& query.hasMaxRowsOrFirstRow()
&& (select.distinctOn() != null || select.manyProperty() == null || query.isSingleAttribute());
}
private void appendSelect() {
if (selectClause != null) {
sb.append(selectClause);
} else {
useSqlLimiter = (query.hasMaxRowsOrFirstRow() && (select.manyProperty() == null || query.isSingleAttribute()));
if (!useSqlLimiter) {
appendSelectDistinct();
}
@@ -582,7 +581,7 @@ final class CQueryBuilder {
if (request.isInlineCountDistinct()) {
sb.append(')');
}
if (distinct && dbOrderBy != null && query.distinctOn() == null) {
if (distinct && dbOrderBy != null) {
// add the orderBy columns to the select clause (due to distinct)
String[] tokens = DbOrderByTrim.trim(dbOrderBy).split(",");
for (String token : tokens) {
@@ -734,7 +733,7 @@ final class CQueryBuilder {
}
if (useSqlLimiter) {
// use LIMIT/OFFSET, ROW_NUMBER() or rownum type SQL query limitation
var r = new OrmQueryLimitRequest(sb.toString(), dbOrderBy, query, dbPlatform, distinct, select.distinctOn(), hint(), inlineSqlComment());
SqlLimitRequest r = new OrmQueryLimitRequest(sb.toString(), dbOrderBy, query, dbPlatform, distinct);
return sqlLimiter.limit(r);
} else {
if (updateStatement) {
@@ -5,7 +5,6 @@ import io.ebean.OrderBy.Property;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.DeployParser;
import io.ebeaninternal.server.deploy.id.IdBinder;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -18,81 +17,50 @@ final class CQueryOrderBy {
private final BeanDescriptor<?> desc;
private final OrderBy<?> orderBy;
private final DeployParser parser;
/**
* Create the logical order by clause.
*/
static String parse(DeployParser parser, BeanDescriptor<?> desc, OrderBy<?> orderBy) {
return new CQueryOrderBy(parser, desc, orderBy).parseInternal();
public static String parse(BeanDescriptor<?> desc, OrderBy<?> orderBy) {
return new CQueryOrderBy(desc, orderBy).parseInternal();
}
private CQueryOrderBy(DeployParser parser, BeanDescriptor<?> desc, OrderBy<?> orderBy) {
private CQueryOrderBy(BeanDescriptor<?> desc, OrderBy<?> orderBy) {
this.desc = desc;
this.parser = parser;
this.orderBy = orderBy;
}
private String parseInternal() {
StringBuilder sb = new StringBuilder();
List<Property> properties = orderBy.getProperties();
if (properties.isEmpty()) {
// order by clause removed by filterMany()
return null;
}
var append = new StringAppend(parser);
for (int i = 0; i < properties.size(); i++) {
if (i > 0) {
append.append(", ");
sb.append(", ");
}
parseProperty(properties.get(i), append);
Property p = properties.get(i);
String expression = parseProperty(p);
sb.append(expression);
}
return append.toString();
return sb.toString();
}
private void parseProperty(Property p, StringAppend append) {
ElPropertyValue el = desc.elGetValue(p.getProperty());
if (el != null) {
BeanProperty beanProperty = el.beanProperty();
if (beanProperty instanceof BeanPropertyAssoc<?>) {
BeanPropertyAssoc<?> ap = (BeanPropertyAssoc<?>) beanProperty;
IdBinder idBinder = ap.targetDescriptor().idBinder();
append.parse(idBinder.orderBy(el.elName(), p.isAscending()));
return;
}
}
p.toStringFormat(append);
}
private static class StringAppend implements OrderBy.Append {
private final StringBuilder builder = new StringBuilder();
private final DeployParser parser;
StringAppend(DeployParser parser) {
this.parser = parser;
private String parseProperty(Property p) {
String propName = p.getProperty();
ElPropertyValue el = desc.elGetValue(propName);
if (el == null) {
return p.toStringFormat();
}
@Override
public String toString() {
return builder.toString();
}
@Override
public OrderBy.Append property(String property) {
builder.append(parser.property(property));
return this;
}
@Override
public OrderBy.Append append(String literal) {
builder.append(literal);
return this;
}
@Override
public OrderBy.Append parse(String raw) {
builder.append(parser.parse(raw));
return this;
BeanProperty beanProperty = el.beanProperty();
if (beanProperty instanceof BeanPropertyAssoc<?>) {
BeanPropertyAssoc<?> ap = (BeanPropertyAssoc<?>) beanProperty;
IdBinder idBinder = ap.targetDescriptor().idBinder();
return idBinder.orderBy(el.elName(), p.isAscending());
}
return p.toStringFormat();
}
}
@@ -7,6 +7,7 @@ import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.DeployParser;
import io.ebeaninternal.server.expression.DefaultExpressionRequest;
@@ -61,7 +62,6 @@ public final class CQueryPredicates {
*/
private String dbFilterMany;
private String dbOrderBy;
private String dbDistinctOn;
private String dbUpdateClause;
/**
* Includes from where and order by clauses.
@@ -177,7 +177,10 @@ public final class CQueryPredicates {
BeanPropertyAssocMany<?> manyProperty = request.determineMany();
if (buildSql) {
dbOrderBy = deriveOrderByWithMany(deployParser, request.manyPropertyForOrderBy());
String logicalOrderBy = deriveOrderByWithMany(request.manyPropertyForOrderBy());
if (logicalOrderBy != null) {
dbOrderBy = deployParser.parse(logicalOrderBy);
}
// create a copy of the includes required to support the orderBy
orderByIncludes = new HashSet<>(deployParser.includes());
}
@@ -206,10 +209,6 @@ public final class CQueryPredicates {
}
}
if (buildSql) {
final String distinctOn = query.distinctOn();
if (distinctOn != null) {
dbDistinctOn = deployParser.parse(distinctOn);
}
predicateIncludes = deployParser.includes();
}
}
@@ -232,52 +231,51 @@ public final class CQueryPredicates {
if (dbOrderBy != null) {
dbOrderBy = alias.parse(dbOrderBy);
}
if (dbDistinctOn != null) {
dbDistinctOn = alias.parse(dbDistinctOn);
}
}
private String parseOrderBy(DeployParser parser) {
private String parseOrderBy() {
OrderBy<?> orderBy = query.getOrderBy();
if (orderBy == null) {
return null;
}
return CQueryOrderBy.parse(parser, request.descriptor(), orderBy);
return CQueryOrderBy.parse(request.descriptor(), orderBy);
}
/**
* There is a many property we need to make sure the ordering is appropriate.
*/
private String deriveOrderByWithMany(DeployParser parser, BeanPropertyAssocMany<?> manyProp) {
String orderBy = parseOrderBy(parser);
private String deriveOrderByWithMany(BeanPropertyAssocMany<?> manyProp) {
if (manyProp == null) {
return orderBy;
return parseOrderBy();
}
String orderById = parser.parse(request.descriptor().defaultOrderBy());
String orderBy = parseOrderBy();
BeanDescriptor<?> desc = request.descriptor();
String orderById = desc.defaultOrderBy();
if (orderBy == null) {
orderBy = orderById;
}
// check for default ordering on the many property...
String manyOrderBy = manyProp.fetchOrderBy();
if (manyOrderBy != null) {
orderBy = orderBy + ", " + parser.parse(CQueryBuilder.prefixOrderByFields(manyProp.name(), manyOrderBy));
orderBy = orderBy + ", " + CQueryBuilder.prefixOrderByFields(manyProp.name(), manyOrderBy);
}
if (request.isFindById()) {
// only one master bean so should be fine...
return orderBy;
}
if (orderBy.startsWith(orderById)) {
return orderBy;
}
// more than one top level row may be returned so
// we need to make sure their is an order by on the
// top level first (to ensure master/detail construction).
int idPos = orderBy.indexOf(orderById);
if (idPos == 0) {
return orderBy;
}
int manyPos = orderBy.indexOf("${" + manyProp.name() + "}");
int manyPos = orderBy.indexOf(manyProp.name());
int idPos = orderBy.indexOf(" " + orderById);
if (manyPos == -1) {
// no ordering of the many
if (idPos == -1) {
// append the orderById so that master level objects are ordered
// even if the orderBy is not unique for the master object
return orderBy + ", " + orderById;
}
// orderById is already in the order by clause
@@ -286,7 +284,7 @@ public final class CQueryPredicates {
if (idPos == -1 || idPos >= manyPos) {
if (idPos > manyPos) {
// there was an error with the order by...
String msg = "A Query on [" + request.descriptor() + "] includes a join to a 'many' association [" + manyProp.name()
String msg = "A Query on [" + desc + "] includes a join to a 'many' association [" + manyProp.name()
+ "] with an incorrect orderBy [" + orderBy + "]. The id property [" + orderById
+ "] must come before the many property [" + manyProp.name() + "] in the orderBy."
+ " Ebean has automatically modified the orderBy clause to do this.";
@@ -353,13 +351,6 @@ public final class CQueryPredicates {
return dbOrderBy;
}
/**
* Return the db distinct on clause.
*/
String dbDistinctOn() {
return dbDistinctOn;
}
/**
* Return the includes required for the where and order by clause.
*/
@@ -59,11 +59,6 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
return new DFetchGroup<>(detail);
}
@Override
public Query<T> distinctOn(String distinctOn) {
throw new UnsupportedOperationException();
}
@Override
public Query<T> select(String columns) {
detail.select(columns);
@@ -156,10 +156,6 @@ public final class SqlTreeBuilder {
}
private String buildDistinctOn() {
String distinctOn = predicates.dbDistinctOn();
if (distinctOn != null) {
return distinctOn;
}
if (rawSql || !distinctOnPlatform || !sqlDistinct || Type.COUNT == query.type()) {
return null;
}
@@ -72,7 +72,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
* Lazy loading batch size (can override server wide default).
*/
private int lazyLoadBatchSize;
private String distinctOn;
private OrderBy<T> orderBy;
private String loadMode;
private String loadDescription;
@@ -516,10 +515,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
* Limit the number of fetch joins to Many properties, mark as query joins as needed.
*/
private void markQueryJoins() {
if (distinctOn == null) {
// no automatic join to query join conversion when distinctOn is used
detail.markQueryJoins(beanDescriptor, lazyLoadManyPath, isAllowOneManyFetch(), type.defaultSelect());
}
detail.markQueryJoins(beanDescriptor, lazyLoadManyPath, isAllowOneManyFetch(), type.defaultSelect());
}
private boolean isAllowOneManyFetch() {
@@ -643,11 +639,12 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return countDistinctOrder;
}
/**
* Return true if the Id should be included in the query.
*/
@Override
public final boolean isWithId() {
// distinctOn orm query will auto include the id property
// distinctOn dto query does NOT (via setting manualId to true)
return !manualId && !singleAttribute && (!distinct || distinctOn != null);
return !manualId && !distinct && !singleAttribute;
}
@Override
@@ -743,7 +740,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
copy.baseTable = baseTable;
copy.rootTableAlias = rootTableAlias;
copy.distinct = distinct;
copy.distinctOn = distinctOn;
copy.allowLoadErrors = allowLoadErrors;
copy.timeout = timeout;
copy.mapKey = mapKey;
@@ -803,11 +799,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
this.type = type;
}
@Override
public String distinctOn() {
return distinctOn;
}
@Override
public final String loadDescription() {
return loadDescription;
@@ -1096,9 +1087,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
}
if (distinct) {
sb.append("/dt");
if (distinctOn != null) {
sb.append("/o:").append(distinctOn);
}
}
if (allowLoadErrors) {
sb.append("/ae");
@@ -1352,13 +1340,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
detail.addNested(name, nestedDetail, config);
}
@Override
public final Query<T> distinctOn(String distinctOn) {
this.distinctOn = distinctOn;
this.distinct = true;
return this;
}
@Override
public final Query<T> select(String columns) {
detail.select(columns);
@@ -11,67 +11,13 @@ public final class OrmQueryLimitRequest implements SqlLimitRequest {
private final String sql;
private final String sqlOrderBy;
private final boolean distinct;
private final String distinctOn;
private final String hint;
private final String label;
public OrmQueryLimitRequest(String sql, String sqlOrderBy, SpiQuery<?> ormQuery, DatabasePlatform dbPlatform, boolean distinct) {
this(sql, sqlOrderBy, ormQuery, dbPlatform, distinct, null, "", "");
}
public OrmQueryLimitRequest(String sql, String sqlOrderBy, SpiQuery<?> ormQuery, DatabasePlatform dbPlatform,
boolean distinct, String distinctOn, String hint, String label) {
this.sql = sql;
this.sqlOrderBy = sqlOrderBy;
this.ormQuery = ormQuery;
this.dbPlatform = dbPlatform;
this.distinct = distinct;
this.distinctOn = distinctOn;
this.hint = hint;
this.label = label;
}
private StringBuilder newBuffer() {
return new StringBuilder(50 + sql.length());
}
@Override
public String ansiOffsetRows() {
final var buffer = selectDistinct();
buffer.append(sql);
int firstRow = getFirstRow();
if (firstRow > 0) {
buffer.append(" offset ").append(firstRow).append(" rows");
}
int maxRows = getMaxRows();
if (maxRows > 0) {
buffer.append(" fetch next ").append(maxRows).append(" rows only");
}
return buffer.toString();
}
@Override
public StringBuilder selectDistinct() {
final var buffer = newBuffer();
buffer.append("select ").append(hint).append(label);
if (distinct) {
buffer.append("distinct ");
}
return buffer;
}
@Override
public StringBuilder selectDistinctOnSql() {
var buffer = newBuffer();
buffer.append("select ").append(hint).append(label);
if (distinct) {
buffer.append("distinct ");
if (distinctOn != null) {
buffer.append("on (").append(distinctOn).append(") ");
}
}
buffer.append(sql);
return buffer;
}
@Override
@@ -609,11 +609,6 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
// do nothing
}
@Override
public void deactivateExternal() {
this.active = false;
}
/**
* Return true if the transaction is active.
*/
@@ -1082,11 +1082,6 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
return active;
}
@Override
public void deactivateExternal() {
this.active = false;
}
@Override
public final boolean isPersistCascade() {
return persistCascade;
@@ -94,14 +94,9 @@ public final class JtaTransactionManager implements ExternalTransactionManager {
// check current Ebean transaction
SpiTransaction currentEbeanTransaction = scope.inScope();
if (currentEbeanTransaction != null) {
if (currentEbeanTransaction.isActive()) {
// NOT expecting this so log WARNING
log.log(WARNING, "JTA Transaction - no current txn BUT using current Ebean one {0}", currentEbeanTransaction.id());
return currentEbeanTransaction;
} else {
log.log(DEBUG, "JTA Transaction - clearing inActive Ebean transaction {0}", currentEbeanTransaction.id());
scope.clearExternal();
}
// NOT expecting this so log WARNING
log.log(WARNING, "JTA Transaction - no current txn BUT using current Ebean one {0}", currentEbeanTransaction.id());
return currentEbeanTransaction;
}
UserTransaction ut = userTransaction();
@@ -191,27 +186,27 @@ public final class JtaTransactionManager implements ExternalTransactionManager {
@Override
public void afterCompletion(int status) {
try {
switch (status) {
case Status.STATUS_COMMITTED:
log.log(DEBUG, "Jta Txn [{0}] committed", transaction.id());
transaction.postCommit();
break;
switch (status) {
case Status.STATUS_COMMITTED:
log.log(DEBUG, "Jta Txn [{0}] committed", transaction.id());
transaction.postCommit();
// Remove this transaction object as it is completed
transactionManager.scope().clearExternal();
break;
case Status.STATUS_ROLLEDBACK:
log.log(DEBUG, "Jta Txn [{0}] rollback", transaction.id());
transaction.postRollback(null);
break;
case Status.STATUS_ROLLEDBACK:
log.log(DEBUG, "Jta Txn [{0}] rollback", transaction.id());
transaction.postRollback(null);
// Remove this transaction object as it is completed
transactionManager.scope().clearExternal();
break;
default:
log.log(DEBUG, "Jta Txn [{0}] status:{1}", transaction.id(), status);
}
} finally {
transaction.deactivateExternal();
transactionManager.scope().clearExternal();
// No matter the completion status of the transaction, we release the connection we got from the pool.
JdbcClose.close(transaction.internalConnection());
default:
log.log(DEBUG, "Jta Txn [{0}] status:{1}", transaction.id(), status);
}
// No matter the completion status of the transaction, we release the connection we got from the pool.
JdbcClose.close(transaction.internalConnection());
}
}
@@ -117,10 +117,6 @@ final class NoTransaction implements SpiTransaction {
// do nothing
}
@Override
public void deactivateExternal() {
// do nothing
}
@Override
public boolean isLogSql() {
@@ -196,6 +196,10 @@ public class InitDataSourceTest {
public void dataSourceDown(DataSource dataSource, SQLException reason) {
}
@Override
public void dataSourceWarning(DataSource dataSource, String msg) {
}
}
@Test
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.querydefn;
import io.ebean.*;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.core.OrmQueryRequestTestHelper;
import io.ebeaninternal.server.expression.BaseExpressionTest;
@@ -55,32 +54,6 @@ public class DefaultOrmQueryTest extends BaseExpressionTest {
assertThat(q1.getId()).isEqualTo(42);
}
@Test
void when_distinctOn_then_planChanges() {
DefaultOrmQuery<Order> q1 = (DefaultOrmQuery<Order>) DB.find(Order.class).distinctOn("name");
DefaultOrmQuery<Order> q2 = (DefaultOrmQuery<Order>) DB.find(Order.class);
prepare(q1, q2);
assertThat(q1.createQueryPlanKey()).isNotEqualTo(q2.createQueryPlanKey());
}
@Test
void when_distinctOn_match() {
DefaultOrmQuery<Order> q1 = (DefaultOrmQuery<Order>) DB.find(Order.class).distinctOn("name");
DefaultOrmQuery<Order> q2 = (DefaultOrmQuery<Order>) DB.find(Order.class).distinctOn("name");
prepare(q1, q2);
assertThat(q1.createQueryPlanKey()).isEqualTo(q2.createQueryPlanKey());
assertThat(bindKey(q1)).isEqualTo(bindKey(q2));
}
@Test
void when_distinctOn_copy() {
DefaultOrmQuery<Order> q1 = (DefaultOrmQuery<Order>) DB.find(Order.class).distinctOn("name");
SpiQuery<Order> copy = q1.copy();
assertThat(copy.distinctOn()).isEqualTo("name");
}
@Test
public void when_addWhere_then_planChanges() {
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
@@ -65,7 +65,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
@@ -5,6 +5,7 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
import io.ebeaninternal.dbmigration.migration.Column;
public class ClickHouseDdl extends PlatformDdl {
@@ -17,6 +18,16 @@ public class ClickHouseDdl extends PlatformDdl {
this.columnNotNull = null;
}
@Override
protected String columnDefn(Column column) {
String defn = super.columnDefn(column);
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
return defn;
} else {
return "Nullable(" + defn + ")";
}
}
@Override
public DdlHandler createDdlHandler(DatabaseBuilder.Settings config) {
return new ClickHouseDdlHandler(config, this);
@@ -230,13 +230,13 @@ public class PlatformDdl {
* Write the column definition to the create table statement.
*/
protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) {
String columnDefn = convert(column.getType());
buffer.append(" ");
buffer.append(quote(column.getName()), 29);
String columnDefn = columnDefn(column);
if (identity.useIdentity() && isTrue(column.isPrimaryKey())) {
columnDefn = asIdentityColumn(columnDefn, identity);
}
buffer.append(" ");
buffer.append(quote(column.getName()), 29);
buffer.append(columnDefn);
if (!Boolean.TRUE.equals(column.isPrimaryKey())) {
String defaultValue = convertDefaultValue(column.getDefaultValue());
@@ -251,6 +251,13 @@ public class PlatformDdl {
// so that the database can potentially provide a nice SQL error
}
/**
* Return the plaform specific column type definition.
*/
protected String columnDefn(Column column) {
return convert(column.getType());
}
/**
* Returns the check constraint.
*/
@@ -0,0 +1,28 @@
package io.ebeaninternal.dbmigration;
import io.ebean.platform.clickhouse.ClickHousePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.PlatformDdlBuilder;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class ClickHousePlatformTest {
@Test
void testTypeConversion() {
PlatformDdl ddl = PlatformDdlBuilder.create(new ClickHousePlatform());
assertThat(ddl.convert("clob")).isEqualTo("String");
assertThat(ddl.convert("varchar(20)")).isEqualTo("String");
assertThat(ddl.convert("json")).isEqualTo("JSON");
assertThat(ddl.convert("jsonb")).isEqualTo("JSON");
assertThat(ddl.convert("decimal(10)")).isEqualTo("Decimal(10)");
assertThat(ddl.convert("decimal(8,4)")).isEqualTo("Decimal(8,4)");
assertThat(ddl.convert("decimal")).isEqualTo("Decimal(16,3)");
assertThat(ddl.convert("boolean")).isEqualTo("Bool");
assertThat(ddl.convert("bit")).isEqualTo("bit");
}
}
@@ -0,0 +1,56 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.platform.clickhouse.ClickHousePlatform;
import io.ebeaninternal.dbmigration.migration.Column;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class ClickHouseDdlTest {
private final ClickHouseDdl ddl = new ClickHouseDdl(new ClickHousePlatform());
@Test
void convert() {
assertThat(ddl.convert("boolean")).isEqualTo("Bool");
assertThat(ddl.convert("integer")).isEqualTo("UInt32");
assertThat(ddl.convert("bigint")).isEqualTo("UInt64");
assertThat(ddl.convert("decimal(20,3)")).isEqualTo("Decimal(20,3)");
assertThat(ddl.convert("varchar(20)")).isEqualTo("String");
assertThat(ddl.convert("hstore")).isEqualTo("Map(String,String)");
assertThat(ddl.convert("json")).isEqualTo("JSON");
assertThat(ddl.convert("varchar[]")).isEqualTo("Array(String)");
}
@Test
void columnDefnNullable() {
Column column = new Column();
column.setType("varchar(20)");
column.setNotnull(null);
assertThat(ddl.columnDefn(column)).isEqualTo("Nullable(String)");
}
@Test
void columnDefnNullable2() {
Column column = new Column();
column.setType("varchar(20)");
column.setNotnull(Boolean.FALSE);
assertThat(ddl.columnDefn(column)).isEqualTo("Nullable(String)");
}
@Test
void columnDefnNotNull() {
Column column = new Column();
column.setType("varchar(20)");
column.setNotnull(Boolean.TRUE);
assertThat(ddl.columnDefn(column)).isEqualTo("String");
}
@Test
void columnDefnNotNullPrimaryKey() {
Column column = new Column();
column.setType("varchar(20)");
column.setPrimaryKey(Boolean.TRUE);
assertThat(ddl.columnDefn(column)).isEqualTo("String");
}
}
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<name>ebean postgis types</name>
@@ -19,14 +19,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
@@ -62,7 +62,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
@@ -86,7 +86,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:14.3.0</tile>
<tile>io.ebean.tile:enhancement:14.2.0</tile>
</tiles>
</configuration>
</plugin>
@@ -35,8 +35,6 @@ public class TestCacheSerialization {
assertEquals(p1, r2.getPoint()); // and did fail https://github.com/ebean-orm/ebean/issues/3026
assertEquals(pol, r2.getPolygon());
DB.delete(tb);
}
@Test
@@ -78,7 +76,5 @@ public class TestCacheSerialization {
assertEquals(pol, r2.getPolygon()); // and did fail https://github.com/ebean-orm/ebean/issues/3026
assertNull(r1.getPoint());
DB.delete(tb);
}
}
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
@@ -63,14 +63,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
@@ -84,7 +84,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
@@ -100,7 +100,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:14.3.0</tile>
<tile>io.ebean.tile:enhancement:14.2.0</tile>
</tiles>
</configuration>
</plugin>
@@ -59,13 +59,6 @@ public interface IQueryBean<T, R> extends QueryBuilder<R, T> {
*/
FetchGroup<T> buildFetchGroup();
/**
* Set DISTINCT ON properties. This is a Postgres only SQL feature.
*
* @param properties The properties to include in the DISTINCT ON clause.
*/
R distinctOn(TQProperty<R, ?>... properties);
/**
* Specify the properties to be loaded on the 'main' root level entity bean.
* <p>
@@ -88,14 +88,14 @@ public abstract class QueryBean<T, R> implements IQueryBean<T, R> {
/**
* Construct using the type of bean to query on and the default database.
*/
protected QueryBean(Class<T> beanType) {
public QueryBean(Class<T> beanType) {
this(beanType, DB.getDefault());
}
/**
* Construct using the type of bean to query on and a given database.
*/
protected QueryBean(Class<T> beanType, Database database) {
public QueryBean(Class<T> beanType, Database database) {
this(database.find(beanType));
}
@@ -119,7 +119,7 @@ public abstract class QueryBean<T, R> implements IQueryBean<T, R> {
* Construct using a query.
*/
@SuppressWarnings("unchecked")
protected QueryBean(Query<T> query) {
public QueryBean(Query<T> query) {
this.query = query;
this.root = (R) this;
}
@@ -129,7 +129,7 @@ public abstract class QueryBean<T, R> implements IQueryBean<T, R> {
* values for select() and fetch().
*/
@SuppressWarnings("unchecked")
protected QueryBean(boolean aliasDummy) {
public QueryBean(boolean aliasDummy) {
this.query = null;
this.root = (R) this;
}
@@ -159,12 +159,6 @@ public abstract class QueryBean<T, R> implements IQueryBean<T, R> {
return query;
}
@Override
public R distinctOn(String distinctOn) {
query.distinctOn(distinctOn);
return root;
}
@Override
public R select(String properties) {
query.select(properties);
@@ -177,17 +171,6 @@ public abstract class QueryBean<T, R> implements IQueryBean<T, R> {
return root;
}
@Override
@SafeVarargs
public final R distinctOn(TQProperty<R, ?>... properties) {
final var joiner = new StringJoiner(", ");
for (Query.Property<?> property : properties) {
joiner.add(property.toString());
}
distinctOn(joiner.toString());
return root;
}
@Override
@SafeVarargs
public final R select(TQProperty<R, ?>... properties) {
@@ -4,7 +4,6 @@ import io.ebean.*;
import io.ebean.annotation.Transactional;
import io.ebean.test.LoggedSql;
import io.ebean.types.Inet;
import io.ebeaninternal.api.SpiQuery;
import org.example.domain.Address;
import org.example.domain.Country;
import org.example.domain.Customer;
@@ -227,22 +226,6 @@ public class QCustomerTest {
.findList();
}
@Test
public void distinctOn() {
var c = QContact.alias();
var q = new QContact()
.distinctOn(c.customer)
.select(c.lastName, c.whenCreated)
.orderBy()
.customer.id.asc()
.whenCreated.desc()
.query();
SpiQuery<?> spiQuery = (SpiQuery<?>) q;
assertThat(spiQuery.distinctOn()).isEqualTo("customer");
assertThat(spiQuery.isDistinct()).isTrue();
}
@Transactional
@Test
public void forUpdate() {
@@ -331,7 +314,7 @@ public class QCustomerTest {
.query();
q.findList();
assertThat(q.getGeneratedSql()).isEqualTo("select /* QCustomerTest.filterManySeparateQuery */ t0.id, t0.name from be_customer t0 limit 10");
assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name from be_customer t0 limit 10");
}
@Test
+15 -15
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.4.0</version>
<version>14.1.0</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -13,51 +13,51 @@
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.4.8</version>
<version>4.2.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.avaje.composite</groupId>
<artifactId>logback</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>14.4.0</version>
<version>14.1.0</version>
<scope>provided</scope>
</dependency>
@@ -72,7 +72,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:14.3.0</tile>
<tile>io.ebean.tile:enhancement:14.2.0</tile>
</tiles>
</configuration>
</plugin>
@@ -11,12 +11,11 @@ public final class EncodeSerializable implements Encode {
@Override
public byte[] encode(Object value) {
try {
final var baos = new ByteArrayOutputStream();
final var oos = new ObjectOutputStream(baos);
ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream());
oos.writeObject(value);
oos.flush();
oos.close();
return baos.toByteArray();
return new ByteArrayOutputStream().toByteArray();
} catch (IOException e) {
throw new RuntimeException("Failed to decode cache data", e);
}
@@ -1,17 +0,0 @@
package io.ebean.redis.encode;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class EncodeSerializableTest {
@Test
void encode() {
EncodeSerializable encodeSerializable = new EncodeSerializable();
byte[] asBytes = encodeSerializable.encode("HelloWorld");
Object result = encodeSerializable.decode(asBytes);
assertThat(result).isEqualTo("HelloWorld");
}
}
@@ -1,40 +0,0 @@
package org.domain;
import io.ebean.annotation.Cache;
import jakarta.persistence.Entity;
/**
* Using Natural Key caching but no Near Caching so always hitting Redis.
*/
@SuppressWarnings("unused")
@Cache(naturalKey = {"one", "two"})
@Entity
public class OtherOne extends EBase {
private final String one;
private final String two;
private String notes;
public OtherOne(String one, String two, String notes) {
this.one = one;
this.two = two;
this.notes = notes;
}
public String one() {
return one;
}
public String two() {
return two;
}
public String notes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
}
@@ -3,8 +3,10 @@ package org.integration;
import io.ebean.DB;
import io.ebean.cache.ServerCache;
import io.ebean.cache.ServerCacheStatistics;
import org.domain.*;
import org.domain.query.QOtherOne;
import org.domain.Person;
import org.domain.RCust;
import org.domain.UChild;
import org.domain.UParent;
import org.domain.query.QPerson;
import org.domain.query.QRCust;
import org.junit.jupiter.api.Test;
@@ -146,37 +148,6 @@ class IntegrationTest {
assertThat(stats2.getHitCount()).isEqualTo(3);
}
@Test
void testOtherOne() {
DB.save(new OtherOne("A", "B", "ab"));
DB.save(new OtherOne("A", "C", "ac"));
DB.save(new OtherOne("B", "B", "bb"));
ServerCache nkeyCache = DB.cacheManager().naturalKeyCache(OtherOne.class);
nkeyCache.clear();
nkeyCache.statistics(true);
OtherOne ab0 = findOther("A", "B");
OtherOne ab1 = findOther("A", "B");
OtherOne ab2 = findOther("A", "B");
OtherOne bb = findOther("B", "B");
assertThat(ab0).isNotNull();
assertThat(ab1).isNotNull();
assertThat(ab2).isNotNull();
assertThat(bb).isNotNull();
ServerCacheStatistics statistics = nkeyCache.statistics(true);
assertThat(statistics.getHitCount()).isEqualTo(2);
}
private static OtherOne findOther(String a, String b) {
return new QOtherOne()
.one.eq(a)
.two.eq(b)
.findOne();
}
@Test
void test() throws InterruptedException {

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