This is an automated email from the ASF dual-hosted git repository.
yuqi1129 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 56aedb27f1 [#13035] fix(core): Add PostgreSQL group-role batch upsert
(#13037)
56aedb27f1 is described below
commit 56aedb27f1f46089951a36be136ee18263e46b35
Author: Qi Yu <[email protected]>
AuthorDate: Thu Sep 10 08:46:08 2026 +0800
[#13035] fix(core): Add PostgreSQL group-role batch upsert (#13037)
### What changes were proposed in this pull request?
Add the missing PostgreSQL implementation for group-role batch upsert.
Use ON CONFLICT and EXCLUDED values, following the user-role
implementation.
### Why are the changes needed?
The group-role method currently uses MySQL SQL on PostgreSQL.
It has no service caller today, but would fail if called.
Fix: #13035
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Add tests for one and two records to check the SQL and parameter values.
All 14 related unit tests passed. Spotless checks passed.
No live PostgreSQL test was run.
---
.../postgresql/GroupRoleRelPostgreSQLProvider.java | 34 +++++++++++++
.../TestGroupRoleRelPostgreSQLProvider.java | 58 ++++++++++++++++++++++
2 files changed, 92 insertions(+)
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/GroupRoleRelPostgreSQLProvider.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/GroupRoleRelPostgreSQLProvider.java
index 60c611b76a..6f59015d94 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/GroupRoleRelPostgreSQLProvider.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/GroupRoleRelPostgreSQLProvider.java
@@ -24,6 +24,7 @@ import static
org.apache.gravitino.storage.relational.mapper.GroupRoleRelMapper.
import java.util.List;
import org.apache.gravitino.storage.relational.mapper.provider.DatabaseTimeSQL;
import
org.apache.gravitino.storage.relational.mapper.provider.base.GroupRoleRelBaseSQLProvider;
+import org.apache.gravitino.storage.relational.po.GroupRoleRelPO;
import org.apache.ibatis.annotations.Param;
public class GroupRoleRelPostgreSQLProvider extends
GroupRoleRelBaseSQLProvider {
@@ -81,6 +82,39 @@ public class GroupRoleRelPostgreSQLProvider extends
GroupRoleRelBaseSQLProvider
+ " WHERE role_id = #{roleId} AND deleted_at = 0";
}
+ /**
+ * Builds a PostgreSQL batch upsert for group-role relations.
+ *
+ * @param groupRoleRelPOs the group-role relations to insert or update
+ * @return the MyBatis SQL script
+ */
+ @Override
+ public String
batchInsertGroupRoleRelOnDuplicateKeyUpdate(List<GroupRoleRelPO>
groupRoleRelPOs) {
+ return "<script>"
+ + "INSERT INTO "
+ + GROUP_ROLE_RELATION_TABLE_NAME
+ + " (group_id, role_id,"
+ + " audit_info,"
+ + " current_version, last_version, deleted_at)"
+ + " VALUES "
+ + "<foreach collection='groupRoleRels' item='item' separator=','>"
+ + "(#{item.groupId},"
+ + " #{item.roleId},"
+ + " #{item.auditInfo},"
+ + " #{item.currentVersion},"
+ + " #{item.lastVersion},"
+ + " #{item.deletedAt})"
+ + "</foreach>"
+ + " ON CONFLICT (group_id, role_id, deleted_at) DO UPDATE SET"
+ + " group_id = EXCLUDED.group_id,"
+ + " role_id = EXCLUDED.role_id,"
+ + " audit_info = EXCLUDED.audit_info,"
+ + " current_version = EXCLUDED.current_version,"
+ + " last_version = EXCLUDED.last_version,"
+ + " deleted_at = EXCLUDED.deleted_at"
+ + "</script>";
+ }
+
@Override
public String deleteGroupRoleRelMetasByLegacyTimeline(
@Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit)
{
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TestGroupRoleRelPostgreSQLProvider.java
b/core/src/test/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TestGroupRoleRelPostgreSQLProvider.java
index 8fcd67d1a5..b0435202eb 100644
---
a/core/src/test/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TestGroupRoleRelPostgreSQLProvider.java
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TestGroupRoleRelPostgreSQLProvider.java
@@ -18,19 +18,77 @@
*/
package org.apache.gravitino.storage.relational.mapper.provider.postgresql;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import org.apache.gravitino.storage.relational.po.GroupRoleRelPO;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
public class TestGroupRoleRelPostgreSQLProvider {
+ @ParameterizedTest
+ @ValueSource(ints = {1, 2})
+ void testBatchInsertGroupRoleRelOnDuplicateKeyUpdate(int batchSize) {
+ List<GroupRoleRelPO> relations = new ArrayList<>();
+ List<Object> expectedParameters = new ArrayList<>();
+ for (int i = 0; i < batchSize; i++) {
+ GroupRoleRelPO relation =
+ GroupRoleRelPO.builder()
+ .withGroupId(10L + i)
+ .withRoleId(20L + i)
+ .withAuditInfo("audit-" + i)
+ .withCurrentVersion(30L + i)
+ .withLastVersion(40L + i)
+ .withDeletedAt(50L + i)
+ .build();
+ relations.add(relation);
+ expectedParameters.addAll(
+ Arrays.asList(
+ relation.getGroupId(),
+ relation.getRoleId(),
+ relation.getAuditInfo(),
+ relation.getCurrentVersion(),
+ relation.getLastVersion(),
+ relation.getDeletedAt()));
+ }
+
+ String script =
+ new
GroupRoleRelPostgreSQLProvider().batchInsertGroupRoleRelOnDuplicateKeyUpdate(relations);
+ SqlSource sqlSource =
+ new XMLLanguageDriver().createSqlSource(new Configuration(), script,
Map.class);
+ BoundSql boundSql = sqlSource.getBoundSql(Map.of("groupRoleRels",
relations));
+ String sql = boundSql.getSql().replaceAll("\\s+", " ").trim();
+
+ Assertions.assertTrue(sql.startsWith("INSERT INTO group_role_rel "));
+ Assertions.assertTrue(
+ sql.contains("ON CONFLICT (group_id, role_id, deleted_at) DO UPDATE
SET"));
+ Assertions.assertFalse(sql.contains("ON DUPLICATE KEY UPDATE"));
+ Assertions.assertFalse(sql.contains("VALUES("));
+ for (String column :
+ Arrays.asList(
+ "group_id", "role_id", "audit_info", "current_version",
"last_version", "deleted_at")) {
+ Assertions.assertTrue(sql.contains(column + " = EXCLUDED." + column));
+ }
+
+ List<Object> actualParameters = new ArrayList<>();
+ boundSql
+ .getParameterMappings()
+ .forEach(
+ mapping ->
+
actualParameters.add(boundSql.getAdditionalParameter(mapping.getProperty())));
+ Assertions.assertEquals(expectedParameters, actualParameters);
+ }
+
@Test
void testSoftDeleteGroupRoleRelByGroupAndRolesWithEmptyRoles() {
GroupRoleRelPostgreSQLProvider provider = new
GroupRoleRelPostgreSQLProvider();