Skip to content

[#12748] fix(clickhouse): preserve composite primary key on table load - #12765

Merged
yuqi1129 merged 1 commit into
apache:mainfrom
jiangxt2:fix/clickhouse-composite-primary-key-readback
Sep 3, 2026
Merged

[#12748] fix(clickhouse): preserve composite primary key on table load#12765
yuqi1129 merged 1 commit into
apache:mainfrom
jiangxt2:fix/clickhouse-composite-primary-key-readback

Conversation

@jiangxt2

@jiangxt2 jiangxt2 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

This pull request aggregates the ClickHouse primary-key metadata rows returned by ClickHouseTableOperations.getIndexes() before constructing Gravitino indexes. Rows are grouped by the synthetic primary-key name and ordered by KEY_SEQ, so PRIMARY KEY (id, ts) is loaded as one PRIMARY_KEY index whose fields are [[id], [ts]] instead of two independent single-column indexes.

The implementation rejects null, non-positive, or duplicate key sequence values, while allowing positive sequence gaps because their relative order remains unambiguous. Existing single-column primary keys and data-skipping index loading remain unchanged.

The patch also adds direct unit coverage for grouping, ordering, invalid sequence metadata, single-column behavior, and secondary-index compatibility, plus a focused real ClickHouse create-load round-trip test for a two-column primary key.

Why are the changes needed?

The ClickHouse JDBC driver does not expose primary keys through DatabaseMetaData.getPrimaryKeys, so the connector reads system.tables.primary_key and returns one metadata row per key column. The current implementation immediately converts each row into a separate Gravitino index and ignores KEY_SEQ, which loses the identity and field order of a composite primary key.

Aggregating these rows restores the same composite-index contract used by the common JDBC metadata path without changing public APIs, primary-key DDL generation, or data-skipping index parsing.

Fix: #12748

Does this PR introduce any user-facing change?

Yes. Loading a ClickHouse table with a composite primary key now returns one ordered Gravitino PRIMARY_KEY index instead of multiple single-column indexes with the same name. Single-column primary keys are unchanged, and no public API or property key is added or removed.

How was this patch tested?

  • ./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:spotlessCheck --console=plain — passed.
  • ./gradlew rat --console=plain — passed.
  • ./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:test -PskipITs --console=plain — passed; TestClickHouseTableOperationsUnit reported 34 tests, zero skipped, failures, or errors.
  • ./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:build -x test --console=plain — passed.
  • ./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:test --tests 'org.apache.gravitino.catalog.clickhouse.integration.test.CatalogClickHouseIT.testCreateAndLoadCompositePrimaryKey' -PskipDockerTests=false --console=plain --no-daemon — passed against ClickHouse 24.8.14 with tests=1, skipped=0, failures=0, errors=0.
  • ./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:test --tests 'org.apache.gravitino.catalog.clickhouse.integration.test.CatalogClickHouseClusterIT' -PskipDockerTests=false --console=plain --no-daemon — passed against ClickHouse 24.8.14 with tests=18, skipped=0, failures=0, errors=0.
  • A ClickHouse 25.3.2.39 characterization query confirmed that a native PRIMARY KEY (id, ts) produces metadata rows id/1 and ts/2.

…le load

Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
@yuqi1129 yuqi1129 added the branch-1.3 Automatically cherry-pick commit to branch-1.3 label Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Code Coverage Report

Overall Project 68.83% +1.82% 🟢
Files changed 82.24% 🟢

Module Coverage
aliyun 19.74% 🔴
api 51.74% -0.03% 🟢
authorization-common 85.96% 🟢
authorization-ranger 4.38% 🔴
aws 53.54% 🟢
azure 32.1% 🔴
catalog-common 19.1% 🔴
catalog-fileset 80.3% 🟢
catalog-glue 69.24% 🟢
catalog-hive 82.96% 🟢
catalog-jdbc-common 45.69% 🟢
catalog-jdbc-doris 82.69% 🟢
catalog-jdbc-mysql 79.33% 🟢
catalog-jdbc-postgresql 83.39% 🟢
catalog-jdbc-starrocks 79.16% 🟢
catalog-kafka 76.99% 🟢
catalog-lakehouse-generic 60.55% 🟢
catalog-lakehouse-hudi 79.1% 🟢
catalog-lakehouse-iceberg 85.86% 🟢
catalog-lakehouse-paimon 84.26% 🟢
catalog-model 77.99% 🟢
cli 44.48% -0.34% 🟢
client-java 77.48% +2.86% 🟢
common 55.43% -2.21% 🟢
core 83.8% +0.74% 🟢
filesystem-hadoop3 76.45% 🟢
flink 0.0% 🔴
flink-common 52.1% 🟢
flink-runtime 0.0% 🔴
gcp 32.2% 🔴
hadoop-auth 68.0% 🟢
hadoop-common 17.84% 🔴
hive-metastore-common 53.4% 🟢
iceberg-aliyun-bundle 0.0% 🔴
iceberg-common 64.75% 🟢
iceberg-rest-server 75.89% 🟢
idp-basic 85.98% +2.6% 🟢
integration-test-common 0.0% 🔴
jobs 62.92% 🟢
lance-common 32.63% -8.01% 🔴
lance-rest-server 65.46% +23.36% 🟢
lineage 53.02% 🟢
optimizer 83.24% 🟢
optimizer-api 21.95% 🔴
server 88.15% +7.48% 🟢
server-common 80.5% -1.28% 🟢
spark 28.57% 🔴
spark-common 48.92% 🟢
tencent 81.78% 🟢
trino-connector 51.26% 🟢
Files
Module File Coverage
api GroupChange.java 69.23% 🟢
UserChange.java 69.23% 🟢
Group.java 0.0% 🔴
User.java 0.0% 🔴
JobHandle.java 0.0% 🔴
cli ListGroups.java 0.0% 🔴
ListUsers.java 0.0% 🔴
client-java GenericJobHandle.java 100.0% 🟢
GravitinoMetalake.java 92.25% 🟢
GravitinoClient.java 71.59% 🟢
common JobDTO.java 89.47% 🟢
AuthMeResponse.java 81.82% 🟢
GroupDTO.java 70.97% 🟢
UserDTO.java 67.57% 🟢
DTOConverters.java 28.57% 🔴
GroupAddRequest.java 0.0% 🔴
UserAddRequest.java 0.0% 🔴
core Entity.java 100.0% 🟢
AccessControlManager.java 100.0% 🟢
GroupAdd.java 100.0% 🟢
UserAdd.java 100.0% 🟢
AlterGroupEvent.java 100.0% 🟢
AlterGroupFailureEvent.java 100.0% 🟢
AlterGroupPreEvent.java 100.0% 🟢
AlterUserEvent.java 100.0% 🟢
AlterUserFailureEvent.java 100.0% 🟢
AlterUserPreEvent.java 100.0% 🟢
GetGroupByIdEvent.java 100.0% 🟢
GetGroupByIdPreEvent.java 100.0% 🟢
GetUserByIdEvent.java 100.0% 🟢
GetUserByIdFailureEvent.java 100.0% 🟢
GetUserByIdPreEvent.java 100.0% 🟢
RemoveUserByIdPreEvent.java 100.0% 🟢
GroupInfo.java 100.0% 🟢
PolicyDispatcher.java 100.0% 🟢
FilesetMetaBaseSQLProvider.java 100.0% 🟢
FunctionVersionMetaBaseSQLProvider.java 100.0% 🟢
GroupMetaBaseSQLProvider.java 100.0% 🟢
JobMetaBaseSQLProvider.java 100.0% 🟢
MetalakeMetaBaseSQLProvider.java 100.0% 🟢
ModelMetaBaseSQLProvider.java 100.0% 🟢
ModelVersionAliasRelBaseSQLProvider.java 100.0% 🟢
ModelVersionMetaBaseSQLProvider.java 100.0% 🟢
PolicyTagRelBaseSQLProvider.java 100.0% 🟢
PolicyVersionBaseSQLProvider.java 100.0% 🟢
RoleMetaBaseSQLProvider.java 100.0% 🟢
SecurableObjectBaseSQLProvider.java 100.0% 🟢
StatisticBaseSQLProvider.java 100.0% 🟢
TableColumnBaseSQLProvider.java 100.0% 🟢
TableVersionBaseSQLProvider.java 100.0% 🟢
TagMetadataObjectRelBaseSQLProvider.java 100.0% 🟢
UserMetaBaseSQLProvider.java 100.0% 🟢
GroupMetaH2Provider.java 100.0% 🟢
UserMetaH2Provider.java 100.0% 🟢
CatalogMetaPostgreSQLProvider.java 100.0% 🟢
FilesetMetaPostgreSQLProvider.java 100.0% 🟢
FunctionMetaPostgreSQLProvider.java 100.0% 🟢
FunctionVersionMetaPostgreSQLProvider.java 100.0% 🟢
GroupMetaPostgreSQLProvider.java 100.0% 🟢
GroupRoleRelPostgreSQLProvider.java 100.0% 🟢
JobMetaPostgreSQLProvider.java 100.0% 🟢
JobTemplateMetaPostgreSQLProvider.java 100.0% 🟢
ModelMetaPostgreSQLProvider.java 100.0% 🟢
ModelVersionAliasRelPostgreSQLProvider.java 100.0% 🟢
ModelVersionMetaPostgreSQLProvider.java 100.0% 🟢
OwnerMetaPostgreSQLProvider.java 100.0% 🟢
PolicyMetaPostgreSQLProvider.java 100.0% 🟢
PolicyTagRelPostgreSQLProvider.java 100.0% 🟢
PolicyVersionPostgreSQLProvider.java 100.0% 🟢
RoleMetaPostgreSQLProvider.java 100.0% 🟢
SecurableObjectPostgreSQLProvider.java 100.0% 🟢
StatisticPostgresSQLProvider.java 100.0% 🟢
TableColumnPostgreSQLProvider.java 100.0% 🟢
TableMetaPostgreSQLProvider.java 100.0% 🟢
TagMetaPostgreSQLProvider.java 100.0% 🟢
TagMetadataObjectRelPostgreSQLProvider.java 100.0% 🟢
TopicMetaPostgreSQLProvider.java 100.0% 🟢
UserMetaPostgreSQLProvider.java 100.0% 🟢
ViewMetaPostgreSQLProvider.java 100.0% 🟢
TableMetaService.java 100.0% 🟢
MetalakeMetaService.java 99.34% 🟢
GroupEntity.java 98.33% 🟢
SchemaMetaService.java 97.59% 🟢
JobEntity.java 97.22% 🟢
UserEntity.java 97.1% 🟢
UserMetaSQLProviderFactory.java 96.67% 🟢
GroupMetaSQLProviderFactory.java 96.43% 🟢
UserMetaService.java 96.23% 🟢
RoleMetaSQLProviderFactory.java 96.0% 🟢
OwnerMetaBaseSQLProvider.java 95.83% 🟢
JobInfo.java 95.45% 🟢
CatalogMetaService.java 95.16% 🟢
RoleMetaService.java 94.83% 🟢
FilesetMetaService.java 93.98% 🟢
TagMetaBaseSQLProvider.java 93.75% 🟢
GroupMetaService.java 93.07% 🟢
UserInfo.java 91.67% 🟢
FilesetVersionBaseSQLProvider.java 90.91% 🟢
CatalogMetaBaseSQLProvider.java 90.0% 🟢
PermissionManager.java 89.04% 🟢
SchemaMetaPostgreSQLProvider.java 88.89% 🟢
POConverters.java 88.35% 🟢
JobPO.java 88.24% 🟢
GroupRoleRelBaseSQLProvider.java 87.5% 🟢
UserRoleRelBaseSQLProvider.java 87.5% 🟢
FilesetVersionPostgreSQLProvider.java 87.5% 🟢
AccessControlEventDispatcher.java 87.43% 🟢
JobManager.java 86.88% 🟢
TagManager.java 86.75% 🟢
RemoveGroupByIdEvent.java 85.71% 🟢
RemoveUserByIdEvent.java 85.71% 🟢
PolicyMetaBaseSQLProvider.java 85.71% 🟢
UserRoleRelPostgreSQLProvider.java 85.71% 🟢
JobTemplateMetaBaseSQLProvider.java 84.62% 🟢
MetalakeMetaPostgreSQLProvider.java 83.33% 🟢
TopicMetaBaseSQLProvider.java 81.82% 🟢
ModelMetaService.java 81.82% 🟢
TableMetaBaseSQLProvider.java 80.95% 🟢
JDBCBackend.java 80.82% 🟢
GetGroupByExternalIdFailureEvent.java 80.0% 🟢
GetUserByExternalIdFailureEvent.java 80.0% 🟢
RemoveGroupByExternalIdPreEvent.java 80.0% 🟢
RemoveGroupByIdPreEvent.java 80.0% 🟢
RemoveUserByExternalIdPreEvent.java 80.0% 🟢
PolicyManager.java 79.17% 🟢
UserGroupIdManager.java 78.38% 🟢
GetGroupByExternalIdEvent.java 77.78% 🟢
GetUserByExternalIdEvent.java 77.78% 🟢
TopicMetaService.java 77.34% 🟢
UserGroupExternalManager.java 76.92% 🟢
PolicyMetadataObjectRelBaseSQLProvider.java 76.92% 🟢
RelationalEntityStore.java 75.96% 🟢
RemoveGroupByExternalIdEvent.java 71.43% 🟢
RemoveUserByExternalIdEvent.java 71.43% 🟢
FunctionMetaBaseSQLProvider.java 70.59% 🟢
ViewMetaBaseSQLProvider.java 70.59% 🟢
PolicyMetadataObjectRelPostgreSQLProvider.java 70.0% 🟢
SchemaMetaBaseSQLProvider.java 68.0% 🟢
AuthorizationUtils.java 67.08% 🟢
GroupPO.java 63.93% 🟢
UserPO.java 63.24% 🟢
GetGroupByExternalIdPreEvent.java 60.0% 🟢
GetUserByExternalIdPreEvent.java 60.0% 🟢
ViewVersionInfoPostgreSQLProvider.java 57.14% 🔴
ViewVersionInfoBaseSQLProvider.java 55.56% 🔴
AccessControlHookDispatcher.java 30.69% 🔴
RelationalBackend.java 20.0% 🔴
EntityStore.java 18.18% 🔴
SupportsExternalIdOperations.java 0.0% 🔴
SupportsIdOperations.java 0.0% 🔴
AccessControlDispatcher.java 0.0% 🔴
GetGroupByIdFailureEvent.java 0.0% 🔴
RemoveGroupByExternalIdFailureEvent.java 0.0% 🔴
RemoveGroupByIdFailureEvent.java 0.0% 🔴
RemoveUserByExternalIdFailureEvent.java 0.0% 🔴
RemoveUserByIdFailureEvent.java 0.0% 🔴
GroupMetaMapper.java 0.0% 🔴
RoleMetaMapper.java 0.0% 🔴
UserMetaMapper.java 0.0% 🔴
TagDispatcher.java 0.0% 🔴
idp-basic IdpUserDTO.java 100.0% 🟢
AddUserRequest.java 100.0% 🟢
ChangePasswordRequest.java 100.0% 🟢
IdpGroupMetaBaseSQLProvider.java 100.0% 🟢
IdpUserGroupRelBaseSQLProvider.java 100.0% 🟢
IdpUserMetaBaseSQLProvider.java 100.0% 🟢
IdpUserMetaH2Provider.java 100.0% 🟢
IdpGroupMetaPostgreSQLProvider.java 100.0% 🟢
IdpUserGroupRelPostgreSQLProvider.java 100.0% 🟢
IdpUserMetaPostgreSQLProvider.java 100.0% 🟢
IdpUserOperations.java 100.0% 🟢
IdpUserMetaService.java 96.77% 🟢
IdpUserGroupManager.java 92.94% 🟢
IdpUserMetaSQLProviderFactory.java 92.86% 🟢
IdpUserPO.java 90.0% 🟢
IdpPOConverters.java 71.43% 🟢
IdpUser.java 61.54% 🟢
IdpUserWithGroupsPO.java 42.86% 🔴
IdpUserMetaMapper.java 0.0% 🔴
lance-common LanceMetadataFilter.java 33.33% 🔴
GravitinoLanceNameSpaceOperations.java 1.35% 🔴
lance-rest-server LanceTableOperations.java 97.37% 🟢
LanceMetadataAuthorizationMethodInterceptor.java 97.33% 🟢
LanceNamespaceOperations.java 88.37% 🟢
LanceAuthorizationExpressions.java 0.0% 🔴
LanceAuthorizationMetadataFilter.java 0.0% 🔴
LanceRESTAuthInterceptionService.java 0.0% 🔴
server CatalogOperations.java 100.0% 🟢
FunctionOperations.java 100.0% 🟢
GroupOperations.java 100.0% 🟢
ModelOperations.java 100.0% 🟢
OwnerOperations.java 100.0% 🟢
SchemaOperations.java 100.0% 🟢
TagOperations.java 100.0% 🟢
UserOperations.java 100.0% 🟢
ViewOperations.java 100.0% 🟢
BulkOperations.java 98.02% 🟢
PolicyOperations.java 97.35% 🟢
TableOperations.java 97.18% 🟢
TopicOperations.java 97.18% 🟢
RoleOperations.java 95.52% 🟢
JobOperations.java 93.52% 🟢
ConfigServlet.java 88.89% 🟢
FilesetOperations.java 85.71% 🟢
MetalakeOperations.java 79.01% 🟢
AuthnOperations.java 60.0% 🟢
server-common MetadataAuthzHelper.java 59.88% 🔴

@yuqi1129
yuqi1129 merged commit d8066df into apache:main Sep 3, 2026
35 checks passed
jerryshao pushed a commit that referenced this pull request Sep 3, 2026
…ite primary key on table load (#12765) (#12863)

**Cherry-pick Information:**
- Original commit: d8066df
- Target branch: `branch-1.3`
- Status: ✅ Clean cherry-pick (no conflicts)

Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Co-authored-by: StormSpirit <jiangxt2@vip.qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

branch-1.3 Automatically cherry-pick commit to branch-1.3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug report] ClickHouse catalog reads composite primary key as separate indexes

2 participants