fmorillo7694 commented on code in PR #206: URL: https://github.com/apache/flink-connector-aws/pull/206#discussion_r4125189796
########## flink-catalog-aws/flink-catalog-aws-glue/src/main/java/org/apache/flink/table/catalog/glue/operator/GlueFunctionOperator.java: ########## @@ -0,0 +1,315 @@ +/* + * 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.flink.table.catalog.glue.operator; + +import org.apache.flink.annotation.Internal; +import org.apache.flink.table.catalog.CatalogFunction; +import org.apache.flink.table.catalog.CatalogFunctionImpl; +import org.apache.flink.table.catalog.ObjectPath; +import org.apache.flink.table.catalog.exceptions.CatalogException; +import org.apache.flink.table.catalog.exceptions.FunctionAlreadyExistException; +import org.apache.flink.table.catalog.exceptions.FunctionNotExistException; +import org.apache.flink.table.catalog.glue.util.GlueCatalogConstants; +import org.apache.flink.table.catalog.glue.util.GlueFunctionsUtil; +import org.apache.flink.table.resource.ResourceUri; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.glue.GlueClient; +import software.amazon.awssdk.services.glue.model.AlreadyExistsException; +import software.amazon.awssdk.services.glue.model.CreateUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.CreateUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.DeleteUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.DeleteUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.EntityNotFoundException; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionsRequest; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionsResponse; +import software.amazon.awssdk.services.glue.model.GlueException; +import software.amazon.awssdk.services.glue.model.PrincipalType; +import software.amazon.awssdk.services.glue.model.UpdateUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.UpdateUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.UserDefinedFunction; +import software.amazon.awssdk.services.glue.model.UserDefinedFunctionInput; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** Utilities for Glue catalog Function related operations. */ +@Internal +public class GlueFunctionOperator extends GlueOperator { + + private static final Logger LOG = LoggerFactory.getLogger(GlueFunctionOperator.class); + + /** + * Constructor to initialize the shared fields. + * + * @param glueClient The Glue client used for interacting with the AWS Glue service. + * @param catalogName The catalog name associated with the Glue operations. + */ + public GlueFunctionOperator(GlueClient glueClient, String catalogName) { + super(glueClient, catalogName); + } + + /** + * Create a function. Function name should be handled in a case-insensitive way. + * + * @param functionPath path of the function + * @param function Flink function to be created + * @throws CatalogException in case of any runtime exception + */ + public void createGlueFunction(ObjectPath functionPath, CatalogFunction function) + throws CatalogException, FunctionAlreadyExistException { + UserDefinedFunctionInput functionInput = createFunctionInput(functionPath, function); + CreateUserDefinedFunctionRequest.Builder createUDFRequest = + CreateUserDefinedFunctionRequest.builder() + .databaseName(functionPath.getDatabaseName()) + .functionInput(functionInput); + try { + CreateUserDefinedFunctionResponse response = + glueClient.createUserDefinedFunction(createUDFRequest.build()); + if (response == null + || (response.sdkHttpResponse() != null + && !response.sdkHttpResponse().isSuccessful())) { + throw new CatalogException( + "Error creating function: " + functionPath.getFullName()); + } + LOG.info("Created Function: {}", functionPath.getFullName()); + } catch (AlreadyExistsException e) { + LOG.error( + String.format( + "%s already Exists. Function language of type: %s. \n%s", + functionPath.getFullName(), function.getFunctionLanguage(), e)); + throw new FunctionAlreadyExistException(catalogName, functionPath, e); + } catch (GlueException e) { + LOG.error("Error creating glue function: {}\n{}", functionPath.getFullName(), e); + throw new CatalogException(GlueCatalogConstants.GLUE_EXCEPTION_MSG_IDENTIFIER, e); + } + } + + /** + * Modify an existing function. Function name should be handled in a case-insensitive way. + * + * @param functionPath path of function. + * @param newFunction modified function. + * @throws CatalogException on runtime errors. + * @throws FunctionNotExistException if the function doesn't exist. + */ + public void alterGlueFunction(ObjectPath functionPath, CatalogFunction newFunction) + throws CatalogException, FunctionNotExistException { + + UserDefinedFunctionInput functionInput = createFunctionInput(functionPath, newFunction); + + UpdateUserDefinedFunctionRequest updateUserDefinedFunctionRequest = + UpdateUserDefinedFunctionRequest.builder() + .functionName(functionPath.getObjectName()) + .databaseName(functionPath.getDatabaseName()) + .functionInput(functionInput) + .build(); + try { + UpdateUserDefinedFunctionResponse response = + glueClient.updateUserDefinedFunction(updateUserDefinedFunctionRequest); + if (response == null + || (response.sdkHttpResponse() != null + && !response.sdkHttpResponse().isSuccessful())) { + throw new CatalogException( + "Error altering function: " + functionPath.getFullName()); + } + LOG.info("Altered Function: {}", functionPath.getFullName()); + } catch (EntityNotFoundException e) { + LOG.error("Function not found: {}", functionPath.getFullName()); + throw new FunctionNotExistException(catalogName, functionPath, e); + } catch (GlueException e) { + LOG.error("Error altering glue function: {}\n{}", functionPath.getFullName(), e); + throw new CatalogException(GlueCatalogConstants.GLUE_EXCEPTION_MSG_IDENTIFIER, e); + } + } + + /** + * Get the user defined function from glue Catalog. Function name should be handled in a + * case-insensitive way. + * + * @param functionPath path of the function + * @return the requested function + * @throws CatalogException in case of any runtime exception + * @throws FunctionNotExistException if the function doesn't exist + */ + public CatalogFunction getGlueFunction(ObjectPath functionPath) + throws CatalogException, FunctionNotExistException { + GetUserDefinedFunctionRequest request = + GetUserDefinedFunctionRequest.builder() + .databaseName(functionPath.getDatabaseName()) + .functionName(functionPath.getObjectName()) + .build(); + try { + GetUserDefinedFunctionResponse response = glueClient.getUserDefinedFunction(request); + UserDefinedFunction udf = response.userDefinedFunction(); + List<ResourceUri> resourceUris = + udf.resourceUris().stream() + .map( + resourceUri -> + new org.apache.flink.table.resource.ResourceUri( + org.apache.flink.table.resource.ResourceType + .valueOf( + resourceUri + .resourceType() + .name()), + resourceUri.uri())) + .collect(Collectors.toList()); + return new CatalogFunctionImpl( + GlueFunctionsUtil.getCatalogFunctionClassName(udf), + GlueFunctionsUtil.getFunctionalLanguage(udf), + resourceUris); + } catch (EntityNotFoundException e) { + LOG.error("Function not found: {}", functionPath.getFullName()); + throw new FunctionNotExistException(catalogName, functionPath, e); + } catch (GlueException e) { + LOG.error("Error fetching function {}: {}", functionPath.getFullName(), e); + throw new CatalogException( + String.format( + "Error getting function %s: %s", + functionPath.getFullName(), e.getMessage()), + e); + } + } + + public List<String> listGlueFunctions(String databaseName) { + GetUserDefinedFunctionsRequest.Builder functionsRequest = + GetUserDefinedFunctionsRequest.builder().databaseName(databaseName); + List<String> glueFunctions = new LinkedList<>(); + try { + GetUserDefinedFunctionsResponse functionsResponse = + glueClient.getUserDefinedFunctions(functionsRequest.build()); + String token = functionsResponse.nextToken(); + glueFunctions.addAll( + functionsResponse.userDefinedFunctions().stream() + .map(UserDefinedFunction::functionName) + .collect(Collectors.toCollection(LinkedList::new))); + while (Optional.ofNullable(token).isPresent()) { + functionsRequest.nextToken(token); + functionsResponse = glueClient.getUserDefinedFunctions(functionsRequest.build()); + glueFunctions.addAll( + functionsResponse.userDefinedFunctions().stream() + .map(UserDefinedFunction::functionName) + .collect(Collectors.toCollection(LinkedList::new))); + token = functionsResponse.nextToken(); Review Comment: Replaced with the SDK paginator (`getUserDefinedFunctionsPaginator`), so there is no manual loop at all. ########## flink-catalog-aws/flink-catalog-aws-glue/src/main/java/org/apache/flink/table/catalog/glue/operator/GlueFunctionOperator.java: ########## @@ -0,0 +1,315 @@ +/* + * 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.flink.table.catalog.glue.operator; + +import org.apache.flink.annotation.Internal; +import org.apache.flink.table.catalog.CatalogFunction; +import org.apache.flink.table.catalog.CatalogFunctionImpl; +import org.apache.flink.table.catalog.ObjectPath; +import org.apache.flink.table.catalog.exceptions.CatalogException; +import org.apache.flink.table.catalog.exceptions.FunctionAlreadyExistException; +import org.apache.flink.table.catalog.exceptions.FunctionNotExistException; +import org.apache.flink.table.catalog.glue.util.GlueCatalogConstants; +import org.apache.flink.table.catalog.glue.util.GlueFunctionsUtil; +import org.apache.flink.table.resource.ResourceUri; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.glue.GlueClient; +import software.amazon.awssdk.services.glue.model.AlreadyExistsException; +import software.amazon.awssdk.services.glue.model.CreateUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.CreateUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.DeleteUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.DeleteUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.EntityNotFoundException; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionsRequest; +import software.amazon.awssdk.services.glue.model.GetUserDefinedFunctionsResponse; +import software.amazon.awssdk.services.glue.model.GlueException; +import software.amazon.awssdk.services.glue.model.PrincipalType; +import software.amazon.awssdk.services.glue.model.UpdateUserDefinedFunctionRequest; +import software.amazon.awssdk.services.glue.model.UpdateUserDefinedFunctionResponse; +import software.amazon.awssdk.services.glue.model.UserDefinedFunction; +import software.amazon.awssdk.services.glue.model.UserDefinedFunctionInput; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** Utilities for Glue catalog Function related operations. */ +@Internal +public class GlueFunctionOperator extends GlueOperator { + + private static final Logger LOG = LoggerFactory.getLogger(GlueFunctionOperator.class); + + /** + * Constructor to initialize the shared fields. + * + * @param glueClient The Glue client used for interacting with the AWS Glue service. + * @param catalogName The catalog name associated with the Glue operations. + */ + public GlueFunctionOperator(GlueClient glueClient, String catalogName) { + super(glueClient, catalogName); + } + + /** + * Create a function. Function name should be handled in a case-insensitive way. + * + * @param functionPath path of the function + * @param function Flink function to be created + * @throws CatalogException in case of any runtime exception + */ + public void createGlueFunction(ObjectPath functionPath, CatalogFunction function) + throws CatalogException, FunctionAlreadyExistException { + UserDefinedFunctionInput functionInput = createFunctionInput(functionPath, function); + CreateUserDefinedFunctionRequest.Builder createUDFRequest = + CreateUserDefinedFunctionRequest.builder() + .databaseName(functionPath.getDatabaseName()) + .functionInput(functionInput); + try { + CreateUserDefinedFunctionResponse response = + glueClient.createUserDefinedFunction(createUDFRequest.build()); + if (response == null + || (response.sdkHttpResponse() != null + && !response.sdkHttpResponse().isSuccessful())) { + throw new CatalogException( + "Error creating function: " + functionPath.getFullName()); + } + LOG.info("Created Function: {}", functionPath.getFullName()); + } catch (AlreadyExistsException e) { + LOG.error( + String.format( + "%s already Exists. Function language of type: %s. \n%s", + functionPath.getFullName(), function.getFunctionLanguage(), e)); + throw new FunctionAlreadyExistException(catalogName, functionPath, e); + } catch (GlueException e) { + LOG.error("Error creating glue function: {}\n{}", functionPath.getFullName(), e); + throw new CatalogException(GlueCatalogConstants.GLUE_EXCEPTION_MSG_IDENTIFIER, e); + } + } + + /** + * Modify an existing function. Function name should be handled in a case-insensitive way. + * + * @param functionPath path of function. + * @param newFunction modified function. + * @throws CatalogException on runtime errors. + * @throws FunctionNotExistException if the function doesn't exist. + */ + public void alterGlueFunction(ObjectPath functionPath, CatalogFunction newFunction) + throws CatalogException, FunctionNotExistException { + + UserDefinedFunctionInput functionInput = createFunctionInput(functionPath, newFunction); + + UpdateUserDefinedFunctionRequest updateUserDefinedFunctionRequest = + UpdateUserDefinedFunctionRequest.builder() + .functionName(functionPath.getObjectName()) + .databaseName(functionPath.getDatabaseName()) + .functionInput(functionInput) + .build(); + try { + UpdateUserDefinedFunctionResponse response = + glueClient.updateUserDefinedFunction(updateUserDefinedFunctionRequest); + if (response == null + || (response.sdkHttpResponse() != null + && !response.sdkHttpResponse().isSuccessful())) { + throw new CatalogException( + "Error altering function: " + functionPath.getFullName()); + } + LOG.info("Altered Function: {}", functionPath.getFullName()); + } catch (EntityNotFoundException e) { + LOG.error("Function not found: {}", functionPath.getFullName()); + throw new FunctionNotExistException(catalogName, functionPath, e); + } catch (GlueException e) { + LOG.error("Error altering glue function: {}\n{}", functionPath.getFullName(), e); + throw new CatalogException(GlueCatalogConstants.GLUE_EXCEPTION_MSG_IDENTIFIER, e); + } + } + + /** + * Get the user defined function from glue Catalog. Function name should be handled in a + * case-insensitive way. + * + * @param functionPath path of the function + * @return the requested function + * @throws CatalogException in case of any runtime exception + * @throws FunctionNotExistException if the function doesn't exist + */ + public CatalogFunction getGlueFunction(ObjectPath functionPath) + throws CatalogException, FunctionNotExistException { + GetUserDefinedFunctionRequest request = + GetUserDefinedFunctionRequest.builder() + .databaseName(functionPath.getDatabaseName()) + .functionName(functionPath.getObjectName()) + .build(); + try { + GetUserDefinedFunctionResponse response = glueClient.getUserDefinedFunction(request); + UserDefinedFunction udf = response.userDefinedFunction(); + List<ResourceUri> resourceUris = + udf.resourceUris().stream() + .map( + resourceUri -> + new org.apache.flink.table.resource.ResourceUri( + org.apache.flink.table.resource.ResourceType + .valueOf( + resourceUri + .resourceType() + .name()), + resourceUri.uri())) + .collect(Collectors.toList()); + return new CatalogFunctionImpl( + GlueFunctionsUtil.getCatalogFunctionClassName(udf), + GlueFunctionsUtil.getFunctionalLanguage(udf), + resourceUris); + } catch (EntityNotFoundException e) { + LOG.error("Function not found: {}", functionPath.getFullName()); + throw new FunctionNotExistException(catalogName, functionPath, e); + } catch (GlueException e) { + LOG.error("Error fetching function {}: {}", functionPath.getFullName(), e); + throw new CatalogException( + String.format( + "Error getting function %s: %s", + functionPath.getFullName(), e.getMessage()), + e); + } + } + + public List<String> listGlueFunctions(String databaseName) { Review Comment: Good catch — the names were returned as stored, so `listFunctions` and `getFunction` disagreed on case. `listGlueFunctions` now returns `FunctionIdentifier.normalizeName(udf.functionName())`, matching what `getFunction` looks up. Covered in `GlueFunctionOperatorTest`. ########## flink-catalog-aws/flink-catalog-aws-glue/src/main/java/org/apache/flink/table/catalog/glue/util/GlueCatalogConstants.java: ########## @@ -0,0 +1,86 @@ +/* + * 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.flink.table.catalog.glue.util; + +import org.apache.flink.annotation.Internal; + +import java.util.regex.Pattern; + +/** + * Constants used throughout the Glue catalog implementation. Includes string literals, patterns, + * and configuration keys. + */ +@Internal +public class GlueCatalogConstants { + public static final String COMMENT = "comment"; + public static final String DEFAULT_SEPARATOR = ":"; + public static final String LOCATION_SEPARATOR = "/"; + public static final String LOCATION_URI = "path"; + public static final String AND = "and"; + public static final String NEXT_LINE = "\n"; + public static final String SPACE = " "; + + public static final String TABLE_OWNER = "owner"; + public static final String TABLE_INPUT_FORMAT = "table.input.format"; + public static final String TABLE_OUTPUT_FORMAT = "table.output.format"; + + // Constants for preserving original case of object names + // These follow the pattern established for column names + public static final String ORIGINAL_DATABASE_NAME = "flink.original-database-name"; + public static final String ORIGINAL_TABLE_NAME = "flink.original-table-name"; + + /** Partition property key carrying the partition's storage location. */ + public static final String PARTITION_LOCATION = "location"; + + public static final String ORIGINAL_COLUMN_NAME = + "originalName"; // Keep existing for backward compatibility + + /** + * Table-level parameter carrying the comma-separated, order-preserving original (declared) + * names of the partition keys. Needed because AWS Glue rejects column-level parameters on + * partition columns ("Parameters not supported for partition columns"), so the originalName + * column-parameter mechanism cannot be used for them. + */ + public static final String ORIGINAL_PARTITION_KEYS = "flink.original-partition-keys"; + + public static final String ORIGINAL_FUNCTION_NAME = "flink.original-function-name"; Review Comment: Removed, along with eleven other unused constants (`DEFAULT_SEPARATOR`, `LOCATION_URI`, `SPACE`, `ORIGINAL_FUNCTION_NAME`, `GLUE_DB_PATTERN`, `IS_PERSISTED`, `EXPLAIN_EXTRAS`, `IS_PHYSICAL`, …) — grep for each showed zero references in main and test code. ########## flink-catalog-aws/flink-catalog-aws-glue/src/main/java/org/apache/flink/table/catalog/glue/operator/GlueOperator.java: ########## @@ -0,0 +1,47 @@ +/* + * 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.flink.table.catalog.glue.operator; + +import org.apache.flink.util.Preconditions; + +import software.amazon.awssdk.services.glue.GlueClient; + +/** + * Abstract base class for Glue operations that contains common functionality for interacting with + * the AWS Glue service. + */ +public abstract class GlueOperator { Review Comment: Done — every class now carries `@Internal` (operators, utils, `ConnectorRegistry`, `GlueFlinkSchemaProperties`, exception) or `@PublicEvolving` (`GlueCatalog`, `GlueCatalogFactory`, the config options). ########## flink-catalog-aws/flink-catalog-aws-glue/src/main/java/org/apache/flink/table/catalog/glue/operator/GluePartitionOperator.java: ########## @@ -0,0 +1,209 @@ +/* + * 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.flink.table.catalog.glue.operator; + +import org.apache.flink.table.catalog.exceptions.CatalogException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.glue.GlueClient; +import software.amazon.awssdk.services.glue.model.CreatePartitionRequest; +import software.amazon.awssdk.services.glue.model.DeletePartitionRequest; +import software.amazon.awssdk.services.glue.model.EntityNotFoundException; +import software.amazon.awssdk.services.glue.model.GetPartitionRequest; +import software.amazon.awssdk.services.glue.model.GetPartitionsRequest; +import software.amazon.awssdk.services.glue.model.GetPartitionsResponse; +import software.amazon.awssdk.services.glue.model.GlueException; +import software.amazon.awssdk.services.glue.model.Partition; +import software.amazon.awssdk.services.glue.model.PartitionInput; +import software.amazon.awssdk.services.glue.model.UpdatePartitionRequest; + +import java.util.ArrayList; +import java.util.List; + +/** + * Handles partition operations for the Glue catalog. Provides functionality for listing, + * retrieving, creating, updating and deleting partitions in AWS Glue, with pagination handled + * internally. + */ +public class GluePartitionOperator extends GlueOperator { Review Comment: Added `GluePartitionOperatorTest` (create/get/list/update/drop lifecycle, missing partition → null, `AlreadyExists`/`EntityNotFound` pass-through, `AccessDenied`/`InvalidInput` translation with the partition values in the message). It runs against the fake by default and against real Glue in real mode; the real-Glue run also caught a bug (see the summary comment: Glue rejects partitions on tables without a location). -- 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: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
