singhpk234 commented on code in PR #1686: URL: https://github.com/apache/polaris/pull/1686#discussion_r2165132012
########## persistence/relational-jdbc/src/main/java/org/apache/polaris/persistence/relational/jdbc/JdbcBasePersistenceImpl.java: ########## @@ -622,6 +632,64 @@ public boolean hasChildren( } } + private int loadVersion() { + PreparedQuery query = QueryGenerator.generateVersionQuery(); + try { + List<SchemaVersion> schemaVersion = + datasourceOperations.executeSelect(query, new SchemaVersion()); + if (schemaVersion == null || schemaVersion.size() != 1) { + throw new RuntimeException("Failed to retrieve schema version"); Review Comment: This didn't truly fail right ? may be IllegalStateException ? ########## polaris-core/src/main/java/org/apache/polaris/core/persistence/BasePersistence.java: ########## @@ -403,6 +406,19 @@ boolean hasChildren( long catalogId, long parentId); + /** + * Check if the specified IcebergTableLikeEntity / NamespaceEntity has any sibling entities which + * share a base location + * + * @param callContext the polaris call context + * @param entity the entity to check for overlapping siblings for + * @return Optional.of(Optional.of(location)) if the parent entity has children, + * Optional.of(Optional.empty()) if not, and Optional.empty() if the metastore doesn't support + * this operation + */ + <T extends PolarisEntity & LocationBasedEntity> Optional<Optional<String>> hasOverlappingSiblings( Review Comment: would it make sense to throw here as not implemented ? like we do in the policy ? https://github.com/trinodb/trino/blob/3b3f15d8303983e2db1f523162e535a470fc9825/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java#L624 ########## persistence/relational-jdbc/src/main/java/org/apache/polaris/persistence/relational/jdbc/DatabaseType.java: ########## @@ -44,6 +44,6 @@ public static DatabaseType fromDisplayName(String displayName) { } public String getInitScriptResource() { - return String.format("%s/schema-v1.sql", this.getDisplayName()); + return String.format("%s/schema-v2.sql", this.getDisplayName()); Review Comment: wouldn't version be passed here ? as it will start bootstraping always by v2 ? ########## polaris-core/src/main/java/org/apache/polaris/core/entity/LocationBasedEntity.java: ########## @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.polaris.core.entity; + +/** + * An interface for entity types that represent data stored at some location. These entities provide Review Comment: [optional to address] is it really the data stored ? specially for catalog and namespace ? ########## persistence/relational-jdbc/src/main/java/org/apache/polaris/persistence/relational/jdbc/QueryGenerator.java: ########## @@ -208,6 +209,59 @@ static QueryFragment generateWhereClause( return new QueryFragment(clause, parameters); } + @VisibleForTesting + static PreparedQuery generateVersionQuery() { + return new PreparedQuery("SELECT version_value FROM POLARIS_SCHEMA.VERSION", List.of()); + } + + /** + * Generate a SELECT query to find any entities that have a given realm & parent and that may with + * a given location. The check is performed without consideration for the scheme, so a path on one + * storage type may give a false positive for overlapping with another storage type. This should + * be combined with a check using `StorageLocation`. + * + * @param realmId A realm to search within + * @param parentId A parent entity to search within + * @param baseLocation The base location to look for overlap with, with or without a scheme + * @return The list of possibly overlapping entities that meet the criteria + */ + @VisibleForTesting + public static PreparedQuery generateOverlapQuery( + String realmId, long parentId, String baseLocation) { + StorageLocation baseStorageLocation = StorageLocation.of(baseLocation); + String locationWithoutScheme = baseStorageLocation.withoutScheme(); + + List<String> conditions = new ArrayList<>(); + List<Object> parameters = new ArrayList<>(); + + String[] components = locationWithoutScheme.split("/"); + StringBuilder pathBuilder = new StringBuilder(); + + for (String component : components) { + pathBuilder.append(component).append("/"); + conditions.add("location_without_scheme = ?"); + parameters.add(pathBuilder.toString()); + } Review Comment: Its fine, thanks for the pointer ########## persistence/relational-jdbc/src/main/java/org/apache/polaris/persistence/relational/jdbc/JdbcBasePersistenceImpl.java: ########## @@ -622,6 +632,64 @@ public boolean hasChildren( } } + private int loadVersion() { + PreparedQuery query = QueryGenerator.generateVersionQuery(); + try { + List<SchemaVersion> schemaVersion = + datasourceOperations.executeSelect(query, new SchemaVersion()); + if (schemaVersion == null || schemaVersion.size() != 1) { + throw new RuntimeException("Failed to retrieve schema version"); + } + return schemaVersion.getFirst().getValue(); + } catch (SQLException e) { + LOGGER.error("Failed to load schema version due to {}", e.getMessage(), e); + throw new RuntimeException("Failed to retrieve schema version", e); + } + } + + /** {@inheritDoc} */ + @Override + public <T extends PolarisEntity & LocationBasedEntity> + Optional<Optional<String>> hasOverlappingSiblings( + @Nonnull PolarisCallContext callContext, T entity) { + if (this.version < 2) { + return Optional.empty(); + } + if (entity.getBaseLocation().chars().filter(ch -> ch == '/').count() + > MAX_LOCATION_COMPONENTS) { + return Optional.empty(); + } + + PreparedQuery query = + QueryGenerator.generateOverlapQuery( + realmId, entity.getParentId(), entity.getBaseLocation()); + try { + var results = datasourceOperations.executeSelect(query, new ModelEntity()); + if (!results.isEmpty()) { + StorageLocation entityLocation = StorageLocation.of(entity.getBaseLocation()); + for (PolarisBaseEntity result : results) { + StorageLocation potentialSiblingLocation = + StorageLocation.of(((LocationBasedEntity) result).getBaseLocation()); + if (entityLocation.isChildOf(potentialSiblingLocation) + || potentialSiblingLocation.isChildOf(entityLocation)) { + return Optional.of(Optional.of(potentialSiblingLocation.toString())); Review Comment: I see, if we end up having the prefix check without normalizing it, would it be better to add it when we do normalize ? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@polaris.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org