diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml index 5470ec781a..ce3874827e 100644 --- a/nifi-assembly/pom.xml +++ b/nifi-assembly/pom.xml @@ -1154,35 +1154,6 @@ language governing permissions and limitations under the License. --> - - include-iceberg - - false - - allProfiles - - - - - org.apache.nifi - nifi-iceberg-processors-nar - 2.0.0-SNAPSHOT - nar - - - org.apache.nifi - nifi-iceberg-services-api-nar - 2.0.0-SNAPSHOT - nar - - - org.apache.nifi - nifi-iceberg-services-nar - 2.0.0-SNAPSHOT - nar - - - include-all diff --git a/nifi-code-coverage/pom.xml b/nifi-code-coverage/pom.xml index d5d91c8af8..6b845b066b 100644 --- a/nifi-code-coverage/pom.xml +++ b/nifi-code-coverage/pom.xml @@ -1000,33 +1000,6 @@ nifi-hubspot-processors 2.0.0-SNAPSHOT - - org.apache.nifi - nifi-iceberg-common - 2.0.0-SNAPSHOT - - - - org.bouncycastle - bcprov-jdk15on - - - - - org.apache.nifi - nifi-iceberg-processors - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-iceberg-services - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-iceberg-services-api - 2.0.0-SNAPSHOT - org.apache.nifi nifi-iotdb-processors diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/pom.xml deleted file mode 100644 index 232068391b..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/pom.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-iceberg-bundle - 2.0.0-SNAPSHOT - - - nifi-iceberg-common - jar - - - - - - org.apache.nifi - nifi-record - - - org.apache.nifi - nifi-utils - - - org.apache.nifi - nifi-record-serialization-service-api - - - org.apache.nifi - nifi-iceberg-services-api - 2.0.0-SNAPSHOT - provided - - - org.apache.nifi - nifi-kerberos-user-service-api - - - org.apache.nifi - nifi-security-kerberos-api - - - org.apache.nifi - nifi-hadoop-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-dbcp-service-api - - - - - org.apache.iceberg - iceberg-core - ${iceberg.version} - - - org.apache.iceberg - iceberg-hive-metastore - ${iceberg.version} - - - org.apache.iceberg - iceberg-data - ${iceberg.version} - - - org.apache.iceberg - iceberg-parquet - ${iceberg.version} - - - org.apache.iceberg - iceberg-orc - ${iceberg.version} - - - org.apache.hadoop - hadoop-client - ${hadoop.version} - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - - - org.slf4j - slf4j-reload4j - - - commons-logging - commons-logging - - - javax.servlet - javax.servlet-api - - - - org.eclipse.jetty.websocket - websocket-client - - - org.eclipse.jetty - jetty-util - - - - - commons-lang - commons-lang - 2.6 - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/AbstractIcebergProcessor.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/AbstractIcebergProcessor.java deleted file mode 100644 index fdea6b07d4..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/AbstractIcebergProcessor.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading; -import org.apache.nifi.annotation.lifecycle.OnScheduled; -import org.apache.nifi.components.ClassloaderIsolationKeyProvider; -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.context.PropertyContext; -import org.apache.nifi.flowfile.FlowFile; -import org.apache.nifi.hadoop.SecurityUtil; -import org.apache.nifi.kerberos.KerberosUserService; -import org.apache.nifi.processor.AbstractProcessor; -import org.apache.nifi.processor.ProcessContext; -import org.apache.nifi.processor.ProcessSession; -import org.apache.nifi.processor.Relationship; -import org.apache.nifi.processor.exception.ProcessException; -import org.apache.nifi.security.krb.KerberosUser; -import org.apache.nifi.services.iceberg.IcebergCatalogService; -import org.ietf.jgss.GSSException; - -import java.io.IOException; -import java.security.PrivilegedExceptionAction; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; - -import static org.apache.nifi.hadoop.SecurityUtil.getUgiForKerberosUser; -import static org.apache.nifi.processors.iceberg.IcebergUtils.findCause; -import static org.apache.nifi.processors.iceberg.IcebergUtils.getConfigurationFromFiles; - -/** - * Base Iceberg processor class. - */ -@RequiresInstanceClassLoading(cloneAncestorResources = true) -public abstract class AbstractIcebergProcessor extends AbstractProcessor implements ClassloaderIsolationKeyProvider { - - public static final PropertyDescriptor CATALOG = new PropertyDescriptor.Builder() - .name("catalog-service") - .displayName("Catalog Service") - .description("Specifies the Controller Service to use for handling references to table’s metadata files.") - .identifiesControllerService(IcebergCatalogService.class) - .required(true) - .build(); - - public static final PropertyDescriptor KERBEROS_USER_SERVICE = new PropertyDescriptor.Builder() - .name("kerberos-user-service") - .displayName("Kerberos User Service") - .description("Specifies the Kerberos User Controller Service that should be used for authenticating with Kerberos.") - .identifiesControllerService(KerberosUserService.class) - .build(); - - public static final Relationship REL_FAILURE = new Relationship.Builder() - .name("failure") - .description("A FlowFile is routed to this relationship if the operation failed and retrying the operation will also fail, such as an invalid data or schema.") - .build(); - - protected static final AtomicReference kerberosUserReference = new AtomicReference<>(); - protected final AtomicReference ugiReference = new AtomicReference<>(); - - @OnScheduled - public void onScheduled(final ProcessContext context) { - initKerberosCredentials(context); - } - - protected synchronized void initKerberosCredentials(ProcessContext context) { - final KerberosUserService kerberosUserService = context.getProperty(KERBEROS_USER_SERVICE).asControllerService(KerberosUserService.class); - final IcebergCatalogService catalogService = context.getProperty(CATALOG).asControllerService(IcebergCatalogService.class); - - if (kerberosUserService != null) { - KerberosUser kerberosUser; - if (kerberosUserReference.get() == null) { - kerberosUser = kerberosUserService.createKerberosUser(); - } else { - kerberosUser = kerberosUserReference.get(); - } - try { - ugiReference.set(getUgiForKerberosUser(getConfigurationFromFiles(catalogService.getConfigFilePaths()), kerberosUser)); - } catch (IOException e) { - throw new ProcessException("Kerberos authentication failed", e); - } - kerberosUserReference.set(kerberosUser); - } - } - - @Override - public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException { - final FlowFile flowFile = session.get(); - if (flowFile == null) { - return; - } - - final KerberosUser kerberosUser = kerberosUserReference.get(); - if (kerberosUser == null) { - doOnTrigger(context, session, flowFile); - } else { - try { - getUgi().doAs((PrivilegedExceptionAction) () -> { - doOnTrigger(context, session, flowFile); - return null; - }); - - } catch (Exception e) { - if (!handleAuthErrors(e, session, context)) { - getLogger().error("Privileged action failed with kerberos user " + kerberosUser, e); - session.transfer(session.penalize(flowFile), REL_FAILURE); - } - } - } - } - - @Override - public String getClassloaderIsolationKey(PropertyContext context) { - try { - final KerberosUserService kerberosUserService = context.getProperty(KERBEROS_USER_SERVICE).asControllerService(KerberosUserService.class); - if (kerberosUserService != null) { - final KerberosUser kerberosUser = kerberosUserService.createKerberosUser(); - return kerberosUser.getPrincipal(); - } - } catch (IllegalStateException e) { - // the Kerberos controller service is disabled, therefore this part of the isolation key cannot be determined yet - } - - return null; - } - - private UserGroupInformation getUgi() { - SecurityUtil.checkTGTAndRelogin(getLogger(), kerberosUserReference.get()); - return ugiReference.get(); - } - - protected boolean handleAuthErrors(Throwable t, ProcessSession session, ProcessContext context) { - final Optional causeOptional = findCause(t, GSSException.class, gsse -> GSSException.NO_CRED == gsse.getMajor()); - if (causeOptional.isPresent()) { - getLogger().info("No valid Kerberos credential found, retrying login", causeOptional.get()); - kerberosUserReference.get().checkTGTAndRelogin(); - session.rollback(); - context.yield(); - return true; - } - return false; - } - - protected abstract void doOnTrigger(ProcessContext context, ProcessSession session, FlowFile flowFile) throws ProcessException; -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/IcebergUtils.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/IcebergUtils.java deleted file mode 100644 index ba2680c37e..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/IcebergUtils.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import com.google.common.base.Throwables; -import org.apache.commons.lang3.StringUtils; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.Path; -import org.apache.nifi.flowfile.FlowFile; -import org.apache.nifi.processor.ProcessContext; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -public class IcebergUtils { - - /** - * Loads configuration files from the provided paths. - * - * @param configFilePaths list of config file paths separated with comma - * @return merged configuration - */ - public static Configuration getConfigurationFromFiles(List configFilePaths) { - final Configuration conf = new Configuration(); - if (configFilePaths != null) { - for (final String configFile : configFilePaths) { - conf.addResource(new Path(configFile.trim())); - } - } - return conf; - } - - /** - * Collects every non-blank dynamic property from the context. - * - * @param context process context - * @param flowFile FlowFile to evaluate attribute expressions - * @return Map of dynamic properties - */ - public static Map getDynamicProperties(ProcessContext context, FlowFile flowFile) { - return context.getProperties().entrySet().stream() - // filter non-blank dynamic properties - .filter(e -> e.getKey().isDynamic() - && StringUtils.isNotBlank(e.getValue()) - && StringUtils.isNotBlank(context.getProperty(e.getKey()).evaluateAttributeExpressions(flowFile).getValue()) - ) - // convert to Map keys and evaluated property values - .collect(Collectors.toMap( - e -> e.getKey().getName(), - e -> context.getProperty(e.getKey()).evaluateAttributeExpressions(flowFile).getValue() - )); - } - - /** - * Returns an optional with the first throwable in the causal chain that is assignable to the provided cause type, - * and satisfies the provided cause predicate, {@link Optional#empty()} otherwise. - * - * @param t The throwable to inspect for the cause. - * @return Throwable Cause - */ - public static Optional findCause(Throwable t, Class expectedCauseType, Predicate causePredicate) { - return Throwables.getCausalChain(t).stream() - .filter(expectedCauseType::isInstance) - .map(expectedCauseType::cast) - .filter(causePredicate) - .findFirst(); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/UnmatchedColumnBehavior.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/UnmatchedColumnBehavior.java deleted file mode 100644 index 094f0daf60..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/UnmatchedColumnBehavior.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.nifi.components.DescribedValue; - -public enum UnmatchedColumnBehavior implements DescribedValue { - IGNORE_UNMATCHED_COLUMN("Ignore Unmatched Columns", - "Any column in the database that does not have a field in the document will be assumed to not be required. No notification will be logged"), - - WARNING_UNMATCHED_COLUMN("Warn on Unmatched Columns", - "Any column in the database that does not have a field in the document will be assumed to not be required. A warning will be logged"), - - FAIL_UNMATCHED_COLUMN("Fail on Unmatched Columns", - "A flow will fail if any column in the database that does not have a field in the document. An error will be logged"); - - - private final String displayName; - private final String description; - - UnmatchedColumnBehavior(final String displayName, final String description) { - this.displayName = displayName; - this.description = description; - } - - @Override - public String getValue() { - return name(); - } - - @Override - public String getDisplayName() { - return displayName; - } - - @Override - public String getDescription() { - return description; - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/catalog/IcebergCatalogFactory.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/catalog/IcebergCatalogFactory.java deleted file mode 100644 index eac1981735..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/catalog/IcebergCatalogFactory.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.nifi.processors.iceberg.catalog; - -import org.apache.hadoop.conf.Configuration; -import org.apache.iceberg.CatalogProperties; -import org.apache.iceberg.CatalogUtil; -import org.apache.iceberg.catalog.Catalog; -import org.apache.iceberg.hadoop.HadoopCatalog; -import org.apache.iceberg.hive.HiveCatalog; -import org.apache.iceberg.io.FileIO; -import org.apache.iceberg.jdbc.JdbcCatalog; -import org.apache.iceberg.jdbc.JdbcClientPool; -import org.apache.nifi.dbcp.DBCPService; -import org.apache.nifi.services.iceberg.IcebergCatalogProperty; -import org.apache.nifi.services.iceberg.IcebergCatalogService; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -import static org.apache.nifi.processors.iceberg.IcebergUtils.getConfigurationFromFiles; -import static org.apache.nifi.services.iceberg.IcebergCatalogProperty.CATALOG_NAME; -import static org.apache.nifi.services.iceberg.IcebergCatalogProperty.CLIENT_POOL_SERVICE; -import static org.apache.nifi.services.iceberg.IcebergCatalogProperty.METASTORE_URI; -import static org.apache.nifi.services.iceberg.IcebergCatalogProperty.WAREHOUSE_LOCATION; - -public class IcebergCatalogFactory { - - private final IcebergCatalogService catalogService; - - public IcebergCatalogFactory(IcebergCatalogService catalogService) { - this.catalogService = catalogService; - } - - public Catalog create() { - return switch (catalogService.getCatalogType()) { - case HIVE -> initHiveCatalog(catalogService); - case HADOOP -> initHadoopCatalog(catalogService); - case JDBC -> initJdbcCatalog(catalogService); - }; - } - - private Catalog initHiveCatalog(IcebergCatalogService catalogService) { - HiveCatalog catalog = new HiveCatalog(); - - if (catalogService.getConfigFilePaths() != null) { - final Configuration configuration = getConfigurationFromFiles(catalogService.getConfigFilePaths()); - catalog.setConf(configuration); - } - - final Map catalogProperties = catalogService.getCatalogProperties(); - final Map properties = new HashMap<>(); - - if (catalogProperties.containsKey(METASTORE_URI)) { - properties.put(CatalogProperties.URI, (String) catalogProperties.get(METASTORE_URI)); - } - - if (catalogProperties.containsKey(WAREHOUSE_LOCATION)) { - properties.put(CatalogProperties.WAREHOUSE_LOCATION, (String) catalogProperties.get(WAREHOUSE_LOCATION)); - } - - catalog.initialize("hive-catalog", properties); - return catalog; - } - - private Catalog initHadoopCatalog(IcebergCatalogService catalogService) { - final Map catalogProperties = catalogService.getCatalogProperties(); - final String warehousePath = (String) catalogProperties.get(WAREHOUSE_LOCATION); - - if (catalogService.getConfigFilePaths() != null) { - return new HadoopCatalog(getConfigurationFromFiles(catalogService.getConfigFilePaths()), warehousePath); - } else { - return new HadoopCatalog(new Configuration(), warehousePath); - } - } - - private Catalog initJdbcCatalog(IcebergCatalogService catalogService) { - final Map catalogProperties = catalogService.getCatalogProperties(); - final Map properties = new HashMap<>(); - properties.put(CatalogProperties.URI, ""); - properties.put(CatalogProperties.WAREHOUSE_LOCATION, (String) catalogProperties.get(WAREHOUSE_LOCATION)); - - final Configuration configuration = getConfigurationFromFiles(catalogService.getConfigFilePaths()); - final DBCPService dbcpService = (DBCPService) catalogProperties.get(CLIENT_POOL_SERVICE); - - final Function, JdbcClientPool> clientPoolBuilder = props -> new IcebergJdbcClientPool(props, dbcpService); - final Function, FileIO> ioBuilder = props -> CatalogUtil.loadFileIO("org.apache.iceberg.hadoop.HadoopFileIO", props, configuration); - - JdbcCatalog catalog = new JdbcCatalog(ioBuilder, clientPoolBuilder, false); - catalog.setConf(configuration); - catalog.initialize((String) catalogProperties.get(CATALOG_NAME), properties); - return catalog; - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/catalog/IcebergJdbcClientPool.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/catalog/IcebergJdbcClientPool.java deleted file mode 100644 index 1b3fa0f673..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/catalog/IcebergJdbcClientPool.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.nifi.processors.iceberg.catalog; - -import org.apache.iceberg.jdbc.JdbcClientPool; -import org.apache.nifi.dbcp.DBCPService; - -import java.sql.Connection; -import java.util.Map; - -public class IcebergJdbcClientPool extends JdbcClientPool { - - private final DBCPService dbcpService; - - public IcebergJdbcClientPool(Map properties, DBCPService dbcpService) { - super("", properties); - this.dbcpService = dbcpService; - } - - @Override - protected Connection newClient() { - return dbcpService.getConnection(); - } - -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/ArrayElementGetter.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/ArrayElementGetter.java deleted file mode 100644 index 7e0be786e7..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/ArrayElementGetter.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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.nifi.processors.iceberg.converter; - -import org.apache.nifi.serialization.record.DataType; -import org.apache.nifi.serialization.record.field.FieldConverter; -import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; -import org.apache.nifi.serialization.record.type.ArrayDataType; -import org.apache.nifi.serialization.record.type.ChoiceDataType; -import org.apache.nifi.serialization.record.type.EnumDataType; -import org.apache.nifi.serialization.record.util.DataTypeUtils; -import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; - -import javax.annotation.Nullable; -import java.io.Serializable; -import java.sql.Time; -import java.sql.Timestamp; -import java.time.LocalDate; -import java.util.Optional; - -public class ArrayElementGetter { - - private static final String ARRAY_FIELD_NAME = "array element"; - - /** - * Creates an accessor for getting elements in an internal array data structure at the given - * position. - * - * @param dataType the element type of the array - */ - public static ElementGetter createElementGetter(DataType dataType) { - ElementGetter elementGetter; - switch (dataType.getFieldType()) { - case STRING: - elementGetter = element -> DataTypeUtils.toString(element, ARRAY_FIELD_NAME); - break; - case CHAR: - elementGetter = element -> DataTypeUtils.toCharacter(element, ARRAY_FIELD_NAME); - break; - case BOOLEAN: - elementGetter = element -> DataTypeUtils.toBoolean(element, ARRAY_FIELD_NAME); - break; - case DECIMAL: - elementGetter = element -> DataTypeUtils.toBigDecimal(element, ARRAY_FIELD_NAME); - break; - case BYTE: - elementGetter = element -> DataTypeUtils.toByte(element, ARRAY_FIELD_NAME); - break; - case SHORT: - elementGetter = element -> DataTypeUtils.toShort(element, ARRAY_FIELD_NAME); - break; - case INT: - elementGetter = element -> DataTypeUtils.toInteger(element, ARRAY_FIELD_NAME); - break; - case DATE: - elementGetter = element -> { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalDate.class); - return converter.convertField(element, Optional.ofNullable(dataType.getFormat()), ARRAY_FIELD_NAME); - }; - break; - case TIME: - elementGetter = element -> { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(Time.class); - return converter.convertField(element, Optional.ofNullable(dataType.getFormat()), ARRAY_FIELD_NAME); - }; - break; - case LONG: - elementGetter = element -> DataTypeUtils.toLong(element, ARRAY_FIELD_NAME); - break; - case BIGINT: - elementGetter = element -> DataTypeUtils.toBigInt(element, ARRAY_FIELD_NAME); - break; - case FLOAT: - elementGetter = element -> DataTypeUtils.toFloat(element, ARRAY_FIELD_NAME); - break; - case DOUBLE: - elementGetter = element -> DataTypeUtils.toDouble(element, ARRAY_FIELD_NAME); - break; - case TIMESTAMP: - elementGetter = element -> { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(Timestamp.class); - return converter.convertField(element, Optional.ofNullable(dataType.getFormat()), ARRAY_FIELD_NAME); - }; - break; - case ENUM: - elementGetter = element -> DataTypeUtils.toEnum(element, (EnumDataType) dataType, ARRAY_FIELD_NAME); - break; - case UUID: - elementGetter = DataTypeUtils::toUUID; - break; - case ARRAY: - elementGetter = element -> DataTypeUtils.toArray(element, ARRAY_FIELD_NAME, ((ArrayDataType) dataType).getElementType()); - break; - case MAP: - elementGetter = element -> DataTypeUtils.toMap(element, ARRAY_FIELD_NAME); - break; - case RECORD: - elementGetter = element -> DataTypeUtils.toRecord(element, ARRAY_FIELD_NAME); - break; - case CHOICE: - elementGetter = element -> { - final ChoiceDataType choiceDataType = (ChoiceDataType) dataType; - final DataType chosenDataType = DataTypeUtils.chooseDataType(element, choiceDataType); - if (chosenDataType == null) { - throw new IllegalTypeConversionException(String.format( - "Cannot convert value [%s] of type %s for array element to any of the following available Sub-Types for a Choice: %s", - element, element.getClass(), choiceDataType.getPossibleSubTypes())); - } - - return DataTypeUtils.convertType(element, chosenDataType, ARRAY_FIELD_NAME); - }; - break; - default: - throw new IllegalArgumentException("Unsupported field type: " + dataType.getFieldType()); - } - - return element -> { - if (element == null) { - return null; - } - - return elementGetter.getElementOrNull(element); - }; - } - - /** - * Accessor for getting the elements of an array during runtime. - */ - public interface ElementGetter extends Serializable { - @Nullable - Object getElementOrNull(Object element); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/DataConverter.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/DataConverter.java deleted file mode 100644 index da549b263a..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/DataConverter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.nifi.processors.iceberg.converter; - -/** - * Interface for data conversion between NiFi Record and Iceberg Record. - */ -public abstract class DataConverter { - - private String sourceFieldName; - private String targetFieldName; - - public String getSourceFieldName() { - return sourceFieldName; - } - - public String getTargetFieldName() { - return targetFieldName; - } - - public void setSourceFieldName(String sourceFieldName) { - this.sourceFieldName = sourceFieldName; - } - - public void setTargetFieldName(String targetFieldName) { - this.targetFieldName = targetFieldName; - } - - abstract T convert(S data); -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/GenericDataConverters.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/GenericDataConverters.java deleted file mode 100644 index e11041c4fc..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/GenericDataConverters.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * 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.nifi.processors.iceberg.converter; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.Validate; -import org.apache.iceberg.data.GenericRecord; -import org.apache.iceberg.types.Type; -import org.apache.iceberg.types.Types; -import org.apache.nifi.serialization.SimpleRecordSchema; -import org.apache.nifi.serialization.record.DataType; -import org.apache.nifi.serialization.record.Record; -import org.apache.nifi.serialization.record.RecordField; -import org.apache.nifi.serialization.record.RecordFieldType; -import org.apache.nifi.serialization.record.RecordSchema; -import org.apache.nifi.serialization.record.field.FieldConverter; -import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; -import org.apache.nifi.serialization.record.util.DataTypeUtils; - -import java.math.BigDecimal; -import java.nio.ByteBuffer; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - -import static org.apache.nifi.processors.iceberg.converter.RecordFieldGetter.createFieldGetter; - -/** - * Data converter implementations for different data types. - */ -public class GenericDataConverters { - - static class PrimitiveTypeConverter extends DataConverter { - final Type.PrimitiveType targetType; - final DataType sourceType; - - public PrimitiveTypeConverter(final Type.PrimitiveType type, final DataType dataType) { - targetType = type; - sourceType = dataType; - } - - @Override - public Object convert(Object data) { - switch (targetType.typeId()) { - case BOOLEAN: - return DataTypeUtils.toBoolean(data, null); - case INTEGER: - return DataTypeUtils.toInteger(data, null); - case LONG: - return DataTypeUtils.toLong(data, null); - case FLOAT: - return DataTypeUtils.toFloat(data, null); - case DOUBLE: - return DataTypeUtils.toDouble(data, null); - case DATE: - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalDate.class); - return converter.convertField(data, Optional.ofNullable(sourceType.getFormat()), null); - case UUID: - return DataTypeUtils.toUUID(data); - case STRING: - default: - return StandardFieldConverterRegistry.getRegistry().getFieldConverter(String.class).convertField(data, Optional.empty(), null); - } - } - } - - static class TimeConverter extends DataConverter { - - private final String timeFormat; - - public TimeConverter(final String format) { - this.timeFormat = format; - } - - @Override - public LocalTime convert(Object data) { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalTime.class); - return converter.convertField(data, Optional.ofNullable(timeFormat), null); - } - } - - static class TimestampConverter extends DataConverter { - - private final DataType dataType; - - public TimestampConverter(final DataType dataType) { - this.dataType = dataType; - } - - @Override - public LocalDateTime convert(Object data) { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalDateTime.class); - return converter.convertField(data, Optional.ofNullable(dataType.getFormat()), null); - } - } - - static class TimestampWithTimezoneConverter extends DataConverter { - - private final DataType dataType; - - public TimestampWithTimezoneConverter(final DataType dataType) { - this.dataType = dataType; - } - - @Override - public OffsetDateTime convert(Object data) { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(OffsetDateTime.class); - return converter.convertField(data, Optional.ofNullable(dataType.getFormat()), null); - } - } - - static class UUIDtoByteArrayConverter extends DataConverter { - - @Override - public byte[] convert(Object data) { - if (data == null) { - return null; - } - final UUID uuid = DataTypeUtils.toUUID(data); - ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); - byteBuffer.putLong(uuid.getMostSignificantBits()); - byteBuffer.putLong(uuid.getLeastSignificantBits()); - return byteBuffer.array(); - } - } - - static class FixedConverter extends DataConverter { - - private final int length; - - FixedConverter(int length) { - this.length = length; - } - - @Override - public byte[] convert(Byte[] data) { - if (data == null) { - return null; - } - Validate.isTrue(data.length == length, String.format("Cannot write byte array of length %s as fixed[%s]", data.length, length)); - return ArrayUtils.toPrimitive(data); - } - } - - static class BinaryConverter extends DataConverter { - - @Override - public ByteBuffer convert(Byte[] data) { - if (data == null) { - return null; - } - return ByteBuffer.wrap(ArrayUtils.toPrimitive(data)); - } - } - - static class BigDecimalConverter extends DataConverter { - private final int precision; - private final int scale; - - BigDecimalConverter(int precision, int scale) { - this.precision = precision; - this.scale = scale; - } - - @Override - public BigDecimal convert(Object data) { - if (data == null) { - return null; - } - - BigDecimal bigDecimal = DataTypeUtils.toBigDecimal(data, null); - - if (bigDecimal.scale() < scale) { - bigDecimal = bigDecimal.setScale(scale); - } - - Validate.isTrue(bigDecimal.scale() == scale, "Cannot write value as decimal(%s,%s), wrong scale %s for value: %s", precision, scale, bigDecimal.scale(), data); - Validate.isTrue(bigDecimal.precision() <= precision, "Cannot write value as decimal(%s,%s), invalid precision %s for value: %s", - precision, scale, bigDecimal.precision(), data); - return bigDecimal; - } - } - - static class ArrayConverter extends DataConverter> { - private final DataConverter fieldConverter; - private final ArrayElementGetter.ElementGetter elementGetter; - - ArrayConverter(DataConverter elementConverter, DataType dataType) { - this.fieldConverter = elementConverter; - this.elementGetter = ArrayElementGetter.createElementGetter(dataType); - } - - @Override - @SuppressWarnings("unchecked") - public List convert(S[] data) { - if (data == null) { - return null; - } - final int numElements = data.length; - final List result = new ArrayList<>(numElements); - for (int i = 0; i < numElements; i += 1) { - result.add(i, fieldConverter.convert((S) elementGetter.getElementOrNull(data[i]))); - } - return result; - } - } - - static class MapConverter extends DataConverter, Map> { - private final DataConverter keyConverter; - private final DataConverter valueConverter; - private final ArrayElementGetter.ElementGetter keyGetter; - private final ArrayElementGetter.ElementGetter valueGetter; - - MapConverter(DataConverter keyConverter, DataType keyType, DataConverter valueConverter, DataType valueType) { - this.keyConverter = keyConverter; - this.keyGetter = ArrayElementGetter.createElementGetter(keyType); - this.valueConverter = valueConverter; - this.valueGetter = ArrayElementGetter.createElementGetter(valueType); - } - - @Override - @SuppressWarnings("unchecked") - public Map convert(Map data) { - if (data == null) { - return null; - } - final int mapSize = data.size(); - final Object[] keyArray = data.keySet().toArray(); - final Object[] valueArray = data.values().toArray(); - final Map result = new HashMap<>(mapSize); - for (int i = 0; i < mapSize; i += 1) { - result.put(keyConverter.convert((SK) keyGetter.getElementOrNull(keyArray[i])), valueConverter.convert((SV) valueGetter.getElementOrNull(valueArray[i]))); - } - - return result; - } - } - - static class RecordConverter extends DataConverter { - - private final List> converters; - private final Map getters; - - private final Types.StructType schema; - - RecordConverter(List> converters, RecordSchema recordSchema, Types.StructType schema) { - this.schema = schema; - this.converters = converters; - this.getters = new HashMap<>(converters.size()); - - for (DataConverter converter : converters) { - final Optional recordField = recordSchema.getField(converter.getSourceFieldName()); - if (recordField.isEmpty()) { - final Types.NestedField missingField = schema.field(converter.getTargetFieldName()); - if (missingField != null) { - getters.put(converter.getTargetFieldName(), createFieldGetter(convertSchemaTypeToDataType(missingField.type()), missingField.name(), missingField.isOptional())); - } - } else { - final RecordField field = recordField.get(); - // creates a record field accessor for every data converter - getters.put(converter.getTargetFieldName(), createFieldGetter(field.getDataType(), field.getFieldName(), field.isNullable())); - } - } - } - - @Override - public GenericRecord convert(Record data) { - if (data == null) { - return null; - } - final GenericRecord record = GenericRecord.create(schema); - - for (DataConverter converter : converters) { - record.setField(converter.getTargetFieldName(), convert(data, converter)); - } - - return record; - } - - @SuppressWarnings("unchecked") - private T convert(Record record, DataConverter converter) { - return converter.convert((S) getters.get(converter.getTargetFieldName()).getFieldOrNull(record)); - } - } - - public static DataType convertSchemaTypeToDataType(Type schemaType) { - switch (schemaType.typeId()) { - case BOOLEAN: - return RecordFieldType.BOOLEAN.getDataType(); - case INTEGER: - return RecordFieldType.INT.getDataType(); - case LONG: - return RecordFieldType.LONG.getDataType(); - case FLOAT: - return RecordFieldType.FLOAT.getDataType(); - case DOUBLE: - return RecordFieldType.DOUBLE.getDataType(); - case DATE: - return RecordFieldType.DATE.getDataType(); - case TIME: - return RecordFieldType.TIME.getDataType(); - case TIMESTAMP: - return RecordFieldType.TIMESTAMP.getDataType(); - case STRING: - return RecordFieldType.STRING.getDataType(); - case UUID: - return RecordFieldType.UUID.getDataType(); - case FIXED: - case BINARY: - return RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.BYTE.getDataType()); - case DECIMAL: - return RecordFieldType.DECIMAL.getDataType(); - case STRUCT: - // Build a record type from the struct type - Types.StructType structType = schemaType.asStructType(); - List fields = structType.fields(); - List recordFields = new ArrayList<>(fields.size()); - for (Types.NestedField field : fields) { - DataType dataType = convertSchemaTypeToDataType(field.type()); - recordFields.add(new RecordField(field.name(), dataType, field.isOptional())); - } - RecordSchema recordSchema = new SimpleRecordSchema(recordFields); - return RecordFieldType.RECORD.getRecordDataType(recordSchema); - case LIST: - // Build a list type from the elements - Types.ListType listType = schemaType.asListType(); - return RecordFieldType.ARRAY.getArrayDataType(convertSchemaTypeToDataType(listType.elementType()), listType.isElementOptional()); - case MAP: - // Build a map type from the elements - Types.MapType mapType = schemaType.asMapType(); - return RecordFieldType.MAP.getMapDataType(convertSchemaTypeToDataType(mapType.valueType()), mapType.isValueOptional()); - } - throw new IllegalArgumentException("Invalid or unsupported type: " + schemaType); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/IcebergRecordConverter.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/IcebergRecordConverter.java deleted file mode 100644 index d4b504f3e4..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/IcebergRecordConverter.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * 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.nifi.processors.iceberg.converter; - -import org.apache.commons.lang.Validate; -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.Schema; -import org.apache.iceberg.data.GenericRecord; -import org.apache.iceberg.schema.SchemaWithPartnerVisitor; -import org.apache.iceberg.types.Type; -import org.apache.iceberg.types.Types; -import org.apache.nifi.logging.ComponentLog; -import org.apache.nifi.processors.iceberg.UnmatchedColumnBehavior; -import org.apache.nifi.serialization.record.DataType; -import org.apache.nifi.serialization.record.Record; -import org.apache.nifi.serialization.record.RecordField; -import org.apache.nifi.serialization.record.RecordFieldType; -import org.apache.nifi.serialization.record.RecordSchema; -import org.apache.nifi.serialization.record.type.ArrayDataType; -import org.apache.nifi.serialization.record.type.MapDataType; -import org.apache.nifi.serialization.record.type.RecordDataType; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * This class is responsible for schema traversal and data conversion between NiFi and Iceberg internal record structure. - */ -public class IcebergRecordConverter { - - private final DataConverter converter; - public final UnmatchedColumnBehavior unmatchedColumnBehavior; - public ComponentLog logger; - - public GenericRecord convert(Record record) { - return converter.convert(record); - } - - - @SuppressWarnings("unchecked") - public IcebergRecordConverter(Schema schema, RecordSchema recordSchema, FileFormat fileFormat, UnmatchedColumnBehavior unmatchedColumnBehavior, ComponentLog logger) { - this.converter = (DataConverter) IcebergSchemaVisitor.visit(schema, new RecordDataType(recordSchema), fileFormat, unmatchedColumnBehavior, logger); - this.unmatchedColumnBehavior = unmatchedColumnBehavior; - this.logger = logger; - } - - private static class IcebergSchemaVisitor extends SchemaWithPartnerVisitor> { - - public static DataConverter visit(Schema schema, RecordDataType recordDataType, FileFormat fileFormat, UnmatchedColumnBehavior unmatchedColumnBehavior, ComponentLog logger) { - return visit(schema, new RecordTypeWithFieldNameMapper(schema, recordDataType), new IcebergSchemaVisitor(), - new IcebergPartnerAccessors(schema, fileFormat, unmatchedColumnBehavior, logger)); - } - - @Override - public DataConverter schema(Schema schema, DataType dataType, DataConverter converter) { - return converter; - } - - @Override - public DataConverter field(Types.NestedField field, DataType dataType, DataConverter converter) { - // set Iceberg schema field name (targetFieldName) in the data converter - converter.setTargetFieldName(field.name()); - return converter; - } - - @Override - public DataConverter primitive(Type.PrimitiveType type, DataType dataType) { - if (type.typeId() != null) { - switch (type.typeId()) { - case BOOLEAN: - case INTEGER: - case LONG: - case FLOAT: - case DOUBLE: - case DATE: - case STRING: - return new GenericDataConverters.PrimitiveTypeConverter(type, dataType); - case TIME: - return new GenericDataConverters.TimeConverter(dataType.getFormat()); - case TIMESTAMP: - final Types.TimestampType timestampType = (Types.TimestampType) type; - if (timestampType.shouldAdjustToUTC()) { - return new GenericDataConverters.TimestampWithTimezoneConverter(dataType); - } - return new GenericDataConverters.TimestampConverter(dataType); - case UUID: - final UUIDDataType uuidType = (UUIDDataType) dataType; - if (uuidType.getFileFormat() == FileFormat.PARQUET) { - return new GenericDataConverters.UUIDtoByteArrayConverter(); - } - return new GenericDataConverters.PrimitiveTypeConverter(type, dataType); - case FIXED: - final Types.FixedType fixedType = (Types.FixedType) type; - return new GenericDataConverters.FixedConverter(fixedType.length()); - case BINARY: - return new GenericDataConverters.BinaryConverter(); - case DECIMAL: - final Types.DecimalType decimalType = (Types.DecimalType) type; - return new GenericDataConverters.BigDecimalConverter(decimalType.precision(), decimalType.scale()); - default: - throw new UnsupportedOperationException("Unsupported type: " + type.typeId()); - } - } - throw new UnsupportedOperationException("Missing type id from PrimitiveType " + type); - } - - @Override - public DataConverter struct(Types.StructType type, DataType dataType, List> converters) { - Validate.notNull(type, "Can not create reader for null type"); - final RecordTypeWithFieldNameMapper recordType = (RecordTypeWithFieldNameMapper) dataType; - final RecordSchema recordSchema = recordType.getChildSchema(); - - // set NiFi schema field names (sourceFieldName) in the data converters - for (DataConverter converter : converters) { - final Optional mappedFieldName = recordType.getNameMapping(converter.getTargetFieldName()); - if (mappedFieldName.isPresent()) { - final Optional recordField = recordSchema.getField(mappedFieldName.get()); - converter.setSourceFieldName(recordField.get().getFieldName()); - } - } - - return new GenericDataConverters.RecordConverter(converters, recordSchema, type); - } - - @Override - public DataConverter list(Types.ListType listTypeInfo, DataType dataType, DataConverter converter) { - return new GenericDataConverters.ArrayConverter<>(converter, ((ArrayDataType) dataType).getElementType()); - } - - @Override - public DataConverter map(Types.MapType mapType, DataType dataType, DataConverter keyConverter, DataConverter valueConverter) { - return new GenericDataConverters.MapConverter<>(keyConverter, RecordFieldType.STRING.getDataType(), valueConverter, ((MapDataType) dataType).getValueType()); - } - } - - public static class IcebergPartnerAccessors implements SchemaWithPartnerVisitor.PartnerAccessors { - private final Schema schema; - private final FileFormat fileFormat; - private final UnmatchedColumnBehavior unmatchedColumnBehavior; - private final ComponentLog logger; - - IcebergPartnerAccessors(Schema schema, FileFormat fileFormat, UnmatchedColumnBehavior unmatchedColumnBehavior, ComponentLog logger) { - this.schema = schema; - this.fileFormat = fileFormat; - this.unmatchedColumnBehavior = unmatchedColumnBehavior; - this.logger = logger; - } - - @Override - public DataType fieldPartner(DataType dataType, int fieldId, String name) { - Validate.isTrue(dataType instanceof RecordTypeWithFieldNameMapper, String.format("Invalid record: %s is not a record", dataType)); - final RecordTypeWithFieldNameMapper recordType = (RecordTypeWithFieldNameMapper) dataType; - - final Optional mappedFieldName = recordType.getNameMapping(name); - if (UnmatchedColumnBehavior.FAIL_UNMATCHED_COLUMN.equals(unmatchedColumnBehavior)) { - Validate.isTrue(mappedFieldName.isPresent(), String.format("Cannot find field with name '%s' in the record schema", name)); - } - if (mappedFieldName.isEmpty()) { - if (UnmatchedColumnBehavior.WARNING_UNMATCHED_COLUMN.equals(unmatchedColumnBehavior)) { - if (logger != null) { - logger.warn("Cannot find field with name '{}' in the record schema, using the target schema for datatype and a null value", name); - } - } - // If the field is missing, use the expected type from the schema (converted to a DataType) - final Types.NestedField schemaField = schema.findField(fieldId); - final Type schemaFieldType = schemaField.type(); - if (schemaField.isRequired()) { - // Iceberg requires a non-null value for required fields - throw new IllegalArgumentException("Iceberg requires a non-null value for required fields, field: " - + schemaField.name() + ", type: " + schemaFieldType); - } - return GenericDataConverters.convertSchemaTypeToDataType(schemaFieldType); - } - final Optional recordField = recordType.getChildSchema().getField(mappedFieldName.get()); - final DataType fieldType = recordField.get().getDataType(); - - // If the actual record contains a nested record then we need to create a RecordTypeWithFieldNameMapper wrapper object for it. - if (fieldType instanceof RecordDataType) { - return new RecordTypeWithFieldNameMapper(new Schema(schema.findField(fieldId).type().asStructType().fields()), (RecordDataType) fieldType); - } - - // If the field is an Array, and it contains Records then add the record's iceberg schema for creating RecordTypeWithFieldNameMapper - if (fieldType instanceof ArrayDataType && ((ArrayDataType) fieldType).getElementType() instanceof RecordDataType) { - return new ArrayTypeWithIcebergSchema( - new Schema(schema.findField(fieldId).type().asListType().elementType().asStructType().fields()), - ((ArrayDataType) fieldType).getElementType() - ); - } - - // If the field is a Map, and it's value field contains Records then add the record's iceberg schema for creating RecordTypeWithFieldNameMapper - if (fieldType instanceof MapDataType && ((MapDataType) fieldType).getValueType() instanceof RecordDataType) { - return new MapTypeWithIcebergSchema( - new Schema(schema.findField(fieldId).type().asMapType().valueType().asStructType().fields()), - ((MapDataType) fieldType).getValueType() - ); - } - - // If the source field or target field is of type UUID, create a UUIDDataType from it - if (fieldType.getFieldType().equals(RecordFieldType.UUID) || schema.findField(fieldId).type().typeId() == Type.TypeID.UUID) { - return new UUIDDataType(fieldType, fileFormat); - } - - return fieldType; - } - - @Override - public DataType mapKeyPartner(DataType dataType) { - return RecordFieldType.STRING.getDataType(); - } - - @Override - public DataType mapValuePartner(DataType dataType) { - Validate.isTrue(dataType instanceof MapDataType, String.format("Invalid map: %s is not a map", dataType)); - final MapDataType mapType = (MapDataType) dataType; - if (mapType instanceof MapTypeWithIcebergSchema) { - MapTypeWithIcebergSchema typeWithSchema = (MapTypeWithIcebergSchema) mapType; - return new RecordTypeWithFieldNameMapper(typeWithSchema.getValueSchema(), (RecordDataType) typeWithSchema.getValueType()); - } - return mapType.getValueType(); - } - - @Override - public DataType listElementPartner(DataType dataType) { - Validate.isTrue(dataType instanceof ArrayDataType, String.format("Invalid array: %s is not an array", dataType)); - final ArrayDataType arrayType = (ArrayDataType) dataType; - if (arrayType instanceof ArrayTypeWithIcebergSchema) { - ArrayTypeWithIcebergSchema typeWithSchema = (ArrayTypeWithIcebergSchema) arrayType; - return new RecordTypeWithFieldNameMapper(typeWithSchema.getElementSchema(), (RecordDataType) typeWithSchema.getElementType()); - } - return arrayType.getElementType(); - } - } - - /** - * Parquet writer expects the UUID value in different format, so it needs to be converted differently: #1881 - */ - private static class UUIDDataType extends DataType { - - private final FileFormat fileFormat; - - UUIDDataType(DataType dataType, FileFormat fileFormat) { - super(dataType.getFieldType(), dataType.getFormat()); - this.fileFormat = fileFormat; - } - - public FileFormat getFileFormat() { - return fileFormat; - } - } - - /** - * Since the {@link RecordSchema} stores the field name and value pairs in a HashMap it makes the retrieval case-sensitive, so we create a name mapper for case-insensitive handling. - */ - private static class RecordTypeWithFieldNameMapper extends RecordDataType { - - private final Map fieldNameMap; - - RecordTypeWithFieldNameMapper(Schema schema, RecordDataType recordType) { - super(recordType.getChildSchema()); - - // create a lowercase map for the NiFi record schema fields - final Map lowerCaseMap = recordType.getChildSchema().getFieldNames().stream() - .collect(Collectors.toMap(String::toLowerCase, s -> s)); - - // map the Iceberg record schema fields to the NiFi record schema fields - this.fieldNameMap = new HashMap<>(); - schema.columns().forEach((s) -> this.fieldNameMap.put(s.name(), lowerCaseMap.get(s.name().toLowerCase()))); - } - - Optional getNameMapping(String name) { - return Optional.ofNullable(fieldNameMap.get(name)); - } - } - - /** - * Data type for Arrays which contains Records. The class stores the iceberg schema for the element type. - */ - private static class ArrayTypeWithIcebergSchema extends ArrayDataType { - - private final Schema elementSchema; - - public ArrayTypeWithIcebergSchema(Schema elementSchema, DataType elementType) { - super(elementType); - this.elementSchema = elementSchema; - } - - public Schema getElementSchema() { - return elementSchema; - } - } - - /** - * Data type for Maps which contains Records in the entries value. The class stores the iceberg schema for the value type. - */ - private static class MapTypeWithIcebergSchema extends MapDataType { - - private final Schema valueSchema; - - public MapTypeWithIcebergSchema(Schema valueSchema, DataType valueType) { - super(valueType); - this.valueSchema = valueSchema; - } - - public Schema getValueSchema() { - return valueSchema; - } - } - -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/RecordFieldGetter.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/RecordFieldGetter.java deleted file mode 100644 index d0f9d55d87..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-common/src/main/java/org/apache/nifi/processors/iceberg/converter/RecordFieldGetter.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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.nifi.processors.iceberg.converter; - -import org.apache.nifi.serialization.record.DataType; -import org.apache.nifi.serialization.record.Record; -import org.apache.nifi.serialization.record.field.FieldConverter; -import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; -import org.apache.nifi.serialization.record.type.ArrayDataType; -import org.apache.nifi.serialization.record.type.ChoiceDataType; -import org.apache.nifi.serialization.record.type.EnumDataType; -import org.apache.nifi.serialization.record.type.RecordDataType; -import org.apache.nifi.serialization.record.util.DataTypeUtils; -import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; - -import javax.annotation.Nullable; -import java.io.Serializable; -import java.sql.Time; -import java.sql.Timestamp; -import java.time.LocalDate; -import java.util.Optional; - -public class RecordFieldGetter { - - /** - * Creates an accessor for getting elements in an internal record data structure with the given - * field name. - * - * @param dataType the element type of the field - * @param fieldName the name of the field - * @param isNullable indicates if the field's value is nullable - */ - public static FieldGetter createFieldGetter(DataType dataType, String fieldName, boolean isNullable) { - FieldGetter fieldGetter; - switch (dataType.getFieldType()) { - case STRING: - fieldGetter = record -> record.getAsString(fieldName); - break; - case CHAR: - fieldGetter = record -> DataTypeUtils.toCharacter(record.getValue(fieldName), fieldName); - break; - case BOOLEAN: - fieldGetter = record -> record.getAsBoolean(fieldName); - break; - case DECIMAL: - fieldGetter = record -> DataTypeUtils.toBigDecimal(record.getValue(fieldName), fieldName); - break; - case BYTE: - fieldGetter = record -> DataTypeUtils.toByte(record.getValue(fieldName), fieldName); - break; - case SHORT: - fieldGetter = record -> DataTypeUtils.toShort(record.getValue(fieldName), fieldName); - break; - case INT: - fieldGetter = record -> record.getAsInt(fieldName); - break; - case DATE: - fieldGetter = record -> { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalDate.class); - return converter.convertField(record.getValue(fieldName), Optional.ofNullable(dataType.getFormat()), fieldName); - }; - break; - case TIME: - fieldGetter = record -> { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(Time.class); - return converter.convertField(record.getValue(fieldName), Optional.ofNullable(dataType.getFormat()), fieldName); - }; - break; - case LONG: - fieldGetter = record -> record.getAsLong(fieldName); - break; - case BIGINT: - fieldGetter = record -> DataTypeUtils.toBigInt(record.getValue(fieldName), fieldName); - break; - case FLOAT: - fieldGetter = record -> record.getAsFloat(fieldName); - break; - case DOUBLE: - fieldGetter = record -> record.getAsDouble(fieldName); - break; - case TIMESTAMP: - fieldGetter = record -> { - final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(Timestamp.class); - return converter.convertField(record.getValue(fieldName), Optional.ofNullable(dataType.getFormat()), fieldName); - }; - break; - case UUID: - fieldGetter = record -> DataTypeUtils.toUUID(record.getValue(fieldName)); - break; - case ENUM: - fieldGetter = record -> DataTypeUtils.toEnum(record.getValue(fieldName), (EnumDataType) dataType, fieldName); - break; - case ARRAY: - fieldGetter = record -> DataTypeUtils.toArray(record.getValue(fieldName), fieldName, ((ArrayDataType) dataType).getElementType()); - break; - case MAP: - fieldGetter = record -> DataTypeUtils.toMap(record.getValue(fieldName), fieldName); - break; - case RECORD: - fieldGetter = record -> record.getAsRecord(fieldName, ((RecordDataType) dataType).getChildSchema()); - break; - case CHOICE: - fieldGetter = record -> { - final ChoiceDataType choiceDataType = (ChoiceDataType) dataType; - final Object value = record.getValue(fieldName); - final DataType chosenDataType = DataTypeUtils.chooseDataType(value, choiceDataType); - if (chosenDataType == null) { - throw new IllegalTypeConversionException(String.format( - "Cannot convert value [%s] of type %s for field %s to any of the following available Sub-Types for a Choice: %s", - value, value.getClass(), fieldName, choiceDataType.getPossibleSubTypes())); - } - - return DataTypeUtils.convertType(record.getValue(fieldName), chosenDataType, fieldName); - }; - break; - default: - throw new IllegalArgumentException("Unsupported field type: " + dataType.getFieldType()); - } - - if (!isNullable) { - return fieldGetter; - } - - return record -> { - if (record.getValue(fieldName) == null) { - return null; - } - - return fieldGetter.getFieldOrNull(record); - }; - } - - /** - * Accessor for getting the field of a record during runtime. - */ - - public interface FieldGetter extends Serializable { - @Nullable - Object getFieldOrNull(Record record); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/pom.xml deleted file mode 100644 index 3ec9ba5d4f..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/pom.xml +++ /dev/null @@ -1,202 +0,0 @@ - - - - - nifi-iceberg-bundle - org.apache.nifi - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-iceberg-processors-nar - nar - - - - org.apache.nifi - nifi-iceberg-processors - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-iceberg-services-api-nar - 2.0.0-SNAPSHOT - nar - - - - - - - include-hadoop-aws - - false - - - - org.apache.hadoop - hadoop-aws - ${hadoop.version} - - - - - - include-hadoop-azure - - false - - - - org.apache.hadoop - hadoop-azure - ${hadoop.version} - - - com.google.guava - guava - - - com.fasterxml.jackson.core - jackson-core - - - commons-logging - commons-logging - - - - - org.apache.hadoop - hadoop-azure-datalake - ${hadoop.version} - - - com.fasterxml.jackson.core - jackson-core - - - - - - - - include-hadoop-cloud-storage - - false - - - - org.apache.hadoop - hadoop-cloud-storage - ${hadoop.version} - - - log4j - log4j - - - org.apache.logging.log4j - log4j-core - - - org.slf4j - slf4j-log4j12 - - - commons-logging - commons-logging - - - - - - - - include-hadoop-ozone - - false - - - - org.apache.ozone - ozone-client - ${ozone.version} - - - commons-logging - commons-logging - - - org.apache.logging.log4j - log4j-core - - - org.bouncycastle - bcprov-jdk15on - - - org.bouncycastle - bcpkix-jdk15on - - - - - org.apache.ozone - ozone-filesystem - ${ozone.version} - - - org.bouncycastle - bcprov-jdk18on - - - org.bouncycastle - bcpkix-jdk18on - - - - - - include-hadoop-gcp - - false - - - - com.google.cloud.bigdataoss - gcs-connector - hadoop3-${gcs.version} - - - com.google.cloud.bigdataoss - util - ${gcs.version} - - - com.google.cloud.bigdataoss - util-hadoop - hadoop3-${gcs.version} - - - com.google.cloud.bigdataoss - gcsio - ${gcs.version} - - - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/src/main/resources/META-INF/LICENSE b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/src/main/resources/META-INF/LICENSE deleted file mode 100644 index f3574b43b4..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/src/main/resources/META-INF/LICENSE +++ /dev/null @@ -1,222 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - -APACHE NIFI SUBCOMPONENTS: - -The Apache NiFi project contains subcomponents with separate copyright -notices and license terms. Your use of the source code for the these -subcomponents is subject to the terms and conditions of the following -licenses. - - --------------------------------------------------------------------------------- - -This product includes code from Apache Hive. - -* Hive metastore derby schema in hive-schema-3.2.0.derby.sql -* Test methods from IcebergTestUtils.java -* Test metastore from MetastoreCore.java, ScriptRunner.java, ThriftMetastore.java - -Copyright: 2011-2018 The Apache Software Foundation -Home page: https://hive.apache.org/ -License: https://www.apache.org/licenses/LICENSE-2.0 \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/src/main/resources/META-INF/NOTICE b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/src/main/resources/META-INF/NOTICE deleted file mode 100644 index f25c183e91..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors-nar/src/main/resources/META-INF/NOTICE +++ /dev/null @@ -1,505 +0,0 @@ -nifi-iceberg-processors-nar -Copyright 2014-2024 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=========================================== -Apache Software License v2 -=========================================== - - (ASLv2) Apache Iceberg - The following NOTICE information applies: - Apache Iceberg - Copyright 2017-2022 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - (ASLv2) Apache Ant - The following NOTICE information applies: - Apache Ant - Copyright 1999-2016 The Apache Software Foundation - - (ASLv2) Apache Commons Codec - The following NOTICE information applies: - Apache Commons Codec - Copyright 2002-2014 The Apache Software Foundation - - src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java - contains test data from http://aspell.net/test/orig/batch0.tab. - Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) - - =============================================================================== - - The content of package org.apache.commons.codec.language.bm has been translated - from the original php source code available at http://stevemorse.org/phoneticinfo.htm - with permission from the original authors. - Original source copyright: - Copyright (c) 2008 Alexander Beider & Stephen P. Morse. - - (ASLv2) Apache Commons DBCP - The following NOTICE information applies: - Apache Commons DBCP - Copyright 2001-2015 The Apache Software Foundation. - - (ASLv2) Apache HttpComponents - The following NOTICE information applies: - Apache HttpComponents Client - Copyright 1999-2016 The Apache Software Foundation - Apache HttpComponents Core - HttpCore - Copyright 2006-2009 The Apache Software Foundation - - (ASLv2) Apache Commons Pool - The following NOTICE information applies: - Apache Commons Pool - Copyright 1999-2009 The Apache Software Foundation. - - (ASLv2) Apache Commons BeanUtils - The following NOTICE information applies: - Apache Commons BeanUtils - Copyright 2000-2016 The Apache Software Foundation - - (ASLv2) Apache Commons IO - The following NOTICE information applies: - Apache Commons IO - Copyright 2002-2016 The Apache Software Foundation - - (ASLv2) Apache Commons Net - The following NOTICE information applies: - Apache Commons Net - Copyright 2001-2016 The Apache Software Foundation - - (ASLv2) Apache Avro - The following NOTICE information applies: - Apache Avro - Copyright 2009-2017 The Apache Software Foundation - - (ASLv2) Apache Parquet - The following NOTICE information applies: - Apache Parquet MR (Incubating) - Copyright 2014 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - (ASLv2) Audience Annotations - The following NOTICE information applies: - Apache Yetus - Copyright 2008-2018 The Apache Software Foundation - - (ASLv2) Apache Commons Compress - The following NOTICE information applies: - Apache Commons Compress - Copyright 2002-2017 The Apache Software Foundation - - The files in the package org.apache.commons.compress.archivers.sevenz - were derived from the LZMA SDK, version 9.20 (C/ and CPP/7zip/), - which has been placed in the public domain: - - "LZMA SDK is placed in the public domain." (http://www.7-zip.org/sdk.html) - - (ASLv2) Apache Commons Configuration - The following NOTICE information applies: - Apache Commons Configuration - Copyright 2001-2017 The Apache Software Foundation - - (ASLv2) Apache Commons Text - The following NOTICE information applies: - Apache Commons Text - Copyright 2001-2018 The Apache Software Foundation - - (ASLv2) Apache Commons CLI - The following NOTICE information applies: - Apache Commons CLI - Copyright 2001-2017 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - (ASLv2) Apache Commons Collections - The following NOTICE information applies: - Apache Commons Collections - Copyright 2001-2016 The Apache Software Foundation - - (ASLv2) Apache Commons Daemon - The following NOTICE information applies: - Apache Commons Daemon - Copyright 2002-2013 The Apache Software Foundation - - (ASLv2) Apache Ivy - The following NOTICE information applies: - Copyright 2007-2017 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - Portions of Ivy were originally developed at - Jayasoft SARL (http://www.jayasoft.fr/) - and are licensed to the Apache Software Foundation under the - "Software Grant License Agreement" - - SSH and SFTP support is provided by the JCraft JSch package, - which is open source software, available under - the terms of a BSD style license. - The original software and related information is available - at http://www.jcraft.com/jsch/. - - (ASLv2) Apache Commons Math - The following NOTICE information applies: - Apache Commons Math - Copyright 2001-2012 The Apache Software Foundation - - (ASLv2) Apache Hive - The following NOTICE information applies: - Apache Hive - Copyright 2008-2015 The Apache Software Foundation - - This product includes software developed by The Apache Software - Foundation (http://www.apache.org/). - - This product includes Jersey (https://jersey.java.net/) - Copyright (c) 2010-2014 Oracle and/or its affiliates. - - This project includes software copyrighted by Microsoft Corporation and - licensed under the Apache License, Version 2.0. - - This project includes software copyrighted by Dell SecureWorks and - licensed under the Apache License, Version 2.0. - - (ASLv2) Jackson JSON processor - The following NOTICE information applies: - # Jackson JSON processor - - Jackson is a high-performance, Free/Open Source JSON processing library. - It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has - been in development since 2007. - It is currently developed by a community of developers, as well as supported - commercially by FasterXML.com. - - ## Licensing - - Jackson core and extension components may licensed under different licenses. - To find the details that apply to this artifact see the accompanying LICENSE file. - For more information, including possible other licensing options, contact - FasterXML.com (http://fasterxml.com). - - ## Credits - - A list of contributors may be found from CREDITS file, which is included - in some artifacts (usually source distributions); but is always available - from the source code management (SCM) system project uses. - - (ASLv2) BoneCP - The following NOTICE information applies: - BoneCP - Copyright 2010 Wallace Wadge - - (ASLv2) Apache Hadoop - The following NOTICE information applies: - The binary distribution of this product bundles binaries of - org.iq80.leveldb:leveldb-api (https://github.com/dain/leveldb), which has the - following notices: - * Copyright 2011 Dain Sundstrom - * Copyright 2011 FuseSource Corp. http://fusesource.com - - The binary distribution of this product bundles binaries of - org.fusesource.hawtjni:hawtjni-runtime (https://github.com/fusesource/hawtjni), - which has the following notices: - * This product includes software developed by FuseSource Corp. - http://fusesource.com - * This product includes software developed at - Progress Software Corporation and/or its subsidiaries or affiliates. - * This product includes software developed by IBM Corporation and others. - - (ASLv2) Apache Commons Lang - The following NOTICE information applies: - Apache Commons Lang - Copyright 2001-2015 The Apache Software Foundation - - (ASLv2) Apache Curator - The following NOTICE information applies: - Curator Framework - Copyright 2011-2014 The Apache Software Foundation - - Curator Client - Copyright 2011-2014 The Apache Software Foundation - - Curator Recipes - Copyright 2011-2014 The Apache Software Foundation - - (ASLv2) Apache Derby - The following NOTICE information applies: - Apache Derby - Copyright 2004-2014 Apache, Apache DB, Apache Derby, Apache Torque, Apache JDO, Apache DDLUtils, - the Derby hat logo, the Apache JDO logo, and the Apache feather logo are trademarks of The Apache Software Foundation. - - (ASLv2) Apache Geronimo - The following NOTICE information applies: - Apache Geronimo - Copyright 2003-2008 The Apache Software Foundation - - (ASLv2) Jettison - The following NOTICE information applies: - Copyright 2006 Envoi Solutions LLC - - (ASLv2) Jetty - The following NOTICE information applies: - Jetty Web Container - Copyright 1995-2019 Mort Bay Consulting Pty Ltd. - - (ASLv2) Apache log4j - The following NOTICE information applies: - Apache log4j - Copyright 2007 The Apache Software Foundation - - (ASLv2) Apache Thrift - The following NOTICE information applies: - Apache Thrift - Copyright 2006-2010 The Apache Software Foundation. - - (ASLv2) Dropwizard Metrics - The following NOTICE information applies: - Metrics - Copyright 2010-2013 Coda Hale and Yammer, Inc. - - This product includes code derived from the JSR-166 project (ThreadLocalRandom, Striped64, - LongAdder), which was released with the following comments: - - Written by Doug Lea with assistance from members of JCP JSR-166 - Expert Group and released to the public domain, as explained at - http://creativecommons.org/publicdomain/zero/1.0/ - - (ASLv2) Joda Time - The following NOTICE information applies: - This product includes software developed by - Joda.org (http://www.joda.org/). - - (ASLv2) The Netty Project - The following NOTICE information applies: - The Netty Project - Copyright 2011 The Netty Project - - (ASLv2) Apache ZooKeeper - The following NOTICE information applies: - Apache ZooKeeper - Copyright 2009-2012 The Apache Software Foundation - - (ASLv2) Google GSON - The following NOTICE information applies: - Copyright 2008 Google Inc. - - (ASLv2) JPam - The following NOTICE information applies: - Copyright 2003-2006 Greg Luck - - (ASLv2) Groovy 2.4.16 (http://www.groovy-lang.org) - groovy-2.4.16-indy - groovy-json-2.4.16-indy - groovy-sql-2.4.16-indy - The following NOTICE information applies: - Apache Groovy - Copyright 2003-2018 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - This product includes/uses ANTLR (http://www.antlr2.org/) - developed by Terence Parr 1989-2006 - - (ASLv2) ASM Based Accessors Helper Used By JSON Smart (net.minidev:accessors-smart:jar:1.2 - http://www.minidev.net/) - The following NOTICE information applies: - ASM Based Accessors Helper Used By JSON Smart 1.2 - Copyright 2017, Uriel Chemouni - - (ASLv2) JSON Smart (net.minidev:json-smart:jar:2.3 - http://www.minidev.net/) - The following NOTICE information applies: - JSON Smart 2.3 - Copyright 2017, Uriel Chemouni, Eitan Raviv - - (ASLv2) Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt - https://connect2id.com/products/nimbus-jose-jwt) - The following NOTICE information applies: - Nimbus JOSE+JWT - Copyright 2021, Connect2id Ltd. - - (ASLv2) Woodstox (com.fasterxml.woodstox:woodstox-core:bundle:5.3.0 - https://github.com/FasterXML/woodstox) - The following NOTICE information applies: - Woodstox Core 5.3.0 - Copyright 2015, FasterXML, LLC - - (ASLv2) Joda Time - The following NOTICE information applies: - This product includes software developed by - Joda.org (http://www.joda.org/). - - (ASLv2) java-util - The following NOTICE information applies: - java-util - Copyright 2011-2017 Metamarkets Group Inc. - - (ASLv2) JCIP Annotations Under Apache License - The following NOTICE information applies: - JCIP Annotations Under Apache License - Copyright 2013 Stephen Connolly. - - (ASLv2) Google GSON - The following NOTICE information applies: - Copyright 2008 Google Inc. - - (ASLv2) Guava - The following NOTICE information applies: - Guava - Copyright 2015 The Guava Authors - - (ASLv2) OkHttp - The following NOTICE information applies: - OkHttp - Copyright (C) 2014 Square, Inc. - - (ASLv2) Okio - The following NOTICE information applies: - Okio - Copyright (C) 2014 Square, Inc. - - (ASLv2) Dropwizard Metrics - The following NOTICE information applies: - Dropwizard Metrics - Copyright 2010-2013 Coda Hale and Yammer, Inc., 2014-2017 Dropwizard Team - - (ASLv2) atinject (javax.inject:javax.inject) - The following NOTICE information applies: - atinject - Copyright - - (ASLv2) opencsv (net.sf.opencsv:opencsv:2.3) - - (ASLv2) JetBrains/java-annotations - The following NOTICE information applies: - JetBrains/java-annotations - Copyright 2000-2016 JetBrains s.r.o. - - (ASLv2) Apache Kerby - The following NOTICE information applies: - Apache Kerby - Copyright 2003-2018 The Apache Software Foundation - - (ASLv2) Carrotsearch HPPC - The following NOTICE information applies: - HPPC borrowed code, ideas or both from: - - * Apache Lucene, http://lucene.apache.org/ - (Apache license) - * Fastutil, http://fastutil.di.unimi.it/ - (Apache license) - * Koloboke, https://github.com/OpenHFT/Koloboke - (Apache license) - - (ASLv2) Ehcache 2.x - The following NOTICE information applies: - Copyright 2003-2010 Terracotta, Inc. - - (ASLv2) Google Guice - The following NOTICE information applies: - Google Guice - Core Library - Copyright 2006-2011 Google, Inc. - - Google Guice - Extensions - Servlet - Copyright 2006-2011 Google, Inc. - - (ASLv2) Apache Arrow - The following NOTICE information applies: - Copyright 2016-2019 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - - (ASLv2) Apache ORC - The following NOTICE information applies: - Copyright 2013-2019 The Apache Software Foundation - - This product includes software developed by The Apache Software - Foundation (http://www.apache.org/). - - This product includes software developed by Hewlett-Packard: - (c) Copyright [2014-2015] Hewlett-Packard Development Company, L.P - -************************ -Common Development and Distribution License 1.1 -************************ - - The following binary components are provided under the Common Development and Distribution License 1.1. See project link for details. - - (CDDL 1.1) (GPL2 w/ CPE) jersey-client (com.sun.jersey:jersey-client:jar:1.19 - https://jersey.java.net) - (CDDL 1.1) (GPL2 w/ CPE) jersey-core (com.sun.jersey:jersey-core:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) jersey-json (com.sun.jersey:jersey-json:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) jersey-server (com.sun.jersey:jersey-server:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) jersey-guice (com.sun.jersey.contribs:jersey-guice:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) Java Architecture For XML Binding (javax.xml.bind:jaxb-api:jar:2.2.11 - https://jaxb.dev.java.net/) - -************************ -Common Development and Distribution License 1.0 -************************ - - The following binary components are provided under the Common Development and Distribution License 1.0. See project link for details. - - (CDDL 1.0) JavaServlet(TM) Specification (javax.servlet:servlet-api:jar:3.1.0 - no url available) - (CDDL 1.0) JavaServer Pages(TM) API (javax.servlet.jsp:jsp-api:jar:2.1 - http://jsp.java.net) - (CDDL 1.0) JSR311 API (javax.ws.rs:jsr311-api:jar:1.1.1 - https://jsr311.dev.java.net) - -***************** -Public Domain -***************** - - The following binary components are provided to the 'Public Domain'. See project link for details. - - (Public Domain) AOP Alliance 1.0 (http://aopalliance.sourceforge.net/) - - -************************ -Eclipse Distribution License 1.0 -************************ - - The following binary components are provided under the Eclipse Distribution License 1.0. - - (EDL 1.0) Jakarta Activation API (jakarta.activation:jakarta.activation-api:jar:1.2.1) - (EDL 1.0) Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3) - -************************ -Eclipse Public License 2.0 -************************ - - The following binary components are provided under the Eclipse Public License 2.0. - - (EPL 2.0) javax.ws.rs-api (https://github.com/eclipse-ee4j/jaxrs-api) javax.ws.rs:javax.ws.rs-api:bundle:2.1.1 - -************************ -BSD License -************************ - - (BSD) JSch - The following NOTICE information applies: - Copyright (c) 2002-2015 Atsuhiko Yamanaka, JCraft,Inc. - All rights reserved. - https://www.jcraft.com/jsch/ - - (BSD 3-Clause) JLine Bundle - The following NOTICE information applies: - Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved. - https://github.com/jline/jline1 - - (BSD 3-Clause) ThreeTen-Extra - The following NOTICE information applies: - Copyright (c) 2007-2022, Stephen Colebourne & Michael Nascimento Santos. - https://github.com/ThreeTen/threeten-extra/ - -************************ -Go License -************************ - -The following binary components are provided under the Go License. See project link for details. - - (Go) RE2/J - The following NOTICE information applies: - Copyright (c) 2009 The Go Authors. All rights reserved. - https://github.com/google/re2j \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/pom.xml deleted file mode 100644 index e16dd764b8..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/pom.xml +++ /dev/null @@ -1,335 +0,0 @@ - - - - - nifi-iceberg-bundle - org.apache.nifi - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-iceberg-processors - jar - - - - - - - org.apache.nifi - nifi-record - - - org.apache.nifi - nifi-utils - - - org.apache.nifi - nifi-record-serialization-service-api - - - org.apache.nifi - nifi-iceberg-services-api - 2.0.0-SNAPSHOT - provided - - - org.apache.nifi - nifi-iceberg-common - 2.0.0-SNAPSHOT - - - - - org.apache.hive - hive-exec - ${hive.version} - core - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - - - commons-logging - commons-logging - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-web - - - org.apache.logging.log4j - log4j-1.2-api - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.apache.hive - hive-llap-tez - - - org.apache.calcite - calcite-core - - - org.apache.calcite - calcite-druid - - - org.apache.calcite.avatica - avatica - - - com.google.guava - guava - - - org.apache.hadoop - hadoop-auth - - - org.apache.hadoop - hadoop-yarn-common - - - org.apache.hadoop - hadoop-yarn-server-common - - - org.apache.hadoop - hadoop-yarn-registry - - - org.apache.hadoop - hadoop-yarn-server-resourcemanager - - - org.bouncycastle - bcprov-jdk15on - - - org.codehaus.groovy - groovy-all - - - org.apache.ivy - ivy - - - org.eclipse.jetty - jetty-server - - - - - org.bouncycastle - bcprov-jdk18on - - - org.apache.hive - hive-metastore - ${hive.version} - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - - - commons-logging - commons-logging - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-web - - - org.apache.logging.log4j - log4j-1.2-api - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.apache.orc - orc-core - - - org.apache.hbase - hbase-client - - - org.apache.hbase - hbase-mapreduce - - - org.apache.hbase - hbase-hadoop2-compat - - - co.cask.tephra - tephra-api - - - co.cask.tephra - tephra-core - - - co.cask.tephra - tephra-hbase-compat-1.0 - - - org.apache.parquet - parquet-hadoop-bundle - - - com.tdunning - json - - - com.zaxxer - HikariCP - - - com.google.guava - guava - - - org.eclipse.jetty - jetty-xml - - - org.eclipse.jetty - jetty-server - - - org.eclipse.jetty - jetty-servlet - - - org.eclipse.jetty - jetty-webapp - - - org.eclipse.jetty - jetty-util - - - org.eclipse.jetty - jetty-http - - - org.eclipse.jetty - jetty-rewrite - - - - - - org.apache.derby - derbytools - ${derby.version} - - - org.apache.derby - derby - ${derby.version} - - - - - org.apache.hadoop - hadoop-hdfs - ${hadoop.version} - test - - - log4j - log4j - - - commons-logging - commons-logging - - - org.eclipse.jetty - jetty-server - - - org.eclipse.jetty - jetty-util - - - org.eclipse.jetty - jetty-util-ajax - - - - - org.apache.nifi - nifi-iceberg-test-utils - 2.0.0-SNAPSHOT - test - - - org.apache.nifi - nifi-avro-record-utils - 2.0.0-SNAPSHOT - test - - - org.apache.nifi - nifi-mock-record-utils - - - org.apache.nifi - nifi-kerberos-user-service-api - test - - - org.apache.nifi - nifi-iceberg-services - 2.0.0-SNAPSHOT - test - - - org.apache.nifi - nifi-dbcp-service - 2.0.0-SNAPSHOT - test - - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/PutIceberg.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/PutIceberg.java deleted file mode 100644 index cecdbff791..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/PutIceberg.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.iceberg.AppendFiles; -import org.apache.iceberg.DataFile; -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.PendingUpdate; -import org.apache.iceberg.Table; -import org.apache.iceberg.catalog.Catalog; -import org.apache.iceberg.catalog.Namespace; -import org.apache.iceberg.catalog.TableIdentifier; -import org.apache.iceberg.exceptions.CommitFailedException; -import org.apache.iceberg.io.TaskWriter; -import org.apache.iceberg.io.WriteResult; -import org.apache.iceberg.util.Tasks; -import org.apache.nifi.annotation.behavior.DynamicProperty; -import org.apache.nifi.annotation.behavior.WritesAttribute; -import org.apache.nifi.annotation.behavior.WritesAttributes; -import org.apache.nifi.annotation.documentation.CapabilityDescription; -import org.apache.nifi.annotation.documentation.Tags; -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.components.ValidationContext; -import org.apache.nifi.components.ValidationResult; -import org.apache.nifi.context.PropertyContext; -import org.apache.nifi.expression.ExpressionLanguageScope; -import org.apache.nifi.flowfile.FlowFile; -import org.apache.nifi.flowfile.attributes.CoreAttributes; -import org.apache.nifi.hadoop.SecurityUtil; -import org.apache.nifi.processor.ProcessContext; -import org.apache.nifi.processor.ProcessSession; -import org.apache.nifi.processor.Relationship; -import org.apache.nifi.processor.exception.ProcessException; -import org.apache.nifi.processor.util.StandardValidators; -import org.apache.nifi.processors.iceberg.catalog.IcebergCatalogFactory; -import org.apache.nifi.processors.iceberg.converter.IcebergRecordConverter; -import org.apache.nifi.processors.iceberg.writer.IcebergTaskWriterFactory; -import org.apache.nifi.serialization.RecordReader; -import org.apache.nifi.serialization.RecordReaderFactory; -import org.apache.nifi.serialization.record.Record; -import org.apache.nifi.services.iceberg.IcebergCatalogService; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import static org.apache.iceberg.TableProperties.DEFAULT_FILE_FORMAT; -import static org.apache.iceberg.TableProperties.DEFAULT_FILE_FORMAT_DEFAULT; -import static org.apache.nifi.processors.iceberg.IcebergUtils.getConfigurationFromFiles; -import static org.apache.nifi.processors.iceberg.IcebergUtils.getDynamicProperties; - -@Tags({"iceberg", "put", "table", "store", "record", "parse", "orc", "parquet", "avro"}) -@CapabilityDescription("This processor uses Iceberg API to parse and load records into Iceberg tables. " + - "The incoming data sets are parsed with Record Reader Controller Service and ingested into an Iceberg table using the configured catalog service and provided table information. " + - "The target Iceberg table should already exist and it must have matching schemas with the incoming records, " + - "which means the Record Reader schema must contain all the Iceberg schema fields, every additional field which is not present in the Iceberg schema will be ignored. " + - "To avoid 'small file problem' it is recommended pre-appending a MergeRecord processor.") -@DynamicProperty( - name = "A custom key to add to the snapshot summary. The value must start with 'snapshot-property.' prefix.", - value = "A custom value to add to the snapshot summary.", - expressionLanguageScope = ExpressionLanguageScope.FLOWFILE_ATTRIBUTES, - description = "Adds an entry with custom-key and corresponding value in the snapshot summary. The key format must be 'snapshot-property.custom-key'.") -@WritesAttributes({ - @WritesAttribute(attribute = "iceberg.record.count", description = "The number of records in the FlowFile.") -}) -public class PutIceberg extends AbstractIcebergProcessor { - - public static final String ICEBERG_RECORD_COUNT = "iceberg.record.count"; - public static final String ICEBERG_SNAPSHOT_SUMMARY_PREFIX = "snapshot-property."; - public static final String ICEBERG_SNAPSHOT_SUMMARY_FLOWFILE_UUID = "nifi-flowfile-uuid"; - - static final PropertyDescriptor RECORD_READER = new PropertyDescriptor.Builder() - .name("record-reader") - .displayName("Record Reader") - .description("Specifies the Controller Service to use for parsing incoming data and determining the data's schema.") - .identifiesControllerService(RecordReaderFactory.class) - .required(true) - .build(); - - static final PropertyDescriptor CATALOG_NAMESPACE = new PropertyDescriptor.Builder() - .name("catalog-namespace") - .displayName("Catalog Namespace") - .description("The namespace of the catalog.") - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .required(true) - .addValidator(StandardValidators.NON_BLANK_VALIDATOR) - .build(); - - static final PropertyDescriptor TABLE_NAME = new PropertyDescriptor.Builder() - .name("table-name") - .displayName("Table Name") - .description("The name of the Iceberg table to write to.") - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .required(true) - .addValidator(StandardValidators.NON_BLANK_VALIDATOR) - .build(); - - static final PropertyDescriptor UNMATCHED_COLUMN_BEHAVIOR = new PropertyDescriptor.Builder() - .name("unmatched-column-behavior") - .displayName("Unmatched Column Behavior") - .description("If an incoming record does not have a field mapping for all of the database table's columns, this property specifies how to handle the situation.") - .allowableValues(UnmatchedColumnBehavior.class) - .defaultValue(UnmatchedColumnBehavior.FAIL_UNMATCHED_COLUMN) - .required(true) - .build(); - - static final PropertyDescriptor FILE_FORMAT = new PropertyDescriptor.Builder() - .name("file-format") - .displayName("File Format") - .description("File format to use when writing Iceberg data files." + - " If not set, then the 'write.format.default' table property will be used, default value is parquet.") - .allowableValues(new FileFormat[]{FileFormat.AVRO, FileFormat.PARQUET, FileFormat.ORC}) - .build(); - - static final PropertyDescriptor MAXIMUM_FILE_SIZE = new PropertyDescriptor.Builder() - .name("maximum-file-size") - .displayName("Maximum File Size") - .description("The maximum size that a file can be, if the file size is exceeded a new file will be generated with the remaining data." + - " If not set, then the 'write.target-file-size-bytes' table property will be used, default value is 512 MB.") - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .addValidator(StandardValidators.LONG_VALIDATOR) - .build(); - - static final PropertyDescriptor NUMBER_OF_COMMIT_RETRIES = new PropertyDescriptor.Builder() - .name("number-of-commit-retries") - .displayName("Number of Commit Retries") - .description("Number of times to retry a commit before failing.") - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .defaultValue("10") - .addValidator(StandardValidators.INTEGER_VALIDATOR) - .build(); - - static final PropertyDescriptor MINIMUM_COMMIT_WAIT_TIME = new PropertyDescriptor.Builder() - .name("minimum-commit-wait-time") - .displayName("Minimum Commit Wait Time") - .description("Minimum time to wait before retrying a commit.") - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .defaultValue("100 ms") - .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) - .build(); - - static final PropertyDescriptor MAXIMUM_COMMIT_WAIT_TIME = new PropertyDescriptor.Builder() - .name("maximum-commit-wait-time") - .displayName("Maximum Commit Wait Time") - .description("Maximum time to wait before retrying a commit.") - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .defaultValue("2 sec") - .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) - .build(); - - static final PropertyDescriptor MAXIMUM_COMMIT_DURATION = new PropertyDescriptor.Builder() - .name("maximum-commit-duration") - .displayName("Maximum Commit Duration") - .description("Total retry timeout period for a commit.") - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .defaultValue("30 sec") - .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) - .build(); - - static final Relationship REL_SUCCESS = new Relationship.Builder() - .name("success") - .description("A FlowFile is routed to this relationship after the data ingestion was successful.") - .build(); - - private static final List PROPERTIES = List.of( - RECORD_READER, - CATALOG, - CATALOG_NAMESPACE, - TABLE_NAME, - UNMATCHED_COLUMN_BEHAVIOR, - FILE_FORMAT, - MAXIMUM_FILE_SIZE, - KERBEROS_USER_SERVICE, - NUMBER_OF_COMMIT_RETRIES, - MINIMUM_COMMIT_WAIT_TIME, - MAXIMUM_COMMIT_WAIT_TIME, - MAXIMUM_COMMIT_DURATION - ); - - public static final Set RELATIONSHIPS = Set.of(REL_SUCCESS, REL_FAILURE); - - @Override - protected List getSupportedPropertyDescriptors() { - return PROPERTIES; - } - - @Override - public Set getRelationships() { - return RELATIONSHIPS; - } - - @Override - protected PropertyDescriptor getSupportedDynamicPropertyDescriptor(final String propertyDescriptorName) { - return new PropertyDescriptor.Builder() - .name(propertyDescriptorName) - .required(false) - .addValidator((subject, input, context) -> { - ValidationResult.Builder builder = new ValidationResult.Builder().subject(subject).input(input); - if (subject.startsWith(ICEBERG_SNAPSHOT_SUMMARY_PREFIX)) { - builder.valid(true); - } else { - builder.valid(false).explanation("Dynamic property key must begin with '" + ICEBERG_SNAPSHOT_SUMMARY_PREFIX + "'"); - } - return builder.build(); - }) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .dynamic(true) - .build(); - } - - @Override - protected Collection customValidate(ValidationContext context) { - final List problems = new ArrayList<>(); - final IcebergCatalogService catalogService = context.getProperty(CATALOG).asControllerService(IcebergCatalogService.class); - boolean catalogServiceEnabled = context.getControllerServiceLookup().isControllerServiceEnabled(catalogService); - - if (catalogServiceEnabled) { - final boolean kerberosUserServiceIsSet = context.getProperty(KERBEROS_USER_SERVICE).isSet(); - final boolean securityEnabled = SecurityUtil.isSecurityEnabled(getConfigurationFromFiles(catalogService.getConfigFilePaths())); - - if (securityEnabled && !kerberosUserServiceIsSet) { - problems.add(new ValidationResult.Builder() - .subject(KERBEROS_USER_SERVICE.getDisplayName()) - .valid(false) - .explanation("'hadoop.security.authentication' is set to 'kerberos' in the hadoop configuration files but no KerberosUserService is configured.") - .build()); - } - - if (!securityEnabled && kerberosUserServiceIsSet) { - problems.add(new ValidationResult.Builder() - .subject(KERBEROS_USER_SERVICE.getDisplayName()) - .valid(false) - .explanation("KerberosUserService is configured but 'hadoop.security.authentication' is not set to 'kerberos' in the hadoop configuration files.") - .build()); - } - } - - return problems; - } - - @Override - public void doOnTrigger(ProcessContext context, ProcessSession session, FlowFile flowFile) throws ProcessException { - final long startNanos = System.nanoTime(); - final RecordReaderFactory readerFactory = context.getProperty(RECORD_READER).asControllerService(RecordReaderFactory.class); - final String fileFormat = context.getProperty(FILE_FORMAT).getValue(); - final String maximumFileSize = context.getProperty(MAXIMUM_FILE_SIZE).evaluateAttributeExpressions(flowFile).getValue(); - - Catalog catalog = null; - Table table = null; - TaskWriter taskWriter = null; - int recordCount = 0; - - try (final InputStream in = session.read(flowFile); - final RecordReader reader = readerFactory.createRecordReader(flowFile, in, getLogger())) { - catalog = loadCatalog(context); - table = loadTable(context, flowFile, catalog); - final FileFormat format = getFileFormat(table.properties(), fileFormat); - final IcebergTaskWriterFactory taskWriterFactory = new IcebergTaskWriterFactory(table, flowFile.getId(), format, maximumFileSize); - taskWriter = taskWriterFactory.create(); - final UnmatchedColumnBehavior unmatchedColumnBehavior = context.getProperty(UNMATCHED_COLUMN_BEHAVIOR).asAllowableValue(UnmatchedColumnBehavior.class); - - final IcebergRecordConverter recordConverter = new IcebergRecordConverter(table.schema(), reader.getSchema(), format, unmatchedColumnBehavior, getLogger()); - - Record record; - while ((record = reader.nextRecord()) != null) { - taskWriter.write(recordConverter.convert(record)); - recordCount++; - } - - final WriteResult result = taskWriter.complete(); - appendDataFiles(context, flowFile, table, result); - } catch (Exception e) { - if (!handleAuthErrors(e, session, context)) { - getLogger().error("Exception occurred while writing Iceberg records", e); - session.transfer(session.penalize(flowFile), REL_FAILURE); - } - - try { - if (taskWriter != null) { - abort(taskWriter.dataFiles(), table); - } - } catch (Exception ex) { - getLogger().warn("Failed to abort uncommitted data files", ex); - } - return; - } finally { - if (catalog instanceof Closeable) { - try { - ((Closeable) catalog).close(); - } catch (IOException e) { - getLogger().warn("Failed to close catalog", e); - } - } - } - - flowFile = session.putAttribute(flowFile, ICEBERG_RECORD_COUNT, String.valueOf(recordCount)); - final long transferMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos); - session.getProvenanceReporter().send(flowFile, table.location(), transferMillis); - session.transfer(flowFile, REL_SUCCESS); - } - - /** - * Loads a table from the catalog service with the provided values from the property context. - * - * @param context holds the user provided information for the {@link Catalog} and the {@link Table} - * @return loaded table - */ - private Table loadTable(final PropertyContext context, final FlowFile flowFile, final Catalog catalog) { - final String catalogNamespace = context.getProperty(CATALOG_NAMESPACE).evaluateAttributeExpressions(flowFile).getValue(); - final String tableName = context.getProperty(TABLE_NAME).evaluateAttributeExpressions(flowFile).getValue(); - - final Namespace namespace = Namespace.of(catalogNamespace); - final TableIdentifier tableIdentifier = TableIdentifier.of(namespace, tableName); - - return catalog.loadTable(tableIdentifier); - } - - private Catalog loadCatalog(final PropertyContext context) { - final IcebergCatalogService catalogService = context.getProperty(CATALOG).asControllerService(IcebergCatalogService.class); - final IcebergCatalogFactory catalogFactory = new IcebergCatalogFactory(catalogService); - - return catalogFactory.create(); - } - - /** - * Appends the pending data files to the given {@link Table}. - * - * @param context processor context - * @param table table to append - * @param result datafiles created by the {@link TaskWriter} - */ - void appendDataFiles(ProcessContext context, FlowFile flowFile, Table table, WriteResult result) { - final int numberOfCommitRetries = context.getProperty(NUMBER_OF_COMMIT_RETRIES).evaluateAttributeExpressions(flowFile).asInteger(); - final long minimumCommitWaitTime = context.getProperty(MINIMUM_COMMIT_WAIT_TIME).evaluateAttributeExpressions(flowFile).asTimePeriod(TimeUnit.MILLISECONDS); - final long maximumCommitWaitTime = context.getProperty(MAXIMUM_COMMIT_WAIT_TIME).evaluateAttributeExpressions(flowFile).asTimePeriod(TimeUnit.MILLISECONDS); - final long maximumCommitDuration = context.getProperty(MAXIMUM_COMMIT_DURATION).evaluateAttributeExpressions(flowFile).asTimePeriod(TimeUnit.MILLISECONDS); - - final AppendFiles appender = table.newAppend(); - Arrays.stream(result.dataFiles()).forEach(appender::appendFile); - - addSnapshotSummaryProperties(context, appender, flowFile); - - Tasks.foreach(appender) - .exponentialBackoff(minimumCommitWaitTime, maximumCommitWaitTime, maximumCommitDuration, 2.0) - .retry(numberOfCommitRetries) - .onlyRetryOn(CommitFailedException.class) - .run(PendingUpdate::commit); - } - - /** - * Adds the FlowFile's uuid and additional entries provided in Dynamic properties to the snapshot summary. - * - * @param context processor context - * @param appender table appender to set the snapshot summaries - * @param flowFile the FlowFile to get the uuid from - */ - private void addSnapshotSummaryProperties(ProcessContext context, AppendFiles appender, FlowFile flowFile) { - appender.set(ICEBERG_SNAPSHOT_SUMMARY_FLOWFILE_UUID, flowFile.getAttribute(CoreAttributes.UUID.key())); - - for (Map.Entry dynamicProperty : getDynamicProperties(context, flowFile).entrySet()) { - String key = dynamicProperty.getKey().substring(ICEBERG_SNAPSHOT_SUMMARY_PREFIX.length()); - appender.set(key, dynamicProperty.getValue()); - } - } - - /** - * Determines the write file format from the requested value and the table configuration. - * - * @param tableProperties table properties - * @param fileFormat requested file format from the processor - * @return file format to use - */ - private FileFormat getFileFormat(Map tableProperties, String fileFormat) { - final String fileFormatName = fileFormat != null ? fileFormat : tableProperties.getOrDefault(DEFAULT_FILE_FORMAT, DEFAULT_FILE_FORMAT_DEFAULT); - return FileFormat.valueOf(fileFormatName.toUpperCase(Locale.ENGLISH)); - } - - /** - * Deletes the completed data files that have not been committed to the table yet. - * - * @param dataFiles files created by the task writer - * @param table table - */ - void abort(DataFile[] dataFiles, Table table) { - Tasks.foreach(dataFiles) - .retry(3) - .run(file -> table.io().deleteFile(file.path().toString())); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/writer/IcebergPartitionedWriter.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/writer/IcebergPartitionedWriter.java deleted file mode 100644 index 0b3f98e7c5..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/writer/IcebergPartitionedWriter.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.nifi.processors.iceberg.writer; - -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.PartitionKey; -import org.apache.iceberg.PartitionSpec; -import org.apache.iceberg.Schema; -import org.apache.iceberg.data.InternalRecordWrapper; -import org.apache.iceberg.data.Record; -import org.apache.iceberg.io.FileAppenderFactory; -import org.apache.iceberg.io.FileIO; -import org.apache.iceberg.io.OutputFileFactory; -import org.apache.iceberg.io.PartitionedFanoutWriter; - -/** - * This class adapts {@link Record} for partitioned writing. - */ -public class IcebergPartitionedWriter extends PartitionedFanoutWriter { - - private final PartitionKey partitionKey; - private final InternalRecordWrapper wrapper; - - public IcebergPartitionedWriter(PartitionSpec spec, FileFormat format, FileAppenderFactory appenderFactory, OutputFileFactory fileFactory, - FileIO io, long targetFileSize, Schema schema) { - super(spec, format, appenderFactory, fileFactory, io, targetFileSize); - this.partitionKey = new PartitionKey(spec, schema); - this.wrapper = new InternalRecordWrapper(schema.asStruct()); - } - - @Override - protected PartitionKey partition(Record record) { - partitionKey.partition(wrapper.wrap(record)); - return partitionKey; - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/writer/IcebergTaskWriterFactory.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/writer/IcebergTaskWriterFactory.java deleted file mode 100644 index 4dc2bbb6c0..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/java/org/apache/nifi/processors/iceberg/writer/IcebergTaskWriterFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.nifi.processors.iceberg.writer; - -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.PartitionSpec; -import org.apache.iceberg.Schema; -import org.apache.iceberg.Table; -import org.apache.iceberg.TableProperties; -import org.apache.iceberg.data.GenericAppenderFactory; -import org.apache.iceberg.data.Record; -import org.apache.iceberg.io.FileAppenderFactory; -import org.apache.iceberg.io.FileIO; -import org.apache.iceberg.io.OutputFileFactory; -import org.apache.iceberg.io.TaskWriter; -import org.apache.iceberg.io.UnpartitionedWriter; -import org.apache.iceberg.util.PropertyUtil; - -/** - * Factory class to create the suitable {@link TaskWriter} based on the {@link Table}'s properties - */ -public class IcebergTaskWriterFactory { - - private final Schema schema; - private final PartitionSpec spec; - private final FileIO io; - private final long targetFileSize; - private final FileFormat fileFormat; - private final FileAppenderFactory appenderFactory; - private final OutputFileFactory outputFileFactory; - - public IcebergTaskWriterFactory(Table table, long taskId, FileFormat fileFormat, String targetFileSize) { - this.schema = table.schema(); - this.spec = table.spec(); - this.io = table.io(); - this.fileFormat = fileFormat; - - this.targetFileSize = targetFileSize != null ? Long.parseLong(targetFileSize) : - PropertyUtil.propertyAsLong(table.properties(), TableProperties.WRITE_TARGET_FILE_SIZE_BYTES, TableProperties.WRITE_TARGET_FILE_SIZE_BYTES_DEFAULT); - - this.outputFileFactory = OutputFileFactory.builderFor(table, table.spec().specId(), taskId).format(fileFormat).build(); - this.appenderFactory = new GenericAppenderFactory(schema, spec); - } - - public TaskWriter create() { - if (spec.isUnpartitioned()) { - return new UnpartitionedWriter<>(spec, fileFormat, appenderFactory, outputFileFactory, io, targetFileSize); - } else { - return new IcebergPartitionedWriter(spec, fileFormat, appenderFactory, outputFileFactory, io, targetFileSize, schema); - } - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor deleted file mode 100644 index f884831b07..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -org.apache.nifi.processors.iceberg.PutIceberg diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/resources/docs/org.apache.nifi.processors.iceberg.PutIceberg/additionalDetails.md b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/resources/docs/org.apache.nifi.processors.iceberg.PutIceberg/additionalDetails.md deleted file mode 100644 index 3870e91e5d..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/main/resources/docs/org.apache.nifi.processors.iceberg.PutIceberg/additionalDetails.md +++ /dev/null @@ -1,46 +0,0 @@ - - -# PutIceberg - -### Description - -Iceberg is a high-performance format for huge analytic tables. The PutIceberg processor is capable of pushing data into -Iceberg tables using different types of Iceberg catalog implementations. - -### Commit retry properties - -Iceberg supports multiple concurrent writes using optimistic concurrency. The processor's commit retry implementation is -using **exponential backoff** with **jitter** and **scale factor 2**, and provides the following properties to configure -the behaviour according to its usage. - -* Number Of Commit Retries (default: 10) - Number of retries that the processor is going to try to commit the new data - files. -* Minimum Commit Wait Time (default: 100 ms) - Minimum time that the processor is going to wait before each commit - attempt. -* Maximum Commit Wait Time (default: 2 sec) - Maximum time that the processor is going to wait before each commit - attempt. -* Maximum Commit Duration (default: 30 sec) - Maximum duration that the processor is going to wait before failing the - current processor event's commit. - -The NiFi side retry logic is built on top of the Iceberg commit retry logic which can be configured through table -properties. See -more: [Table behavior properties](https://iceberg.apache.org/docs/latest/configuration/#table-behavior-properties) - -### Snapshot summary properties - -The processor provides an option to add additional properties to the snapshot summary using dynamic properties. The -additional property must have the 'snapshot-property.' prefix in the dynamic property key but the actual entry will be -inserted without it. Each snapshot automatically gets the FlowFile's uuid in the 'nifi-flowfile-uuid' summary property. \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/AbstractTestPutIceberg.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/AbstractTestPutIceberg.java deleted file mode 100644 index cd1c5f37c8..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/AbstractTestPutIceberg.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.avro.Schema; -import org.apache.commons.io.IOUtils; -import org.apache.iceberg.catalog.Catalog; -import org.apache.iceberg.catalog.TableIdentifier; -import org.apache.iceberg.types.Types; -import org.apache.nifi.avro.AvroTypeUtil; -import org.apache.nifi.reporting.InitializationException; -import org.apache.nifi.serialization.record.MockRecordParser; -import org.apache.nifi.serialization.record.RecordField; -import org.apache.nifi.serialization.record.RecordSchema; -import org.apache.nifi.util.TestRunner; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; - -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.NAMESPACE; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.RECORD_READER_SERVICE; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.createTemporaryDirectory; - -public class AbstractTestPutIceberg { - - protected static final String TABLE_NAME = "users"; - - protected static final TableIdentifier TABLE_IDENTIFIER = TableIdentifier.of(NAMESPACE, TABLE_NAME); - - protected static final org.apache.iceberg.Schema USER_SCHEMA = new org.apache.iceberg.Schema( - Types.NestedField.required(1, "id", Types.IntegerType.get()), - Types.NestedField.required(2, "name", Types.StringType.get()), - Types.NestedField.required(3, "department", Types.StringType.get()) - ); - - protected TestRunner runner; - protected PutIceberg processor; - protected Catalog catalog; - protected String warehousePath; - protected static Schema inputSchema; - - protected void initRecordReader() throws InitializationException { - final MockRecordParser readerFactory = new MockRecordParser(); - final RecordSchema recordSchema = AvroTypeUtil.createSchema(inputSchema); - - for (RecordField recordField : recordSchema.getFields()) { - readerFactory.addSchemaField(recordField); - } - - readerFactory.addRecord(0, "John", "Finance"); - readerFactory.addRecord(1, "Jill", "Finance"); - readerFactory.addRecord(2, "James", "Marketing"); - readerFactory.addRecord(3, "Joana", "Sales"); - - runner.addControllerService(RECORD_READER_SERVICE, readerFactory); - runner.enableControllerService(readerFactory); - - runner.setProperty(PutIceberg.RECORD_READER, RECORD_READER_SERVICE); - } - - @BeforeAll - public static void initSchema() throws IOException { - final String avroSchema = IOUtils.toString(Files.newInputStream(Paths.get("src/test/resources/user.avsc")), StandardCharsets.UTF_8); - inputSchema = new Schema.Parser().parse(avroSchema); - } - - @BeforeEach - public void setUp() { - warehousePath = createTemporaryDirectory().getAbsolutePath(); - processor = new PutIceberg(); - } - - @AfterEach - public void tearDown() { - catalog.dropTable(TABLE_IDENTIFIER); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestDataFileActions.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestDataFileActions.java deleted file mode 100644 index 6bdd7dd5f7..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestDataFileActions.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.hadoop.conf.Configuration; -import org.apache.iceberg.AppendFiles; -import org.apache.iceberg.DataFile; -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.PartitionSpec; -import org.apache.iceberg.Schema; -import org.apache.iceberg.Table; -import org.apache.iceberg.catalog.Namespace; -import org.apache.iceberg.catalog.TableIdentifier; -import org.apache.iceberg.data.Record; -import org.apache.iceberg.exceptions.CommitFailedException; -import org.apache.iceberg.hadoop.HadoopCatalog; -import org.apache.iceberg.io.TaskWriter; -import org.apache.iceberg.io.WriteResult; -import org.apache.iceberg.types.Types; -import org.apache.nifi.flowfile.FlowFile; -import org.apache.nifi.logging.ComponentLog; -import org.apache.nifi.processor.ProcessContext; -import org.apache.nifi.processors.iceberg.converter.IcebergRecordConverter; -import org.apache.nifi.processors.iceberg.writer.IcebergTaskWriterFactory; -import org.apache.nifi.serialization.SimpleRecordSchema; -import org.apache.nifi.serialization.record.MapRecord; -import org.apache.nifi.serialization.record.RecordField; -import org.apache.nifi.serialization.record.RecordFieldType; -import org.apache.nifi.serialization.record.RecordSchema; -import org.apache.nifi.util.MockComponentLog; -import org.apache.nifi.util.MockFlowFile; -import org.apache.nifi.util.MockPropertyValue; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.mockito.Mockito; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -import static org.apache.nifi.processors.iceberg.PutIceberg.MAXIMUM_COMMIT_DURATION; -import static org.apache.nifi.processors.iceberg.PutIceberg.MAXIMUM_COMMIT_WAIT_TIME; -import static org.apache.nifi.processors.iceberg.PutIceberg.MINIMUM_COMMIT_WAIT_TIME; -import static org.apache.nifi.processors.iceberg.PutIceberg.NUMBER_OF_COMMIT_RETRIES; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.createTemporaryDirectory; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.condition.OS.WINDOWS; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class TestDataFileActions { - - private static final Namespace NAMESPACE = Namespace.of("default"); - private static final TableIdentifier TABLE_IDENTIFIER = TableIdentifier.of(NAMESPACE, "abort"); - - private static final Schema ABORT_SCHEMA = new Schema( - Types.NestedField.required(0, "id", Types.IntegerType.get()) - ); - - private PutIceberg icebergProcessor; - private ComponentLog logger; - - @BeforeEach - public void setUp() { - icebergProcessor = new PutIceberg(); - logger = new MockComponentLog("id", "TestDataFileActions"); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testAbortUncommittedFiles() throws IOException { - Table table = initCatalog(); - - List recordFields = Collections.singletonList(new RecordField("id", RecordFieldType.INT.getDataType())); - RecordSchema abortSchema = new SimpleRecordSchema(recordFields); - - List recordList = new ArrayList<>(); - recordList.add(new MapRecord(abortSchema, Collections.singletonMap("id", 1))); - recordList.add(new MapRecord(abortSchema, Collections.singletonMap("id", 2))); - recordList.add(new MapRecord(abortSchema, Collections.singletonMap("id", 3))); - recordList.add(new MapRecord(abortSchema, Collections.singletonMap("id", 4))); - recordList.add(new MapRecord(abortSchema, Collections.singletonMap("id", 5))); - - IcebergTaskWriterFactory taskWriterFactory = new IcebergTaskWriterFactory(table, new Random().nextLong(), FileFormat.PARQUET, null); - TaskWriter taskWriter = taskWriterFactory.create(); - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(table.schema(), abortSchema, FileFormat.PARQUET, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - - for (MapRecord record : recordList) { - taskWriter.write(recordConverter.convert(record)); - } - - DataFile[] dataFiles = taskWriter.dataFiles(); - - // DataFiles written by the taskWriter should exist - for (DataFile dataFile : dataFiles) { - Assertions.assertTrue(Files.exists(Paths.get(dataFile.path().toString()))); - } - - icebergProcessor.abort(taskWriter.dataFiles(), table); - - // DataFiles shouldn't exist after aborting them - for (DataFile dataFile : dataFiles) { - Assertions.assertFalse(Files.exists(Paths.get(dataFile.path().toString()))); - } - } - - @Test - public void testAppenderCommitRetryExceeded() { - ProcessContext context = Mockito.mock(ProcessContext.class); - when(context.getProperty(NUMBER_OF_COMMIT_RETRIES)).thenReturn(new MockPropertyValue("3", null)); - when(context.getProperty(MINIMUM_COMMIT_WAIT_TIME)).thenReturn(new MockPropertyValue("1 ms", null)); - when(context.getProperty(MAXIMUM_COMMIT_WAIT_TIME)).thenReturn(new MockPropertyValue("1 ms", null)); - when(context.getProperty(MAXIMUM_COMMIT_DURATION)).thenReturn(new MockPropertyValue("1 min", null)); - - FlowFile mockFlowFile = new MockFlowFile(1234567890L); - AppendFiles appender = Mockito.mock(AppendFiles.class); - doThrow(CommitFailedException.class).when(appender).commit(); - - Table table = Mockito.mock(Table.class); - when(table.newAppend()).thenReturn(appender); - - // assert the commit action eventually fails after exceeding the number of retries - assertThrows(CommitFailedException.class, () -> icebergProcessor.appendDataFiles(context, mockFlowFile, table, WriteResult.builder().build())); - - // verify the commit action was called the configured number of times - verify(appender, times(4)).commit(); - } - - @SuppressWarnings("unchecked") - @Test - public void testAppenderCommitSucceeded() { - ProcessContext context = Mockito.mock(ProcessContext.class); - when(context.getProperty(NUMBER_OF_COMMIT_RETRIES)).thenReturn(new MockPropertyValue("3", null)); - when(context.getProperty(MINIMUM_COMMIT_WAIT_TIME)).thenReturn(new MockPropertyValue("1 ms", null)); - when(context.getProperty(MAXIMUM_COMMIT_WAIT_TIME)).thenReturn(new MockPropertyValue("1 ms", null)); - when(context.getProperty(MAXIMUM_COMMIT_DURATION)).thenReturn(new MockPropertyValue("1 min", null)); - - FlowFile mockFlowFile = new MockFlowFile(1234567890L); - AppendFiles appender = Mockito.mock(AppendFiles.class); - // the commit action should throw exception 2 times before succeeding - doThrow(CommitFailedException.class, CommitFailedException.class).doNothing().when(appender).commit(); - - Table table = Mockito.mock(Table.class); - when(table.newAppend()).thenReturn(appender); - - // the method call shouldn't throw exception since the configured number of retries is higher than the number of failed commit actions - icebergProcessor.appendDataFiles(context, mockFlowFile, table, WriteResult.builder().build()); - - // verify the proper number of commit action was called - verify(appender, times(3)).commit(); - } - - @Test - public void testMaxCommitDurationExceeded() { - ProcessContext context = Mockito.mock(ProcessContext.class); - when(context.getProperty(NUMBER_OF_COMMIT_RETRIES)).thenReturn(new MockPropertyValue("5", null)); - when(context.getProperty(MINIMUM_COMMIT_WAIT_TIME)).thenReturn(new MockPropertyValue("2 ms", null)); - when(context.getProperty(MAXIMUM_COMMIT_WAIT_TIME)).thenReturn(new MockPropertyValue("2 ms", null)); - when(context.getProperty(MAXIMUM_COMMIT_DURATION)).thenReturn(new MockPropertyValue("1 ms", null)); - - FlowFile mockFlowFile = new MockFlowFile(1234567890L); - AppendFiles appender = Mockito.mock(AppendFiles.class); - doThrow(CommitFailedException.class).when(appender).commit(); - - Table table = Mockito.mock(Table.class); - when(table.newAppend()).thenReturn(appender); - - // assert the commit action eventually fails after exceeding duration of maximum retries - assertThrows(CommitFailedException.class, () -> icebergProcessor.appendDataFiles(context, mockFlowFile, table, WriteResult.builder().build())); - - // verify the commit action was called only 2 times instead of the configured 5 - verify(appender, times(2)).commit(); - } - - private Table initCatalog() { - final File warehousePath = createTemporaryDirectory(); - final HadoopCatalog catalog = new HadoopCatalog(new Configuration(), warehousePath.getAbsolutePath()); - - return catalog.createTable(TABLE_IDENTIFIER, ABORT_SCHEMA, PartitionSpec.unpartitioned()); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestIcebergRecordConverter.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestIcebergRecordConverter.java deleted file mode 100644 index 4db691b072..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestIcebergRecordConverter.java +++ /dev/null @@ -1,1124 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.Files; -import org.apache.iceberg.Schema; -import org.apache.iceberg.avro.Avro; -import org.apache.iceberg.avro.AvroIterable; -import org.apache.iceberg.data.GenericRecord; -import org.apache.iceberg.data.avro.DataReader; -import org.apache.iceberg.data.avro.DataWriter; -import org.apache.iceberg.data.orc.GenericOrcReader; -import org.apache.iceberg.data.orc.GenericOrcWriter; -import org.apache.iceberg.data.parquet.GenericParquetReaders; -import org.apache.iceberg.data.parquet.GenericParquetWriter; -import org.apache.iceberg.io.CloseableIterable; -import org.apache.iceberg.io.FileAppender; -import org.apache.iceberg.io.InputFile; -import org.apache.iceberg.io.OutputFile; -import org.apache.iceberg.orc.ORC; -import org.apache.iceberg.parquet.Parquet; -import org.apache.iceberg.relocated.com.google.common.collect.Lists; -import org.apache.iceberg.types.Types; -import org.apache.nifi.logging.ComponentLog; -import org.apache.nifi.processors.iceberg.converter.ArrayElementGetter; -import org.apache.nifi.processors.iceberg.converter.IcebergRecordConverter; -import org.apache.nifi.processors.iceberg.converter.RecordFieldGetter; -import org.apache.nifi.serialization.SimpleRecordSchema; -import org.apache.nifi.serialization.record.DataType; -import org.apache.nifi.serialization.record.MapRecord; -import org.apache.nifi.serialization.record.Record; -import org.apache.nifi.serialization.record.RecordField; -import org.apache.nifi.serialization.record.RecordFieldType; -import org.apache.nifi.serialization.record.RecordSchema; -import org.apache.nifi.serialization.record.type.ArrayDataType; -import org.apache.nifi.serialization.record.type.MapDataType; -import org.apache.nifi.serialization.record.type.RecordDataType; -import org.apache.nifi.util.MockComponentLog; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; - -import java.io.File; -import java.io.IOException; -import java.math.BigDecimal; -import java.nio.ByteBuffer; -import java.sql.Time; -import java.sql.Timestamp; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import static java.io.File.createTempFile; -import static org.apache.iceberg.FileFormat.PARQUET; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.condition.OS.WINDOWS; - -public class TestIcebergRecordConverter { - - private static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.of(2017, 4, 4, 14, 20, 33, 789000000); - - private OutputFile tempFile; - - private ComponentLog logger; - - @BeforeEach - public void setUp() throws Exception { - tempFile = Files.localOutput(createTempFile("test", null)); - logger = new MockComponentLog("id", "TestIcebergRecordConverter"); - } - - @AfterEach - public void tearDown() { - File file = new File(tempFile.location()); - file.deleteOnExit(); - } - - private static final Schema STRUCT_SCHEMA = new Schema( - Types.NestedField.required(0, "struct", Types.StructType.of( - Types.NestedField.required(1, "nested_struct", Types.StructType.of( - Types.NestedField.required(2, "string", Types.StringType.get()), - Types.NestedField.required(3, "integer", Types.IntegerType.get())) - ) - )) - ); - - private static final Schema LIST_SCHEMA = new Schema( - Types.NestedField.required(0, "list", Types.ListType.ofRequired( - 1, Types.ListType.ofRequired(2, Types.StringType.get()) - ) - ) - ); - - private static final Schema MAP_SCHEMA = new Schema( - Types.NestedField.required(0, "map", Types.MapType.ofRequired( - 1, 2, Types.StringType.get(), Types.MapType.ofRequired( - 3, 4, Types.StringType.get(), Types.LongType.get() - ) - )) - ); - - private static final Schema RECORD_IN_LIST_SCHEMA = new Schema( - Types.NestedField.required(0, "list", Types.ListType.ofRequired( - 1, Types.StructType.of( - Types.NestedField.required(2, "string", Types.StringType.get()), - Types.NestedField.required(3, "integer", Types.IntegerType.get()))) - ) - ); - - private static final Schema RECORD_IN_MAP_SCHEMA = new Schema( - Types.NestedField.required(0, "map", Types.MapType.ofRequired( - 1, 2, Types.StringType.get(), Types.StructType.of( - Types.NestedField.required(3, "string", Types.StringType.get()), - Types.NestedField.required(4, "integer", Types.IntegerType.get()))) - ) - ); - - private static final Schema PRIMITIVES_SCHEMA = new Schema( - Types.NestedField.optional(0, "string", Types.StringType.get()), - Types.NestedField.optional(1, "integer", Types.IntegerType.get()), - Types.NestedField.optional(2, "float", Types.FloatType.get()), - Types.NestedField.optional(3, "long", Types.LongType.get()), - Types.NestedField.optional(4, "double", Types.DoubleType.get()), - Types.NestedField.optional(5, "decimal", Types.DecimalType.of(10, 2)), - Types.NestedField.optional(6, "decimalLowerScore", Types.DecimalType.of(10, 2)), - Types.NestedField.optional(7, "boolean", Types.BooleanType.get()), - Types.NestedField.optional(8, "fixed", Types.FixedType.ofLength(5)), - Types.NestedField.optional(9, "binary", Types.BinaryType.get()), - Types.NestedField.optional(10, "date", Types.DateType.get()), - Types.NestedField.optional(11, "time", Types.TimeType.get()), - Types.NestedField.optional(12, "timestamp", Types.TimestampType.withZone()), - Types.NestedField.optional(13, "timestampTz", Types.TimestampType.withoutZone()), - Types.NestedField.optional(14, "uuid", Types.UUIDType.get()), - Types.NestedField.optional(15, "choice", Types.IntegerType.get()), - Types.NestedField.optional(16, "enum", Types.StringType.get()) - ); - - private static final Schema PRIMITIVES_SCHEMA_WITH_REQUIRED_FIELDS = new Schema( - Types.NestedField.optional(0, "string", Types.StringType.get()), - Types.NestedField.required(1, "integer", Types.IntegerType.get()), - Types.NestedField.required(2, "float", Types.FloatType.get()), - Types.NestedField.required(3, "long", Types.LongType.get()), - Types.NestedField.optional(4, "double", Types.DoubleType.get()), - Types.NestedField.optional(5, "decimal", Types.DecimalType.of(10, 2)), - Types.NestedField.optional(6, "boolean", Types.BooleanType.get()), - Types.NestedField.optional(7, "fixed", Types.FixedType.ofLength(5)), - Types.NestedField.optional(8, "binary", Types.BinaryType.get()), - Types.NestedField.optional(9, "date", Types.DateType.get()), - Types.NestedField.optional(10, "time", Types.TimeType.get()), - Types.NestedField.optional(11, "timestamp", Types.TimestampType.withZone()), - Types.NestedField.optional(12, "timestampTz", Types.TimestampType.withoutZone()), - Types.NestedField.optional(13, "uuid", Types.UUIDType.get()), - Types.NestedField.optional(14, "choice", Types.IntegerType.get()) - ); - - private static final Schema COMPATIBLE_PRIMITIVES_SCHEMA = new Schema( - Types.NestedField.optional(0, "string", Types.StringType.get()), - Types.NestedField.optional(1, "integer", Types.IntegerType.get()), - Types.NestedField.optional(2, "float", Types.FloatType.get()), - Types.NestedField.optional(3, "long", Types.LongType.get()), - Types.NestedField.optional(4, "double", Types.DoubleType.get()), - Types.NestedField.optional(5, "decimal", Types.DecimalType.of(10, 2)), - Types.NestedField.optional(7, "fixed", Types.FixedType.ofLength(5)), - Types.NestedField.optional(8, "binary", Types.BinaryType.get()), - Types.NestedField.optional(9, "date", Types.DateType.get()), - Types.NestedField.optional(10, "time", Types.TimeType.get()), - Types.NestedField.optional(11, "timestamp", Types.TimestampType.withZone()), - Types.NestedField.optional(12, "timestampTz", Types.TimestampType.withoutZone()), - Types.NestedField.optional(13, "uuid", Types.UUIDType.get()), - Types.NestedField.optional(14, "choice", Types.IntegerType.get()) - ); - - private static final Schema CASE_INSENSITIVE_SCHEMA = new Schema( - Types.NestedField.optional(0, "FIELD1", Types.StringType.get()), - Types.NestedField.optional(1, "Field2", Types.StringType.get()), - Types.NestedField.optional(2, "fielD3", Types.StringType.get()), - Types.NestedField.optional(3, "field4", Types.StringType.get()) - ); - - private static final Schema UNORDERED_SCHEMA = new Schema( - Types.NestedField.optional(0, "field1", Types.StringType.get()), - Types.NestedField.required(1, "field2", Types.StructType.of( - Types.NestedField.required(2, "field3", Types.StringType.get()), - Types.NestedField.required(3, "field4", Types.ListType.ofRequired(4, Types.StringType.get())) - )), - Types.NestedField.optional(5, "field5", Types.StringType.get()), - Types.NestedField.required(6, "field6", Types.MapType.ofRequired( - 7, 8, Types.StringType.get(), Types.StringType.get() - )) - ); - - private static RecordSchema getStructSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("struct", new RecordDataType(getNestedStructSchema()))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getNestedStructSchema() { - List nestedFields = new ArrayList<>(); - nestedFields.add(new RecordField("nested_struct", new RecordDataType(getNestedStructSchema2()))); - - return new SimpleRecordSchema(nestedFields); - } - - private static RecordSchema getNestedStructSchema2() { - List nestedFields2 = new ArrayList<>(); - nestedFields2.add(new RecordField("string", RecordFieldType.STRING.getDataType())); - nestedFields2.add(new RecordField("integer", RecordFieldType.INT.getDataType())); - - return new SimpleRecordSchema(nestedFields2); - } - - private static RecordSchema getListSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("list", new ArrayDataType( - new ArrayDataType(RecordFieldType.STRING.getDataType())))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getMapSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("map", new MapDataType( - new MapDataType(RecordFieldType.LONG.getDataType())))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getRecordInListSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("list", new ArrayDataType( - new RecordDataType(getNestedStructSchema2())))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getRecordInMapSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("map", new MapDataType( - new RecordDataType(getNestedStructSchema2())))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getPrimitivesSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("string", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("integer", RecordFieldType.INT.getDataType())); - fields.add(new RecordField("float", RecordFieldType.FLOAT.getDataType())); - fields.add(new RecordField("long", RecordFieldType.LONG.getDataType())); - fields.add(new RecordField("double", RecordFieldType.DOUBLE.getDataType())); - fields.add(new RecordField("decimal", RecordFieldType.DECIMAL.getDecimalDataType(10, 2))); - fields.add(new RecordField("decimalLowerScore", RecordFieldType.DECIMAL.getDecimalDataType(10, 2))); - fields.add(new RecordField("boolean", RecordFieldType.BOOLEAN.getDataType())); - fields.add(new RecordField("fixed", RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.BYTE.getDataType()))); - fields.add(new RecordField("binary", RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.BYTE.getDataType()))); - fields.add(new RecordField("date", RecordFieldType.DATE.getDataType())); - fields.add(new RecordField("time", RecordFieldType.TIME.getDataType())); - fields.add(new RecordField("timestamp", RecordFieldType.TIMESTAMP.getDataType())); - fields.add(new RecordField("timestampTz", RecordFieldType.TIMESTAMP.getDataType())); - fields.add(new RecordField("uuid", RecordFieldType.UUID.getDataType())); - fields.add(new RecordField("choice", RecordFieldType.CHOICE.getChoiceDataType(RecordFieldType.STRING.getDataType(), RecordFieldType.INT.getDataType()))); - fields.add(new RecordField("enum", RecordFieldType.ENUM.getEnumDataType(Arrays.asList("red", "blue", "yellow")))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getPrimitivesSchemaMissingFields() { - List fields = new ArrayList<>(); - fields.add(new RecordField("string", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("double", RecordFieldType.DOUBLE.getDataType())); - fields.add(new RecordField("decimal", RecordFieldType.DECIMAL.getDecimalDataType(10, 2))); - fields.add(new RecordField("boolean", RecordFieldType.BOOLEAN.getDataType())); - fields.add(new RecordField("fixed", RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.BYTE.getDataType()))); - fields.add(new RecordField("binary", RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.BYTE.getDataType()))); - fields.add(new RecordField("date", RecordFieldType.DATE.getDataType())); - fields.add(new RecordField("time", RecordFieldType.TIME.getDataType())); - fields.add(new RecordField("timestamp", RecordFieldType.TIMESTAMP.getDataType())); - fields.add(new RecordField("timestampTz", RecordFieldType.TIMESTAMP.getDataType())); - fields.add(new RecordField("uuid", RecordFieldType.UUID.getDataType())); - fields.add(new RecordField("choice", RecordFieldType.CHOICE.getChoiceDataType(RecordFieldType.STRING.getDataType(), RecordFieldType.INT.getDataType()))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getPrimitivesAsCompatiblesSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("string", RecordFieldType.INT.getDataType())); - fields.add(new RecordField("integer", RecordFieldType.SHORT.getDataType())); - fields.add(new RecordField("float", RecordFieldType.DOUBLE.getDataType())); - fields.add(new RecordField("long", RecordFieldType.INT.getDataType())); - fields.add(new RecordField("double", RecordFieldType.FLOAT.getDataType())); - fields.add(new RecordField("decimal", RecordFieldType.DOUBLE.getDataType())); - fields.add(new RecordField("fixed", RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.BYTE.getDataType()))); - fields.add(new RecordField("binary", RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.BYTE.getDataType()))); - fields.add(new RecordField("date", RecordFieldType.STRING.getDataType("yyyy-MM-dd"))); - fields.add(new RecordField("time", RecordFieldType.STRING.getDataType("HH:mm:ss.SSS"))); - fields.add(new RecordField("timestamp", RecordFieldType.STRING.getDataType("yyyy-MM-dd HH:mm:ss.SSSZ"))); - fields.add(new RecordField("timestampTz", RecordFieldType.STRING.getDataType("yyyy-MM-dd HH:mm:ss.SSSZ"))); - fields.add(new RecordField("uuid", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("choice", RecordFieldType.CHOICE.getChoiceDataType(RecordFieldType.STRING.getDataType(), RecordFieldType.INT.getDataType()))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getCaseInsensitiveSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("field1", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("FIELD2", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("Field3", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("fielD4", RecordFieldType.STRING.getDataType())); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getNestedUnorderedSchema() { - List nestedFields = new ArrayList<>(); - nestedFields.add(new RecordField("FIELD4", new ArrayDataType(RecordFieldType.STRING.getDataType()))); - nestedFields.add(new RecordField("FIELD3", RecordFieldType.STRING.getDataType())); - - return new SimpleRecordSchema(nestedFields); - } - - private static RecordSchema getUnorderedSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("FIELD6", new MapDataType(RecordFieldType.STRING.getDataType()))); - fields.add(new RecordField("FIELD5", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("FIELD1", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("FIELD2", new RecordDataType(getNestedUnorderedSchema()))); - - return new SimpleRecordSchema(fields); - } - - private static RecordSchema getChoiceSchema() { - List fields = new ArrayList<>(); - fields.add(new RecordField("string", RecordFieldType.INT.getDataType())); - fields.add(new RecordField("integer", RecordFieldType.STRING.getDataType())); - fields.add(new RecordField("float", RecordFieldType.LONG.getDataType())); - - return new SimpleRecordSchema(fields); - } - - private static Record setupStructTestRecord() { - Map nestedValues2 = new HashMap<>(); - nestedValues2.put("string", "Test String"); - nestedValues2.put("integer", 10); - MapRecord nestedRecord2 = new MapRecord(getNestedStructSchema2(), nestedValues2); - - Map nestedValues = new HashMap<>(); - nestedValues.put("nested_struct", nestedRecord2); - MapRecord nestedRecord = new MapRecord(getNestedStructSchema(), nestedValues); - - Map values = new HashMap<>(); - values.put("struct", nestedRecord); - return new MapRecord(getStructSchema(), values); - } - - private static Record setupListTestRecord() { - List nestedList1 = new ArrayList<>(); - nestedList1.add("Test String1"); - nestedList1.add("Test String2"); - - List nestedList2 = new ArrayList<>(); - nestedList2.add("Test String3"); - nestedList2.add("Test String4"); - - List> list = new ArrayList<>(); - list.add(nestedList1); - list.add(nestedList2); - - Map values = new HashMap<>(); - values.put("list", list); - - return new MapRecord(getListSchema(), values); - } - - private static Record setupMapTestRecord() { - Map nestedMap = new HashMap<>(); - nestedMap.put("nested_key", 42L); - - Map> map = new HashMap<>(); - map.put("key", nestedMap); - - Map values = new HashMap<>(); - values.put("map", map); - - return new MapRecord(getMapSchema(), values); - } - - private static Record setupRecordInListTestRecord() { - Map struct1 = new HashMap<>(); - struct1.put("string", "Test String 1"); - struct1.put("integer", 10); - - Map struct2 = new HashMap<>(); - struct2.put("string", "Test String 2"); - struct2.put("integer", 20); - - return new MapRecord(getRecordInListSchema(), Collections.singletonMap("list", Arrays.asList(struct1, struct2))); - } - - private static Record setupRecordInMapTestRecord() { - Map struct1 = new HashMap<>(); - struct1.put("string", "Test String 1"); - struct1.put("integer", 10); - - Map struct2 = new HashMap<>(); - struct2.put("string", "Test String 2"); - struct2.put("integer", 20); - - Map> map = new HashMap<>(); - map.put("key1", struct1); - map.put("key2", struct2); - - return new MapRecord(getMapSchema(), Collections.singletonMap("map", map)); - } - - private static Record setupPrimitivesTestRecord() { - LocalDate localDate = LocalDate.of(2017, 4, 4); - LocalTime localTime = LocalTime.of(14, 20, 33); - OffsetDateTime offsetDateTime = OffsetDateTime.of(LOCAL_DATE_TIME, ZoneOffset.ofHours(-5)); - - Map values = new HashMap<>(); - values.put("string", "Test String"); - values.put("integer", 8); - values.put("float", 1.23456F); - values.put("long", 42L); - values.put("double", 3.14159D); - values.put("decimal", new BigDecimal("12345678.12")); - values.put("decimalLowerScore", 12345678.1); - values.put("boolean", true); - values.put("fixed", "hello".getBytes()); - values.put("binary", "hello".getBytes()); - values.put("date", localDate); - values.put("time", Time.valueOf(localTime)); - values.put("timestamp", Timestamp.from(offsetDateTime.toInstant())); - values.put("timestampTz", Timestamp.valueOf(LOCAL_DATE_TIME)); - values.put("uuid", UUID.fromString("0000-00-00-00-000000")); - values.put("choice", "10"); - values.put("enum", "blue"); - - return new MapRecord(getPrimitivesSchema(), values); - } - - private static Record setupPrimitivesTestRecordMissingFields() { - LocalDate localDate = LocalDate.of(2017, 4, 4); - LocalTime localTime = LocalTime.of(14, 20, 33); - OffsetDateTime offsetDateTime = OffsetDateTime.of(LOCAL_DATE_TIME, ZoneOffset.ofHours(-5)); - - Map values = new HashMap<>(); - values.put("string", "Test String"); - values.put("double", 3.14159D); - values.put("decimal", new BigDecimal("12345678.12")); - values.put("boolean", true); - values.put("fixed", "hello".getBytes()); - values.put("binary", "hello".getBytes()); - values.put("date", localDate); - values.put("time", Time.valueOf(localTime)); - values.put("timestamp", Timestamp.from(offsetDateTime.toInstant())); - values.put("timestampTz", Timestamp.valueOf(LOCAL_DATE_TIME)); - values.put("uuid", UUID.fromString("0000-00-00-00-000000")); - values.put("choice", "10"); - - return new MapRecord(getPrimitivesSchemaMissingFields(), values); - } - - private static Record setupCompatiblePrimitivesTestRecord() { - - Map values = new HashMap<>(); - values.put("string", 123); - values.put("integer", 8); - values.put("float", 1.23456); - values.put("long", 42L); - values.put("double", 3.14159); - values.put("decimal", 12345678.12); - values.put("fixed", "hello".getBytes()); - values.put("binary", "hello".getBytes()); - values.put("date", "2017-04-04"); - values.put("time", "14:20:33.000"); - values.put("timestamp", Timestamp.valueOf(LOCAL_DATE_TIME)); - values.put("timestampTz", Timestamp.valueOf(LOCAL_DATE_TIME)); - values.put("uuid", "0000-00-00-00-000000"); - values.put("choice", "10"); - - return new MapRecord(getPrimitivesAsCompatiblesSchema(), values); - } - - private static Record setupCaseInsensitiveTestRecord() { - Map values = new HashMap<>(); - values.put("field1", "Text1"); - values.put("FIELD2", "Text2"); - values.put("Field3", "Text3"); - values.put("fielD4", "Text4"); - - return new MapRecord(getCaseInsensitiveSchema(), values); - } - - private static Record setupUnorderedTestRecord() { - List listValues = new ArrayList<>(); - listValues.add("list value2"); - listValues.add("list value1"); - - Map mapValues = new HashMap<>(); - mapValues.put("key2", "map value2"); - mapValues.put("key1", "map value1"); - - Map nestedValues = new HashMap<>(); - nestedValues.put("FIELD4", listValues); - nestedValues.put("FIELD3", "value3"); - MapRecord nestedRecord = new MapRecord(getNestedUnorderedSchema(), nestedValues); - - Map values = new HashMap<>(); - values.put("FIELD6", mapValues); - values.put("FIELD5", "value5"); - values.put("FIELD1", "value1"); - values.put("FIELD2", nestedRecord); - return new MapRecord(getStructSchema(), values); - } - - private static Record setupChoiceTestRecord() { - Map values = new HashMap<>(); - values.put("choice1", "20"); - values.put("choice2", "30a"); - values.put("choice3", String.valueOf(Long.MAX_VALUE)); - - return new MapRecord(getChoiceSchema(), values); - } - - @DisabledOnOs(WINDOWS) - @ParameterizedTest - @EnumSource(value = FileFormat.class, names = {"AVRO", "ORC", "PARQUET"}) - public void testPrimitives(FileFormat format) throws IOException { - RecordSchema nifiSchema = getPrimitivesSchema(); - Record record = setupPrimitivesTestRecord(); - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(PRIMITIVES_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, PRIMITIVES_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, PRIMITIVES_SCHEMA, tempFile.toInputFile()); - - assertEquals(results.size(), 1); - GenericRecord resultRecord = results.getFirst(); - - OffsetDateTime offsetDateTime = OffsetDateTime.of(LOCAL_DATE_TIME, ZoneOffset.ofHours(-5)); - - assertEquals("Test String", resultRecord.get(0, String.class)); - assertEquals(Integer.valueOf(8), resultRecord.get(1, Integer.class)); - assertEquals(Float.valueOf(1.23456F), resultRecord.get(2, Float.class)); - assertEquals(Long.valueOf(42L), resultRecord.get(3, Long.class)); - assertEquals(Double.valueOf(3.14159D), resultRecord.get(4, Double.class)); - assertEquals(new BigDecimal("12345678.12"), resultRecord.get(5, BigDecimal.class)); - assertEquals(new BigDecimal("12345678.10"), resultRecord.get(6, BigDecimal.class)); - assertEquals(Boolean.TRUE, resultRecord.get(7, Boolean.class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(8, byte[].class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(9, ByteBuffer.class).array()); - assertEquals(LocalDate.of(2017, 4, 4), resultRecord.get(10, LocalDate.class)); - assertEquals(LocalTime.of(14, 20, 33), resultRecord.get(11, LocalTime.class)); - assertEquals(offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC), resultRecord.get(12, OffsetDateTime.class)); - assertEquals(LOCAL_DATE_TIME, resultRecord.get(13, LocalDateTime.class)); - assertEquals(Integer.valueOf(10), resultRecord.get(15, Integer.class)); - assertEquals("blue", resultRecord.get(16, String.class)); - - if (format.equals(PARQUET)) { - assertArrayEquals(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, resultRecord.get(14, byte[].class)); - } else { - assertEquals(UUID.fromString("0000-00-00-00-000000"), resultRecord.get(14, UUID.class)); - } - } - - @DisabledOnOs(WINDOWS) - @ParameterizedTest - @EnumSource(value = FileFormat.class, names = {"AVRO", "ORC", "PARQUET"}) - public void testPrimitivesIgnoreMissingFields(FileFormat format) throws IOException { - RecordSchema nifiSchema = getPrimitivesSchemaMissingFields(); - Record record = setupPrimitivesTestRecordMissingFields(); - MockComponentLog mockComponentLogger = new MockComponentLog("id", "TestIcebergRecordConverter"); - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(PRIMITIVES_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, mockComponentLogger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, PRIMITIVES_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, PRIMITIVES_SCHEMA, tempFile.toInputFile()); - - assertEquals(results.size(), 1); - GenericRecord resultRecord = results.getFirst(); - - OffsetDateTime offsetDateTime = OffsetDateTime.of(LOCAL_DATE_TIME, ZoneOffset.ofHours(-5)); - - assertEquals("Test String", resultRecord.get(0, String.class)); - assertNull(resultRecord.get(1, Integer.class)); - assertNull(resultRecord.get(2, Float.class)); - assertNull(resultRecord.get(3, Long.class)); - assertEquals(Double.valueOf(3.14159D), resultRecord.get(4, Double.class)); - assertEquals(new BigDecimal("12345678.12"), resultRecord.get(5, BigDecimal.class)); - assertEquals(Boolean.TRUE, resultRecord.get(7, Boolean.class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(8, byte[].class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(9, ByteBuffer.class).array()); - assertEquals(LocalDate.of(2017, 4, 4), resultRecord.get(10, LocalDate.class)); - assertEquals(LocalTime.of(14, 20, 33), resultRecord.get(11, LocalTime.class)); - assertEquals(offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC), resultRecord.get(12, OffsetDateTime.class)); - assertEquals(LOCAL_DATE_TIME, resultRecord.get(13, LocalDateTime.class)); - assertEquals(Integer.valueOf(10), resultRecord.get(15, Integer.class)); - - if (format.equals(FileFormat.PARQUET)) { - // Parquet uses a conversion to the byte values of numeric characters such as "0" -> byte value 0 - UUID uuid = UUID.fromString("0000-00-00-00-000000"); - ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); - byteBuffer.putLong(uuid.getMostSignificantBits()); - byteBuffer.putLong(uuid.getLeastSignificantBits()); - assertArrayEquals(byteBuffer.array(), resultRecord.get(14, byte[].class)); - } else { - assertEquals(UUID.fromString("0000-00-00-00-000000"), resultRecord.get(14, UUID.class)); - } - - // Test null values - for (String fieldName : record.getRawFieldNames()) { - record.setValue(fieldName, null); - } - - genericRecord = recordConverter.convert(record); - - writeTo(format, PRIMITIVES_SCHEMA, genericRecord, tempFile); - - results = readFrom(format, PRIMITIVES_SCHEMA, tempFile.toInputFile()); - - assertEquals(results.size(), 1); - resultRecord = results.getFirst(); - assertNull(resultRecord.get(0, String.class)); - assertNull(resultRecord.get(1, Integer.class)); - assertNull(resultRecord.get(2, Float.class)); - assertNull(resultRecord.get(3, Long.class)); - assertNull(resultRecord.get(4, Double.class)); - assertNull(resultRecord.get(5, BigDecimal.class)); - assertNull(resultRecord.get(6, Boolean.class)); - assertNull(resultRecord.get(7)); - assertNull(resultRecord.get(8)); - assertNull(resultRecord.get(9, LocalDate.class)); - assertNull(resultRecord.get(10, LocalTime.class)); - assertNull(resultRecord.get(11, OffsetDateTime.class)); - assertNull(resultRecord.get(14, Integer.class)); - } - - @DisabledOnOs(WINDOWS) - @ParameterizedTest - @EnumSource(value = FileFormat.class, names = {"AVRO", "ORC", "PARQUET"}) - public void testPrimitivesMissingRequiredFields(FileFormat format) { - RecordSchema nifiSchema = getPrimitivesSchemaMissingFields(); - MockComponentLog mockComponentLogger = new MockComponentLog("id", "TestIcebergRecordConverter"); - - assertThrows(IllegalArgumentException.class, - () -> new IcebergRecordConverter(PRIMITIVES_SCHEMA_WITH_REQUIRED_FIELDS, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, mockComponentLogger)); - } - - @DisabledOnOs(WINDOWS) - @ParameterizedTest - @EnumSource(value = FileFormat.class, names = {"AVRO", "ORC", "PARQUET"}) - public void testPrimitivesWarnMissingFields(FileFormat format) throws IOException { - RecordSchema nifiSchema = getPrimitivesSchemaMissingFields(); - Record record = setupPrimitivesTestRecordMissingFields(); - MockComponentLog mockComponentLogger = new MockComponentLog("id", "TestIcebergRecordConverter"); - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(PRIMITIVES_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.WARNING_UNMATCHED_COLUMN, mockComponentLogger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, PRIMITIVES_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, PRIMITIVES_SCHEMA, tempFile.toInputFile()); - - assertEquals(results.size(), 1); - GenericRecord resultRecord = results.getFirst(); - - OffsetDateTime offsetDateTime = OffsetDateTime.of(LOCAL_DATE_TIME, ZoneOffset.ofHours(-5)); - - assertEquals("Test String", resultRecord.get(0, String.class)); - assertNull(resultRecord.get(1, Integer.class)); - assertNull(resultRecord.get(2, Float.class)); - assertNull(resultRecord.get(3, Long.class)); - assertEquals(Double.valueOf(3.14159D), resultRecord.get(4, Double.class)); - assertEquals(new BigDecimal("12345678.12"), resultRecord.get(5, BigDecimal.class)); - assertEquals(Boolean.TRUE, resultRecord.get(7, Boolean.class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(8, byte[].class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(9, ByteBuffer.class).array()); - assertEquals(LocalDate.of(2017, 4, 4), resultRecord.get(10, LocalDate.class)); - assertEquals(LocalTime.of(14, 20, 33), resultRecord.get(11, LocalTime.class)); - assertEquals(offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC), resultRecord.get(12, OffsetDateTime.class)); - assertEquals(LOCAL_DATE_TIME, resultRecord.get(13, LocalDateTime.class)); - assertEquals(Integer.valueOf(10), resultRecord.get(15, Integer.class)); - - if (format.equals(FileFormat.PARQUET)) { - // Parquet uses a conversion to the byte values of numeric characters such as "0" -> byte value 0 - UUID uuid = UUID.fromString("0000-00-00-00-000000"); - ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); - byteBuffer.putLong(uuid.getMostSignificantBits()); - byteBuffer.putLong(uuid.getLeastSignificantBits()); - assertArrayEquals(byteBuffer.array(), resultRecord.get(14, byte[].class)); - } else { - assertEquals(UUID.fromString("0000-00-00-00-000000"), resultRecord.get(14, UUID.class)); - } - } - - @DisabledOnOs(WINDOWS) - @ParameterizedTest - @EnumSource(value = FileFormat.class, names = {"AVRO", "ORC", "PARQUET"}) - public void testPrimitivesFailMissingFields(FileFormat format) { - RecordSchema nifiSchema = getPrimitivesSchemaMissingFields(); - MockComponentLog mockComponentLogger = new MockComponentLog("id", "TestIcebergRecordConverter"); - - assertThrows(IllegalArgumentException.class, - () -> new IcebergRecordConverter(PRIMITIVES_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.FAIL_UNMATCHED_COLUMN, mockComponentLogger)); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testCompatiblePrimitives() throws IOException { - RecordSchema nifiSchema = getPrimitivesAsCompatiblesSchema(); - Record record = setupCompatiblePrimitivesTestRecord(); - final FileFormat format = PARQUET; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(COMPATIBLE_PRIMITIVES_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.FAIL_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, COMPATIBLE_PRIMITIVES_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, COMPATIBLE_PRIMITIVES_SCHEMA, tempFile.toInputFile()); - - assertEquals(results.size(), 1); - GenericRecord resultRecord = results.getFirst(); - - final ZonedDateTime zonedDateTime = ZonedDateTime.of(LOCAL_DATE_TIME, ZoneId.systemDefault()); - OffsetDateTime offsetDateTime = zonedDateTime.toOffsetDateTime(); - - assertEquals("123", resultRecord.get(0, String.class)); - assertEquals(Integer.valueOf(8), resultRecord.get(1, Integer.class)); - assertEquals(Float.valueOf(1.23456F), resultRecord.get(2, Float.class)); - assertEquals(Long.valueOf(42L), resultRecord.get(3, Long.class)); - assertEquals(Double.valueOf(3.141590118408203), resultRecord.get(4, Double.class)); - assertEquals(new BigDecimal("12345678.12"), resultRecord.get(5, BigDecimal.class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(6, byte[].class)); - assertArrayEquals(new byte[]{104, 101, 108, 108, 111}, resultRecord.get(7, ByteBuffer.class).array()); - assertEquals(LocalDate.of(2017, 4, 4), resultRecord.get(8, LocalDate.class)); - assertEquals(LocalTime.of(14, 20, 33), resultRecord.get(9, LocalTime.class)); - assertEquals(offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC), resultRecord.get(10, OffsetDateTime.class)); - assertEquals(LOCAL_DATE_TIME, resultRecord.get(11, LocalDateTime.class)); - assertEquals(Integer.valueOf(10), resultRecord.get(13, Integer.class)); - - assertArrayEquals(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, resultRecord.get(12, byte[].class)); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testStruct() throws IOException { - RecordSchema nifiSchema = getStructSchema(); - Record record = setupStructTestRecord(); - final FileFormat format = FileFormat.ORC; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(STRUCT_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, STRUCT_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, STRUCT_SCHEMA, tempFile.toInputFile()); - - assertEquals(1, results.size()); - GenericRecord resultRecord = results.getFirst(); - - assertEquals(1, resultRecord.size()); - assertInstanceOf(GenericRecord.class, resultRecord.get(0)); - GenericRecord nestedRecord = (GenericRecord) resultRecord.get(0); - - assertEquals(1, nestedRecord.size()); - assertInstanceOf(GenericRecord.class, nestedRecord.get(0)); - GenericRecord baseRecord = (GenericRecord) nestedRecord.get(0); - - assertEquals("Test String", baseRecord.get(0, String.class)); - assertEquals(Integer.valueOf(10), baseRecord.get(1, Integer.class)); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testList() throws IOException { - RecordSchema nifiSchema = getListSchema(); - Record record = setupListTestRecord(); - final FileFormat format = FileFormat.AVRO; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(LIST_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, LIST_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, LIST_SCHEMA, tempFile.toInputFile()); - - assertEquals(1, results.size()); - GenericRecord resultRecord = results.getFirst(); - - assertEquals(1, resultRecord.size()); - assertInstanceOf(List.class, resultRecord.get(0)); - List nestedList = resultRecord.get(0, List.class); - - assertEquals(2, nestedList.size()); - assertInstanceOf(List.class, nestedList.get(0)); - assertInstanceOf(List.class, nestedList.get(1)); - - assertTrue(((List) nestedList.get(0)).containsAll(List.of("Test String1", "Test String2"))); - assertTrue(((List) nestedList.get(1)).containsAll(List.of("Test String3", "Test String4"))); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testMap() throws IOException { - RecordSchema nifiSchema = getMapSchema(); - Record record = setupMapTestRecord(); - final FileFormat format = PARQUET; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(MAP_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, MAP_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, MAP_SCHEMA, tempFile.toInputFile()); - - assertEquals(1, results.size()); - GenericRecord resultRecord = results.getFirst(); - - assertEquals(1, resultRecord.size()); - assertInstanceOf(Map.class, resultRecord.get(0)); - Map nestedMap = resultRecord.get(0, Map.class); - - assertEquals(1, nestedMap.size()); - assertInstanceOf(Map.class, nestedMap.get("key")); - Map baseMap = (Map) nestedMap.get("key"); - - assertEquals(42L, baseMap.get("nested_key")); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testRecordInList() throws IOException { - RecordSchema nifiSchema = getRecordInListSchema(); - Record record = setupRecordInListTestRecord(); - final FileFormat format = FileFormat.AVRO; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(RECORD_IN_LIST_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, RECORD_IN_LIST_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, RECORD_IN_LIST_SCHEMA, tempFile.toInputFile()); - - assertEquals(1, results.size()); - assertInstanceOf(GenericRecord.class, results.get(0)); - GenericRecord resultRecord = results.get(0); - - assertEquals(1, resultRecord.size()); - assertInstanceOf(List.class, resultRecord.get(0)); - List fieldList = resultRecord.get(0, List.class); - - assertEquals(2, fieldList.size()); - assertInstanceOf(GenericRecord.class, fieldList.get(0)); - assertInstanceOf(GenericRecord.class, fieldList.get(1)); - - GenericRecord record1 = (GenericRecord) fieldList.get(0); - GenericRecord record2 = (GenericRecord) fieldList.get(1); - - assertEquals("Test String 1", record1.get(0, String.class)); - assertEquals(Integer.valueOf(10), record1.get(1, Integer.class)); - - assertEquals("Test String 2", record2.get(0, String.class)); - assertEquals(Integer.valueOf(20), record2.get(1, Integer.class)); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testRecordInMap() throws IOException { - RecordSchema nifiSchema = getRecordInMapSchema(); - Record record = setupRecordInMapTestRecord(); - final FileFormat format = FileFormat.ORC; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(RECORD_IN_MAP_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, RECORD_IN_MAP_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, RECORD_IN_MAP_SCHEMA, tempFile.toInputFile()); - - assertEquals(1, results.size()); - assertInstanceOf(GenericRecord.class, results.get(0)); - GenericRecord resultRecord = results.get(0); - - assertEquals(1, resultRecord.size()); - assertInstanceOf(Map.class, resultRecord.get(0)); - Map recordMap = resultRecord.get(0, Map.class); - - assertEquals(2, recordMap.size()); - assertInstanceOf(GenericRecord.class, recordMap.get("key1")); - assertInstanceOf(GenericRecord.class, recordMap.get("key2")); - - GenericRecord record1 = (GenericRecord) recordMap.get("key1"); - GenericRecord record2 = (GenericRecord) recordMap.get("key2"); - - assertEquals("Test String 1", record1.get(0, String.class)); - assertEquals(Integer.valueOf(10), record1.get(1, Integer.class)); - - assertEquals("Test String 2", record2.get(0, String.class)); - assertEquals(Integer.valueOf(20), record2.get(1, Integer.class)); - } - - @DisabledOnOs(WINDOWS) - @ParameterizedTest - @EnumSource(value = FileFormat.class, names = {"AVRO", "ORC", "PARQUET"}) - public void testSchemaMismatch(FileFormat format) { - RecordSchema nifiSchema = getPrimitivesSchemaMissingFields(); - - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, - () -> new IcebergRecordConverter(PRIMITIVES_SCHEMA_WITH_REQUIRED_FIELDS, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger)); - assertTrue(e.getMessage().contains("Iceberg requires a non-null value for required fields"), e.getMessage()); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testCaseInsensitiveFieldMapping() throws IOException { - RecordSchema nifiSchema = getCaseInsensitiveSchema(); - Record record = setupCaseInsensitiveTestRecord(); - final FileFormat format = FileFormat.AVRO; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(CASE_INSENSITIVE_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, CASE_INSENSITIVE_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, CASE_INSENSITIVE_SCHEMA, tempFile.toInputFile()); - - assertEquals(1, results.size()); - GenericRecord resultRecord = results.getFirst(); - - assertEquals("Text1", resultRecord.get(0, String.class)); - assertEquals("Text2", resultRecord.get(1, String.class)); - assertEquals("Text3", resultRecord.get(2, String.class)); - assertEquals("Text4", resultRecord.get(3, String.class)); - } - - @DisabledOnOs(WINDOWS) - @Test - public void testUnorderedFieldMapping() throws IOException { - RecordSchema nifiSchema = getUnorderedSchema(); - Record record = setupUnorderedTestRecord(); - final FileFormat format = PARQUET; - - IcebergRecordConverter recordConverter = new IcebergRecordConverter(UNORDERED_SCHEMA, nifiSchema, format, UnmatchedColumnBehavior.IGNORE_UNMATCHED_COLUMN, logger); - GenericRecord genericRecord = recordConverter.convert(record); - - writeTo(format, UNORDERED_SCHEMA, genericRecord, tempFile); - - List results = readFrom(format, UNORDERED_SCHEMA, tempFile.toInputFile()); - - assertEquals(1, results.size()); - GenericRecord resultRecord = results.getFirst(); - - assertEquals("value1", resultRecord.get(0, String.class)); - - assertInstanceOf(GenericRecord.class, resultRecord.get(1)); - GenericRecord nestedRecord = (GenericRecord) resultRecord.get(1); - - assertEquals("value3", nestedRecord.get(0, String.class)); - - assertInstanceOf(List.class, nestedRecord.get(1)); - List nestedList = nestedRecord.get(1, List.class); - assertTrue(nestedList.containsAll(List.of("list value1", "list value2"))); - - assertEquals("value5", resultRecord.get(2, String.class)); - - assertInstanceOf(Map.class, resultRecord.get(3)); - Map map = resultRecord.get(3, Map.class); - assertEquals("map value1", map.get("key1")); - assertEquals("map value2", map.get("key2")); - } - - @Test - public void testChoiceDataTypeInRecord() { - Record record = setupChoiceTestRecord(); - DataType dataType = RecordFieldType.CHOICE.getChoiceDataType( - RecordFieldType.STRING.getDataType(), RecordFieldType.INT.getDataType(), RecordFieldType.LONG.getDataType()); - - RecordFieldGetter.FieldGetter fieldGetter1 = RecordFieldGetter.createFieldGetter(dataType, "choice1", true); - RecordFieldGetter.FieldGetter fieldGetter2 = RecordFieldGetter.createFieldGetter(dataType, "choice2", true); - RecordFieldGetter.FieldGetter fieldGetter3 = RecordFieldGetter.createFieldGetter(dataType, "choice3", true); - - assertInstanceOf(Integer.class, fieldGetter1.getFieldOrNull(record)); - assertInstanceOf(String.class, fieldGetter2.getFieldOrNull(record)); - assertInstanceOf(Long.class, fieldGetter3.getFieldOrNull(record)); - } - - @Test - public void testChoiceDataTypeInArray() { - DataType dataType = RecordFieldType.CHOICE.getChoiceDataType( - RecordFieldType.STRING.getDataType(), RecordFieldType.INT.getDataType(), RecordFieldType.LONG.getDataType()); - ArrayElementGetter.ElementGetter elementGetter = ArrayElementGetter.createElementGetter(dataType); - - String[] testArray = {"20", "30a", String.valueOf(Long.MAX_VALUE)}; - - assertInstanceOf(Integer.class, elementGetter.getElementOrNull(testArray[0])); - assertInstanceOf(String.class, elementGetter.getElementOrNull(testArray[1])); - assertInstanceOf(Long.class, elementGetter.getElementOrNull(testArray[2])); - } - - private void writeTo(FileFormat format, Schema schema, GenericRecord record, OutputFile outputFile) throws IOException { - switch (format) { - case AVRO: - writeToAvro(schema, record, outputFile); - break; - case ORC: - writeToOrc(schema, record, outputFile); - break; - case PARQUET: - writeToParquet(schema, record, outputFile); - break; - } - } - - private ArrayList readFrom(FileFormat format, Schema schema, InputFile inputFile) throws IOException { - return switch (format) { - case AVRO -> readFromAvro(schema, inputFile); - case ORC -> readFromOrc(schema, inputFile); - case PARQUET -> readFromParquet(schema, inputFile); - default -> throw new IOException("Unknown file format: " + format); - }; - } - - private void writeToAvro(Schema schema, GenericRecord record, OutputFile outputFile) throws IOException { - try (FileAppender appender = Avro.write(outputFile) - .schema(schema) - .createWriterFunc(DataWriter::create) - .overwrite() - .build()) { - appender.add(record); - } - } - - private ArrayList readFromAvro(Schema schema, InputFile inputFile) throws IOException { - try (AvroIterable reader = Avro.read(inputFile) - .project(schema) - .createReaderFunc(DataReader::create) - .build()) { - return Lists.newArrayList(reader); - } - } - - private void writeToOrc(Schema schema, GenericRecord record, OutputFile outputFile) throws IOException { - try (FileAppender appender = ORC.write(outputFile) - .schema(schema) - .createWriterFunc(GenericOrcWriter::buildWriter) - .overwrite() - .build()) { - appender.add(record); - } - } - - private ArrayList readFromOrc(Schema schema, InputFile inputFile) throws IOException { - try (CloseableIterable reader = ORC.read(inputFile) - .project(schema) - .createReaderFunc(fileSchema -> GenericOrcReader.buildReader(schema, fileSchema)) - .build()) { - return Lists.newArrayList(reader); - } - } - - private void writeToParquet(Schema schema, GenericRecord record, OutputFile outputFile) throws IOException { - try (FileAppender appender = Parquet.write(outputFile) - .schema(schema) - .createWriterFunc(GenericParquetWriter::buildWriter) - .overwrite() - .build()) { - appender.add(record); - } - } - - private ArrayList readFromParquet(Schema schema, InputFile inputFile) throws IOException { - try (CloseableIterable reader = Parquet.read(inputFile) - .project(schema) - .createReaderFunc(fileSchema -> GenericParquetReaders.buildReader(schema, fileSchema)) - .build()) { - return Lists.newArrayList(reader); - } - } -} \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergCustomValidation.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergCustomValidation.java deleted file mode 100644 index f1ab1d3983..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergCustomValidation.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.nifi.kerberos.KerberosUserService; -import org.apache.nifi.reporting.InitializationException; -import org.apache.nifi.serialization.record.MockRecordParser; -import org.apache.nifi.services.iceberg.HiveCatalogService; -import org.apache.nifi.util.TestRunner; -import org.apache.nifi.util.TestRunners; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.apache.nifi.services.iceberg.AbstractCatalogService.HADOOP_CONFIGURATION_RESOURCES; -import static org.apache.nifi.services.iceberg.HiveCatalogService.METASTORE_URI; -import static org.apache.nifi.services.iceberg.HiveCatalogService.WAREHOUSE_LOCATION; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class TestPutIcebergCustomValidation { - - private static final String RECORD_READER_NAME = "record-reader"; - private static final String KERBEROS_USER_SERVICE_NAME = "kerberos-user-service"; - private static final String CATALOG_SERVICE_NAME = "catalog-service"; - - private static final String CATALOG_NAMESPACE = "catalogNamespace"; - private static final String TABLE_NAME = "tableName"; - - private TestRunner runner; - - @BeforeEach - public void setUp() { - PutIceberg processor = new PutIceberg(); - runner = TestRunners.newTestRunner(processor); - } - - private void initRecordReader() throws InitializationException { - MockRecordParser readerFactory = new MockRecordParser(); - - runner.addControllerService(RECORD_READER_NAME, readerFactory); - runner.enableControllerService(readerFactory); - - runner.setProperty(PutIceberg.RECORD_READER, RECORD_READER_NAME); - } - - private void initCatalogService(String configFilePaths) throws InitializationException { - final HiveCatalogService catalogService = new HiveCatalogService(); - runner.addControllerService(CATALOG_SERVICE_NAME, catalogService); - runner.setProperty(catalogService, METASTORE_URI, "test-metastore"); - runner.setProperty(catalogService, WAREHOUSE_LOCATION, "test-warehouse"); - runner.setProperty(catalogService, HADOOP_CONFIGURATION_RESOURCES, configFilePaths); - - runner.enableControllerService(catalogService); - - runner.setProperty(PutIceberg.CATALOG, CATALOG_SERVICE_NAME); - } - - private void initKerberosUserService() throws InitializationException { - KerberosUserService kerberosUserService = mock(KerberosUserService.class); - when(kerberosUserService.getIdentifier()).thenReturn(KERBEROS_USER_SERVICE_NAME); - - runner.addControllerService(KERBEROS_USER_SERVICE_NAME, kerberosUserService); - runner.enableControllerService(kerberosUserService); - - runner.setProperty(PutIceberg.KERBEROS_USER_SERVICE, KERBEROS_USER_SERVICE_NAME); - } - - @Test - public void testCustomValidateWithKerberosSecurityConfigAndWithoutKerberosUserService() throws InitializationException { - initRecordReader(); - initCatalogService("src/test/resources/secured-core-site.xml"); - - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAMESPACE); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.assertNotValid(); - } - - @Test - public void testCustomValidateWithKerberosSecurityConfigAndKerberosUserService() throws InitializationException { - initRecordReader(); - initCatalogService("src/test/resources/secured-core-site.xml"); - - initKerberosUserService(); - - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAMESPACE); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.assertValid(); - } - - @Test - public void testCustomValidateWithoutKerberosSecurityConfigAndKerberosUserService() throws InitializationException { - initRecordReader(); - initCatalogService("src/test/resources/unsecured-core-site.xml"); - - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAMESPACE); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.assertValid(); - } - - @Test - public void testCustomValidateWithoutKerberosSecurityConfigAndWithKerberosUserService() throws InitializationException { - initRecordReader(); - initCatalogService("src/test/resources/unsecured-core-site.xml"); - - initKerberosUserService(); - - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAMESPACE); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.assertNotValid(); - } - - @Test - public void testInvalidSnapshotSummaryDynamicProperty() throws InitializationException { - initRecordReader(); - initCatalogService("src/test/resources/unsecured-core-site.xml"); - - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAMESPACE); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - - runner.setProperty("invalid.dynamic.property", "test value"); - runner.assertNotValid(); - } - - @Test - public void testValidSnapshotSummaryDynamicProperty() throws InitializationException { - initRecordReader(); - initCatalogService("src/test/resources/unsecured-core-site.xml"); - - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAMESPACE); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - - runner.setProperty("snapshot-property.valid-property", "test value"); - runner.assertValid(); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithHadoopCatalog.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithHadoopCatalog.java deleted file mode 100644 index 6d120ea2b5..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithHadoopCatalog.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.avro.Schema; -import org.apache.commons.io.IOUtils; -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.PartitionSpec; -import org.apache.iceberg.Table; -import org.apache.iceberg.TableProperties; -import org.apache.iceberg.catalog.Catalog; -import org.apache.iceberg.catalog.TableIdentifier; -import org.apache.iceberg.types.Types; -import org.apache.nifi.avro.AvroTypeUtil; -import org.apache.nifi.processors.iceberg.catalog.IcebergCatalogFactory; -import org.apache.nifi.reporting.InitializationException; -import org.apache.nifi.serialization.record.MockRecordParser; -import org.apache.nifi.serialization.record.RecordField; -import org.apache.nifi.serialization.record.RecordSchema; -import org.apache.nifi.services.iceberg.HadoopCatalogService; -import org.apache.nifi.util.MockFlowFile; -import org.apache.nifi.util.TestRunner; -import org.apache.nifi.util.TestRunners; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.sql.Date; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import static org.apache.nifi.processors.iceberg.PutIceberg.ICEBERG_RECORD_COUNT; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.CATALOG_NAME; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.CATALOG_SERVICE; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.NAMESPACE; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.RECORD_READER_SERVICE; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.createTemporaryDirectory; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validateNumberOfDataFiles; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validatePartitionFolders; -import static org.apache.nifi.services.iceberg.HadoopCatalogService.WAREHOUSE_PATH; -import static org.junit.jupiter.api.condition.OS.WINDOWS; - -public class TestPutIcebergWithHadoopCatalog { - - protected static final String TABLE_NAME = "date_test"; - - private static final TableIdentifier TABLE_IDENTIFIER = TableIdentifier.of(NAMESPACE, TABLE_NAME); - - private static final org.apache.iceberg.Schema DATE_SCHEMA = new org.apache.iceberg.Schema( - Types.NestedField.required(1, "timeMicros", Types.TimeType.get()), - Types.NestedField.required(2, "timestampMicros", Types.TimestampType.withZone()), - Types.NestedField.required(3, "date", Types.DateType.get()) - ); - - private TestRunner runner; - private PutIceberg processor; - private static Schema inputSchema; - private Catalog catalog; - - - @BeforeAll - public static void initSchema() throws IOException { - final String avroSchema = IOUtils.toString(Files.newInputStream(Paths.get("src/test/resources/date.avsc")), StandardCharsets.UTF_8); - inputSchema = new Schema.Parser().parse(avroSchema); - } - - @BeforeEach - public void setUp() { - processor = new PutIceberg(); - } - - private void initRecordReader() throws InitializationException { - final MockRecordParser readerFactory = new MockRecordParser(); - final RecordSchema recordSchema = AvroTypeUtil.createSchema(inputSchema); - - for (RecordField recordField : recordSchema.getFields()) { - readerFactory.addSchemaField(recordField.getFieldName(), recordField.getDataType().getFieldType(), recordField.isNullable()); - } - - readerFactory.addRecord(Time.valueOf("15:30:30"), Timestamp.valueOf("2015-02-02 15:30:30.800"), Date.valueOf("2015-02-02")); - readerFactory.addRecord(Time.valueOf("15:30:30"), Timestamp.valueOf("2015-02-02 15:30:30.800"), Date.valueOf("2015-02-02")); - readerFactory.addRecord(Time.valueOf("15:30:30"), Timestamp.valueOf("2016-01-02 15:30:30.800"), Date.valueOf("2016-01-02")); - readerFactory.addRecord(Time.valueOf("15:30:30"), Timestamp.valueOf("2017-01-10 15:30:30.800"), Date.valueOf("2017-01-10")); - - runner.addControllerService(RECORD_READER_SERVICE, readerFactory); - runner.enableControllerService(readerFactory); - - runner.setProperty(PutIceberg.RECORD_READER, RECORD_READER_SERVICE); - } - - private void initCatalog(PartitionSpec spec, FileFormat fileFormat) throws InitializationException { - final File warehousePath = createTemporaryDirectory(); - final HadoopCatalogService catalogService = new HadoopCatalogService(); - runner.addControllerService(CATALOG_SERVICE, catalogService); - runner.setProperty(catalogService, WAREHOUSE_PATH, warehousePath.getAbsolutePath()); - runner.enableControllerService(catalogService); - - final IcebergCatalogFactory catalogFactory = new IcebergCatalogFactory(catalogService); - catalog = catalogFactory.create(); - - final Map tableProperties = new HashMap<>(); - tableProperties.put(TableProperties.DEFAULT_FILE_FORMAT, fileFormat.name()); - - catalog.createTable(TABLE_IDENTIFIER, DATE_SCHEMA, spec, tableProperties); - - runner.setProperty(PutIceberg.CATALOG, CATALOG_SERVICE); - } - - @DisabledOnOs(WINDOWS) - @Test - public void onTriggerYearTransform() throws Exception { - PartitionSpec spec = PartitionSpec.builderFor(DATE_SCHEMA) - .year("date") - .build(); - - runner = TestRunners.newTestRunner(processor); - initRecordReader(); - initCatalog(spec, FileFormat.PARQUET); - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAME); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.setValidateExpressionUsage(false); - runner.enqueue(new byte[0]); - runner.run(); - - final Table table = catalog.loadTable(TABLE_IDENTIFIER); - - runner.assertTransferCount(PutIceberg.REL_SUCCESS, 1); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutIceberg.REL_SUCCESS).getFirst(); - - Assertions.assertTrue(table.spec().isPartitioned()); - Assertions.assertEquals("4", flowFile.getAttribute(ICEBERG_RECORD_COUNT)); - validateNumberOfDataFiles(table.location(), 3); - validatePartitionFolders(table.location(), Arrays.asList("date_year=2015", "date_year=2016", "date_year=2017")); - } - - @DisabledOnOs(WINDOWS) - @Test - public void onTriggerMonthTransform() throws Exception { - final PartitionSpec spec = PartitionSpec.builderFor(DATE_SCHEMA) - .month("timestampMicros") - .build(); - - runner = TestRunners.newTestRunner(processor); - initRecordReader(); - initCatalog(spec, FileFormat.ORC); - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAME); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.setValidateExpressionUsage(false); - runner.enqueue(new byte[0]); - runner.run(); - - final Table table = catalog.loadTable(TABLE_IDENTIFIER); - - runner.assertTransferCount(PutIceberg.REL_SUCCESS, 1); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutIceberg.REL_SUCCESS).getFirst(); - - Assertions.assertTrue(table.spec().isPartitioned()); - Assertions.assertEquals("4", flowFile.getAttribute(ICEBERG_RECORD_COUNT)); - validateNumberOfDataFiles(table.location(), 3); - validatePartitionFolders(table.location(), Arrays.asList( - "timestampMicros_month=2015-02", "timestampMicros_month=2016-01", "timestampMicros_month=2017-01")); - } - - @DisabledOnOs(WINDOWS) - @Test - public void onTriggerDayTransform() throws Exception { - final PartitionSpec spec = PartitionSpec.builderFor(DATE_SCHEMA) - .day("timestampMicros") - .build(); - - runner = TestRunners.newTestRunner(processor); - initRecordReader(); - initCatalog(spec, FileFormat.AVRO); - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAME); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.setValidateExpressionUsage(false); - runner.enqueue(new byte[0]); - runner.run(); - - final Table table = catalog.loadTable(TABLE_IDENTIFIER); - - runner.assertTransferCount(PutIceberg.REL_SUCCESS, 1); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutIceberg.REL_SUCCESS).getFirst(); - - Assertions.assertTrue(table.spec().isPartitioned()); - Assertions.assertEquals("4", flowFile.getAttribute(ICEBERG_RECORD_COUNT)); - validateNumberOfDataFiles(table.location(), 3); - validatePartitionFolders(table.location(), Arrays.asList( - "timestampMicros_day=2015-02-02", "timestampMicros_day=2016-01-02", "timestampMicros_day=2017-01-10")); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithHiveCatalog.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithHiveCatalog.java deleted file mode 100644 index 21ff765c1f..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithHiveCatalog.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.PartitionSpec; -import org.apache.iceberg.Table; -import org.apache.iceberg.TableProperties; -import org.apache.iceberg.data.Record; -import org.apache.nifi.hive.metastore.ThriftMetastore; -import org.apache.nifi.processors.iceberg.catalog.IcebergCatalogFactory; -import org.apache.nifi.processors.iceberg.util.IcebergTestUtils; -import org.apache.nifi.provenance.ProvenanceEventRecord; -import org.apache.nifi.provenance.ProvenanceEventType; -import org.apache.nifi.reporting.InitializationException; -import org.apache.nifi.services.iceberg.HiveCatalogService; -import org.apache.nifi.util.MockFlowFile; -import org.apache.nifi.util.TestRunners; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.net.URI; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.apache.nifi.processors.iceberg.PutIceberg.ICEBERG_RECORD_COUNT; -import static org.apache.nifi.processors.iceberg.PutIceberg.ICEBERG_SNAPSHOT_SUMMARY_FLOWFILE_UUID; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.CATALOG_NAME; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validateData; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validateNumberOfDataFiles; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validatePartitionFolders; -import static org.apache.nifi.services.iceberg.HiveCatalogService.METASTORE_URI; -import static org.apache.nifi.services.iceberg.HiveCatalogService.WAREHOUSE_LOCATION; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.condition.OS.WINDOWS; - -@DisabledOnOs(WINDOWS) -public class TestPutIcebergWithHiveCatalog extends AbstractTestPutIceberg { - - @RegisterExtension - public static ThriftMetastore metastore = new ThriftMetastore(); - - private void initCatalog(PartitionSpec spec, FileFormat fileFormat) throws InitializationException { - final Map tableProperties = new HashMap<>(); - tableProperties.put(TableProperties.DEFAULT_FILE_FORMAT, fileFormat.name()); - - final HiveCatalogService catalogService = new HiveCatalogService(); - runner.addControllerService("catalog-service", catalogService); - runner.setProperty(catalogService, METASTORE_URI, metastore.getThriftConnectionUri()); - runner.setProperty(catalogService, WAREHOUSE_LOCATION, warehousePath); - runner.enableControllerService(catalogService); - - final IcebergCatalogFactory catalogFactory = new IcebergCatalogFactory(catalogService); - catalog = catalogFactory.create(); - - catalog.createTable(TABLE_IDENTIFIER, USER_SCHEMA, spec, tableProperties); - - runner.setProperty(PutIceberg.CATALOG, "catalog-service"); - } - - @Test - public void onTriggerIdentityPartitioned() throws Exception { - final PartitionSpec spec = PartitionSpec.builderFor(USER_SCHEMA) - .identity("department") - .build(); - - runner = TestRunners.newTestRunner(processor); - initRecordReader(); - initCatalog(spec, FileFormat.ORC); - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAME); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.setValidateExpressionUsage(false); - runner.enqueue(new byte[0]); - runner.run(); - - final Table table = catalog.loadTable(TABLE_IDENTIFIER); - - final List expectedRecords = IcebergTestUtils.RecordsBuilder.newInstance(USER_SCHEMA) - .add(0, "John", "Finance") - .add(1, "Jill", "Finance") - .add(2, "James", "Marketing") - .add(3, "Joana", "Sales") - .build(); - - runner.assertTransferCount(PutIceberg.REL_SUCCESS, 1); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutIceberg.REL_SUCCESS).getFirst(); - - final String tableLocation = new URI(table.location()).getPath(); - assertTrue(table.spec().isPartitioned()); - assertEquals("4", flowFile.getAttribute(ICEBERG_RECORD_COUNT)); - validateData(table, expectedRecords, 0); - validateNumberOfDataFiles(tableLocation, 3); - validatePartitionFolders(tableLocation, Arrays.asList( - "department=Finance", "department=Marketing", "department=Sales")); - assertProvenanceEvents(); - } - - @Test - public void onTriggerMultiLevelIdentityPartitioned() throws Exception { - final PartitionSpec spec = PartitionSpec.builderFor(USER_SCHEMA) - .identity("name") - .identity("department") - .build(); - - runner = TestRunners.newTestRunner(processor); - initRecordReader(); - initCatalog(spec, FileFormat.PARQUET); - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAME); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.setValidateExpressionUsage(false); - runner.enqueue(new byte[0]); - runner.run(); - - final Table table = catalog.loadTable(TABLE_IDENTIFIER); - - final List expectedRecords = IcebergTestUtils.RecordsBuilder.newInstance(USER_SCHEMA) - .add(0, "John", "Finance") - .add(1, "Jill", "Finance") - .add(2, "James", "Marketing") - .add(3, "Joana", "Sales") - .build(); - - runner.assertTransferCount(PutIceberg.REL_SUCCESS, 1); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutIceberg.REL_SUCCESS).getFirst(); - - final String tableLocation = new URI(table.location()).getPath(); - assertTrue(table.spec().isPartitioned()); - assertEquals("4", flowFile.getAttribute(ICEBERG_RECORD_COUNT)); - validateData(table, expectedRecords, 0); - validateNumberOfDataFiles(tableLocation, 4); - validatePartitionFolders(tableLocation, Arrays.asList( - "name=James/department=Marketing/", - "name=Jill/department=Finance/", - "name=Joana/department=Sales/", - "name=John/department=Finance/" - )); - assertProvenanceEvents(); - } - - @Test - public void onTriggerUnPartitioned() throws Exception { - runner = TestRunners.newTestRunner(processor); - initRecordReader(); - initCatalog(PartitionSpec.unpartitioned(), FileFormat.AVRO); - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, "${catalog.name}"); - runner.setProperty(PutIceberg.TABLE_NAME, "${table.name}"); - runner.setProperty(PutIceberg.MAXIMUM_FILE_SIZE, "${max.filesize}"); - runner.setProperty("snapshot-property.additional-summary-property", "test summary property"); - final Map attributes = new HashMap<>(); - attributes.put("catalog.name", CATALOG_NAME); - attributes.put("table.name", TABLE_NAME); - attributes.put("max.filesize", "536870912"); // 512 MB - runner.enqueue(new byte[0], attributes); - runner.run(); - - final Table table = catalog.loadTable(TABLE_IDENTIFIER); - - final List expectedRecords = IcebergTestUtils.RecordsBuilder.newInstance(USER_SCHEMA) - .add(0, "John", "Finance") - .add(1, "Jill", "Finance") - .add(2, "James", "Marketing") - .add(3, "Joana", "Sales") - .build(); - - runner.assertTransferCount(PutIceberg.REL_SUCCESS, 1); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutIceberg.REL_SUCCESS).getFirst(); - - assertTrue(table.spec().isUnpartitioned()); - assertEquals("4", flowFile.getAttribute(ICEBERG_RECORD_COUNT)); - validateData(table, expectedRecords, 0); - validateNumberOfDataFiles(new URI(table.location()).getPath(), 1); - assertProvenanceEvents(); - assertSnapshotSummaryProperties(table, Collections.singletonMap("additional-summary-property", "test summary property")); - } - - private void assertProvenanceEvents() { - final List provenanceEvents = runner.getProvenanceEvents(); - assertEquals(1, provenanceEvents.size()); - final ProvenanceEventRecord sendEvent = provenanceEvents.getFirst(); - assertEquals(ProvenanceEventType.SEND, sendEvent.getEventType()); - assertTrue(sendEvent.getTransitUri().endsWith(CATALOG_NAME + ".db/" + TABLE_NAME)); - } - - private void assertSnapshotSummaryProperties(Table table, Map summaryProperties) { - final Map snapshotSummary = table.currentSnapshot().summary(); - - assertTrue(snapshotSummary.containsKey(ICEBERG_SNAPSHOT_SUMMARY_FLOWFILE_UUID)); - - for (Map.Entry entry : summaryProperties.entrySet()) { - assertEquals(snapshotSummary.get(entry.getKey()), entry.getValue()); - } - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithJdbcCatalog.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithJdbcCatalog.java deleted file mode 100644 index c03aff304b..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/TestPutIcebergWithJdbcCatalog.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.nifi.processors.iceberg; - -import org.apache.hadoop.conf.Configuration; -import org.apache.iceberg.CatalogProperties; -import org.apache.iceberg.CatalogUtil; -import org.apache.iceberg.FileFormat; -import org.apache.iceberg.PartitionSpec; -import org.apache.iceberg.Table; -import org.apache.iceberg.TableProperties; -import org.apache.iceberg.data.Record; -import org.apache.iceberg.io.FileIO; -import org.apache.iceberg.jdbc.JdbcCatalog; -import org.apache.iceberg.jdbc.JdbcClientPool; -import org.apache.nifi.dbcp.DBCPConnectionPool; -import org.apache.nifi.processors.iceberg.catalog.IcebergJdbcClientPool; -import org.apache.nifi.processors.iceberg.util.IcebergTestUtils; -import org.apache.nifi.reporting.InitializationException; -import org.apache.nifi.services.iceberg.JdbcCatalogService; -import org.apache.nifi.util.MockFlowFile; -import org.apache.nifi.util.TestRunners; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; - -import java.io.File; -import java.net.URI; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import static org.apache.nifi.dbcp.utils.DBCPProperties.DATABASE_URL; -import static org.apache.nifi.dbcp.utils.DBCPProperties.DB_DRIVERNAME; -import static org.apache.nifi.dbcp.utils.DBCPProperties.DB_PASSWORD; -import static org.apache.nifi.dbcp.utils.DBCPProperties.DB_USER; -import static org.apache.nifi.processors.iceberg.PutIceberg.ICEBERG_RECORD_COUNT; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.CATALOG_NAME; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.CATALOG_SERVICE; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.createTemporaryDirectory; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.getSystemTemporaryDirectory; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validateData; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validateNumberOfDataFiles; -import static org.apache.nifi.processors.iceberg.util.IcebergTestUtils.validatePartitionFolders; -import static org.apache.nifi.services.iceberg.JdbcCatalogService.CONNECTION_POOL; -import static org.apache.nifi.services.iceberg.JdbcCatalogService.WAREHOUSE_PATH; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.condition.OS.WINDOWS; - -@DisabledOnOs(WINDOWS) -public class TestPutIcebergWithJdbcCatalog extends AbstractTestPutIceberg { - - private static final String DERBY_LOG_PROPERTY = "derby.stream.error.file"; - private static final String CONNECTION_POOL_SERVICE = "connection-pool-service"; - - private static DBCPConnectionPool connectionPool; - - @BeforeAll - public static void initConnectionPool() { - setDerbyLog(); - connectionPool = new DBCPConnectionPool(); - } - - @AfterAll - public static void clearDerbyLog() { - System.clearProperty(DERBY_LOG_PROPERTY); - } - - private void initServices(PartitionSpec spec) throws InitializationException { - initDBCPService(); - initRecordReader(); - initCatalogService(); - createTestTable(spec); - } - - private void initCatalogService() throws InitializationException { - final JdbcCatalogService catalogService = new JdbcCatalogService(); - runner.addControllerService(CATALOG_SERVICE, catalogService); - runner.setProperty(catalogService, CONNECTION_POOL, CONNECTION_POOL_SERVICE); - runner.setProperty(catalogService, WAREHOUSE_PATH, warehousePath); - runner.enableControllerService(catalogService); - runner.setProperty(PutIceberg.CATALOG, CATALOG_SERVICE); - } - - private void initDBCPService() throws InitializationException { - final String url = String.format("jdbc:derby:%s;create=true", createTemporaryDirectory()); - runner.addControllerService(CONNECTION_POOL_SERVICE, connectionPool); - runner.setProperty(connectionPool, DATABASE_URL, url); - runner.setProperty(connectionPool, DB_USER, String.class.getSimpleName()); - runner.setProperty(connectionPool, DB_PASSWORD, String.class.getName()); - runner.setProperty(connectionPool, DB_DRIVERNAME, "org.apache.derby.jdbc.EmbeddedDriver"); - runner.enableControllerService(connectionPool); - } - - private void createTestTable(PartitionSpec spec) { - final Map properties = new HashMap<>(); - properties.put(CatalogProperties.URI, ""); - properties.put(CatalogProperties.WAREHOUSE_LOCATION, warehousePath); - - final Function, JdbcClientPool> clientPoolBuilder = props -> new IcebergJdbcClientPool(props, connectionPool); - final Function, FileIO> ioBuilder = props -> CatalogUtil.loadFileIO("org.apache.iceberg.hadoop.HadoopFileIO", props, new Configuration()); - - catalog = new JdbcCatalog(ioBuilder, clientPoolBuilder, true); - catalog.initialize("jdbc-catalog", properties); - - final Map tableProperties = new HashMap<>(); - tableProperties.put(TableProperties.DEFAULT_FILE_FORMAT, FileFormat.PARQUET.name()); - - catalog.createTable(TABLE_IDENTIFIER, USER_SCHEMA, spec, tableProperties); - } - - public static void setDerbyLog() { - final File derbyLog = new File(getSystemTemporaryDirectory(), "derby.log"); - derbyLog.deleteOnExit(); - System.setProperty(DERBY_LOG_PROPERTY, derbyLog.getAbsolutePath()); - } - - @Test - public void onTriggerBucketPartitioned() throws Exception { - final PartitionSpec spec = PartitionSpec.builderFor(USER_SCHEMA) - .bucket("department", 3) - .build(); - - runner = TestRunners.newTestRunner(processor); - runner.setValidateExpressionUsage(false); - initServices(spec); - runner.setProperty(PutIceberg.CATALOG_NAMESPACE, CATALOG_NAME); - runner.setProperty(PutIceberg.TABLE_NAME, TABLE_NAME); - runner.enqueue(new byte[0]); - runner.run(); - - final Table table = catalog.loadTable(TABLE_IDENTIFIER); - - final List expectedRecords = IcebergTestUtils.RecordsBuilder.newInstance(USER_SCHEMA) - .add(0, "John", "Finance") - .add(1, "Jill", "Finance") - .add(2, "James", "Marketing") - .add(3, "Joana", "Sales") - .build(); - - runner.assertTransferCount(PutIceberg.REL_SUCCESS, 1); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutIceberg.REL_SUCCESS).getFirst(); - - final String tableLocation = new URI(table.location()).getPath(); - assertTrue(table.spec().isPartitioned()); - assertEquals("4", flowFile.getAttribute(ICEBERG_RECORD_COUNT)); - validateData(table, expectedRecords, 0); - validateNumberOfDataFiles(tableLocation, 3); - validatePartitionFolders(tableLocation, Arrays.asList( - "department_bucket=0", "department_bucket=1", "department_bucket=2")); - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/util/IcebergTestUtils.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/util/IcebergTestUtils.java deleted file mode 100644 index 06918893ac..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/java/org/apache/nifi/processors/iceberg/util/IcebergTestUtils.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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.nifi.processors.iceberg.util; - -import com.google.common.collect.Lists; -import org.apache.commons.lang.Validate; -import org.apache.iceberg.Schema; -import org.apache.iceberg.Table; -import org.apache.iceberg.catalog.Namespace; -import org.apache.iceberg.data.GenericRecord; -import org.apache.iceberg.data.IcebergGenerics; -import org.apache.iceberg.data.Record; -import org.apache.iceberg.io.CloseableIterable; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class IcebergTestUtils { - - public static final String RECORD_READER_SERVICE = "record-reader-service"; - public static final String CATALOG_SERVICE = "catalog-service"; - public static final String CATALOG_NAME = "iceberg_test"; - - public static final Namespace NAMESPACE = Namespace.of(CATALOG_NAME); - - /** - * Validates whether the table contains the expected records. The results should be sorted by a unique key, so we do not end up with flaky tests. - * - * @param table The table we should read the records from - * @param expected The expected list of Records - * @param sortBy The column position by which we will sort - * @throws IOException Exceptions when reading the table data - */ - public static void validateData(Table table, List expected, int sortBy) throws IOException { - List records = Lists.newArrayListWithExpectedSize(expected.size()); - try (CloseableIterable iterable = IcebergGenerics.read(table).build()) { - iterable.forEach(records::add); - } - - validateData(expected, records, sortBy); - } - - /** - * Validates whether the 2 sets of records are the same. The results should be sorted by a unique key, so we do not end up with flaky tests. - * - * @param expected The expected list of Records - * @param actual The actual list of Records - * @param sortBy The column position by which we will sort - */ - public static void validateData(List expected, List actual, int sortBy) { - List sortedExpected = Lists.newArrayList(expected); - List sortedActual = Lists.newArrayList(actual); - // Sort based on the specified field - sortedExpected.sort(Comparator.comparingInt(record -> record.get(sortBy).hashCode())); - sortedActual.sort(Comparator.comparingInt(record -> record.get(sortBy).hashCode())); - - assertEquals(sortedExpected.size(), sortedActual.size()); - for (int i = 0; i < expected.size(); ++i) { - assertEquals(sortedExpected.get(i), sortedActual.get(i)); - } - } - - /** - * Validates the number of files under a {@link Table} - * - * @param tableLocation The location of table we are checking - * @param numberOfDataFiles The expected number of data files (TABLE_LOCATION/data/*) - */ - public static void validateNumberOfDataFiles(String tableLocation, int numberOfDataFiles) throws IOException { - List dataFiles = Files.walk(Paths.get(tableLocation + "/data")) - .filter(Files::isRegularFile) - .filter(path -> !path.getFileName().toString().startsWith(".")) - .toList(); - - assertEquals(numberOfDataFiles, dataFiles.size()); - } - - public static void validatePartitionFolders(String tableLocation, List partitionPaths) { - for (String partitionPath : partitionPaths) { - Path path = Paths.get(tableLocation + "/data/" + partitionPath); - assertTrue(Files.exists(path), "The expected path doesn't exists: " + path); - } - } - - public static String getSystemTemporaryDirectory() { - return System.getProperty("java.io.tmpdir"); - } - - public static File createTemporaryDirectory() { - return Paths.get(getSystemTemporaryDirectory(), UUID.randomUUID().toString()).toFile(); - } - - public static class RecordsBuilder { - - private final List records = new ArrayList<>(); - private final Schema schema; - - private RecordsBuilder(Schema schema) { - this.schema = schema; - } - - public RecordsBuilder add(Object... values) { - Validate.isTrue(schema.columns().size() == values.length, "Number of provided values and schema length should be equal."); - - GenericRecord record = GenericRecord.create(schema); - - for (int i = 0; i < values.length; i++) { - record.set(i, values[i]); - } - - records.add(record); - return this; - } - - public List build() { - return Collections.unmodifiableList(records); - } - - public static RecordsBuilder newInstance(Schema schema) { - return new RecordsBuilder(schema); - } - } - -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/date.avsc b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/date.avsc deleted file mode 100644 index 6fc6010b78..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/date.avsc +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ -{ - "namespace": "nifi", - "name": "data_types", - "type": "record", - "fields": [ - { - "name" : "timeMicros", - "type": { - "type": "long", - "logicalType": "time-micros" - } - }, - { - "name" : "timestampMicros", - "type": { - "type" : "long", - "logicalType" : "timestamp-micros" - } - }, - { - "name" : "date", - "type": { - "type" : "int", - "logicalType" : "date" - } - } - ] -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/secured-core-site.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/secured-core-site.xml deleted file mode 100644 index 0fd06a5383..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/secured-core-site.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - hadoop.security.authentication - kerberos - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/unsecured-core-site.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/unsecured-core-site.xml deleted file mode 100644 index d590a5039c..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/unsecured-core-site.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - hadoop.security.authentication - simple - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/user.avsc b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/user.avsc deleted file mode 100644 index 799c0023b4..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-processors/src/test/resources/user.avsc +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ -{ - "namespace": "nifi", - "type": "record", - "name": "User", - "fields": [ - { - "name": "id", - "type": ["long", "null"] - }, - { - "name": "name", - "type": ["string", "null"] - }, - { - "name": "department", - "type": { - "name": "Department", - "type": "enum", - "symbols": ["Finance", "Marketing", "Sales"] - } - } - ] -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/pom.xml deleted file mode 100644 index 4e7d773945..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - nifi-iceberg-bundle - org.apache.nifi - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-iceberg-services-api-nar - nar - - - - org.apache.nifi - nifi-iceberg-services-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-standard-services-api-nar - 2.0.0-SNAPSHOT - nar - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/src/main/resources/META-INF/LICENSE b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/src/main/resources/META-INF/LICENSE deleted file mode 100644 index 6effaa89d3..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/src/main/resources/META-INF/LICENSE +++ /dev/null @@ -1,209 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - -APACHE NIFI SUBCOMPONENTS: - -The Apache NiFi project contains subcomponents with separate copyright -notices and license terms. Your use of the source code for the these -subcomponents is subject to the terms and conditions of the following -licenses. \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/src/main/resources/META-INF/NOTICE b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/src/main/resources/META-INF/NOTICE deleted file mode 100644 index 1c764a0630..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api-nar/src/main/resources/META-INF/NOTICE +++ /dev/null @@ -1,501 +0,0 @@ -nifi-iceberg-processors-nar -Copyright 2014-2024 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=========================================== -Apache Software License v2 -=========================================== - - (ASLv2) Apache Iceberg - The following NOTICE information applies: - Apache Iceberg - Copyright 2017-2022 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - (ASLv2) Apache Ant - The following NOTICE information applies: - Apache Ant - Copyright 1999-2016 The Apache Software Foundation - - (ASLv2) Apache Commons Codec - The following NOTICE information applies: - Apache Commons Codec - Copyright 2002-2014 The Apache Software Foundation - - src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java - contains test data from http://aspell.net/test/orig/batch0.tab. - Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) - - =============================================================================== - - The content of package org.apache.commons.codec.language.bm has been translated - from the original php source code available at http://stevemorse.org/phoneticinfo.htm - with permission from the original authors. - Original source copyright: - Copyright (c) 2008 Alexander Beider & Stephen P. Morse. - - (ASLv2) Apache Commons DBCP - The following NOTICE information applies: - Apache Commons DBCP - Copyright 2001-2015 The Apache Software Foundation. - - (ASLv2) Apache HttpComponents - The following NOTICE information applies: - Apache HttpComponents Client - Copyright 1999-2016 The Apache Software Foundation - Apache HttpComponents Core - HttpCore - Copyright 2006-2009 The Apache Software Foundation - - (ASLv2) Apache Commons Pool - The following NOTICE information applies: - Apache Commons Pool - Copyright 1999-2009 The Apache Software Foundation. - - (ASLv2) Apache Commons BeanUtils - The following NOTICE information applies: - Apache Commons BeanUtils - Copyright 2000-2016 The Apache Software Foundation - - (ASLv2) Apache Commons IO - The following NOTICE information applies: - Apache Commons IO - Copyright 2002-2016 The Apache Software Foundation - - (ASLv2) Apache Commons Net - The following NOTICE information applies: - Apache Commons Net - Copyright 2001-2016 The Apache Software Foundation - - (ASLv2) Apache Avro - The following NOTICE information applies: - Apache Avro - Copyright 2009-2017 The Apache Software Foundation - - (ASLv2) Apache Parquet - The following NOTICE information applies: - Apache Parquet MR (Incubating) - Copyright 2014 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - (ASLv2) Audience Annotations - The following NOTICE information applies: - Apache Yetus - Copyright 2008-2018 The Apache Software Foundation - - (ASLv2) Apache Commons Compress - The following NOTICE information applies: - Apache Commons Compress - Copyright 2002-2017 The Apache Software Foundation - - The files in the package org.apache.commons.compress.archivers.sevenz - were derived from the LZMA SDK, version 9.20 (C/ and CPP/7zip/), - which has been placed in the public domain: - - "LZMA SDK is placed in the public domain." (http://www.7-zip.org/sdk.html) - - (ASLv2) Apache Commons Configuration - The following NOTICE information applies: - Apache Commons Configuration - Copyright 2001-2017 The Apache Software Foundation - - (ASLv2) Apache Commons Text - The following NOTICE information applies: - Apache Commons Text - Copyright 2001-2018 The Apache Software Foundation - - (ASLv2) Apache Commons CLI - The following NOTICE information applies: - Apache Commons CLI - Copyright 2001-2017 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - (ASLv2) Apache Commons Collections - The following NOTICE information applies: - Apache Commons Collections - Copyright 2001-2016 The Apache Software Foundation - - (ASLv2) Apache Commons Daemon - The following NOTICE information applies: - Apache Commons Daemon - Copyright 2002-2013 The Apache Software Foundation - - (ASLv2) Apache Ivy - The following NOTICE information applies: - Copyright 2007-2017 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - Portions of Ivy were originally developed at - Jayasoft SARL (http://www.jayasoft.fr/) - and are licensed to the Apache Software Foundation under the - "Software Grant License Agreement" - - SSH and SFTP support is provided by the JCraft JSch package, - which is open source software, available under - the terms of a BSD style license. - The original software and related information is available - at http://www.jcraft.com/jsch/. - - (ASLv2) Apache Commons Math - The following NOTICE information applies: - Apache Commons Math - Copyright 2001-2012 The Apache Software Foundation - - (ASLv2) Apache Hive - The following NOTICE information applies: - Apache Hive - Copyright 2008-2015 The Apache Software Foundation - - This product includes software developed by The Apache Software - Foundation (http://www.apache.org/). - - This product includes Jersey (https://jersey.java.net/) - Copyright (c) 2010-2014 Oracle and/or its affiliates. - - This project includes software copyrighted by Microsoft Corporation and - licensed under the Apache License, Version 2.0. - - This project includes software copyrighted by Dell SecureWorks and - licensed under the Apache License, Version 2.0. - - (ASLv2) Jackson JSON processor - The following NOTICE information applies: - # Jackson JSON processor - - Jackson is a high-performance, Free/Open Source JSON processing library. - It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has - been in development since 2007. - It is currently developed by a community of developers, as well as supported - commercially by FasterXML.com. - - ## Licensing - - Jackson core and extension components may licensed under different licenses. - To find the details that apply to this artifact see the accompanying LICENSE file. - For more information, including possible other licensing options, contact - FasterXML.com (http://fasterxml.com). - - ## Credits - - A list of contributors may be found from CREDITS file, which is included - in some artifacts (usually source distributions); but is always available - from the source code management (SCM) system project uses. - - (ASLv2) BoneCP - The following NOTICE information applies: - BoneCP - Copyright 2010 Wallace Wadge - - (ASLv2) Apache Hadoop - The following NOTICE information applies: - The binary distribution of this product bundles binaries of - org.iq80.leveldb:leveldb-api (https://github.com/dain/leveldb), which has the - following notices: - * Copyright 2011 Dain Sundstrom - * Copyright 2011 FuseSource Corp. http://fusesource.com - - The binary distribution of this product bundles binaries of - org.fusesource.hawtjni:hawtjni-runtime (https://github.com/fusesource/hawtjni), - which has the following notices: - * This product includes software developed by FuseSource Corp. - http://fusesource.com - * This product includes software developed at - Progress Software Corporation and/or its subsidiaries or affiliates. - * This product includes software developed by IBM Corporation and others. - - (ASLv2) Apache Commons Lang - The following NOTICE information applies: - Apache Commons Lang - Copyright 2001-2015 The Apache Software Foundation - - (ASLv2) Apache Curator - The following NOTICE information applies: - Curator Framework - Copyright 2011-2014 The Apache Software Foundation - - Curator Client - Copyright 2011-2014 The Apache Software Foundation - - Curator Recipes - Copyright 2011-2014 The Apache Software Foundation - - (ASLv2) Apache Derby - The following NOTICE information applies: - Apache Derby - Copyright 2004-2014 Apache, Apache DB, Apache Derby, Apache Torque, Apache JDO, Apache DDLUtils, - the Derby hat logo, the Apache JDO logo, and the Apache feather logo are trademarks of The Apache Software Foundation. - - (ASLv2) Apache Geronimo - The following NOTICE information applies: - Apache Geronimo - Copyright 2003-2008 The Apache Software Foundation - - (ASLv2) Jettison - The following NOTICE information applies: - Copyright 2006 Envoi Solutions LLC - - (ASLv2) Jetty - The following NOTICE information applies: - Jetty Web Container - Copyright 1995-2019 Mort Bay Consulting Pty Ltd. - - (ASLv2) Apache log4j - The following NOTICE information applies: - Apache log4j - Copyright 2007 The Apache Software Foundation - - (ASLv2) Apache Thrift - The following NOTICE information applies: - Apache Thrift - Copyright 2006-2010 The Apache Software Foundation. - - (ASLv2) Dropwizard Metrics - The following NOTICE information applies: - Metrics - Copyright 2010-2013 Coda Hale and Yammer, Inc. - - This product includes code derived from the JSR-166 project (ThreadLocalRandom, Striped64, - LongAdder), which was released with the following comments: - - Written by Doug Lea with assistance from members of JCP JSR-166 - Expert Group and released to the public domain, as explained at - http://creativecommons.org/publicdomain/zero/1.0/ - - (ASLv2) Joda Time - The following NOTICE information applies: - This product includes software developed by - Joda.org (http://www.joda.org/). - - (ASLv2) The Netty Project - The following NOTICE information applies: - The Netty Project - Copyright 2011 The Netty Project - - (ASLv2) Apache ZooKeeper - The following NOTICE information applies: - Apache ZooKeeper - Copyright 2009-2012 The Apache Software Foundation - - (ASLv2) JPam - The following NOTICE information applies: - Copyright 2003-2006 Greg Luck - - (ASLv2) Groovy 2.4.16 (http://www.groovy-lang.org) - groovy-2.4.16-indy - groovy-json-2.4.16-indy - groovy-sql-2.4.16-indy - The following NOTICE information applies: - Apache Groovy - Copyright 2003-2018 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - This product includes/uses ANTLR (http://www.antlr2.org/) - developed by Terence Parr 1989-2006 - - (ASLv2) ASM Based Accessors Helper Used By JSON Smart (net.minidev:accessors-smart:jar:1.2 - http://www.minidev.net/) - The following NOTICE information applies: - ASM Based Accessors Helper Used By JSON Smart 1.2 - Copyright 2017, Uriel Chemouni - - (ASLv2) JSON Smart (net.minidev:json-smart:jar:2.3 - http://www.minidev.net/) - The following NOTICE information applies: - JSON Smart 2.3 - Copyright 2017, Uriel Chemouni, Eitan Raviv - - (ASLv2) Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt - https://connect2id.com/products/nimbus-jose-jwt) - The following NOTICE information applies: - Nimbus JOSE+JWT - Copyright 2021, Connect2id Ltd. - - (ASLv2) Woodstox (com.fasterxml.woodstox:woodstox-core:bundle:5.3.0 - https://github.com/FasterXML/woodstox) - The following NOTICE information applies: - Woodstox Core 5.3.0 - Copyright 2015, FasterXML, LLC - - (ASLv2) Joda Time - The following NOTICE information applies: - This product includes software developed by - Joda.org (http://www.joda.org/). - - (ASLv2) java-util - The following NOTICE information applies: - java-util - Copyright 2011-2017 Metamarkets Group Inc. - - (ASLv2) JCIP Annotations Under Apache License - The following NOTICE information applies: - JCIP Annotations Under Apache License - Copyright 2013 Stephen Connolly. - - (ASLv2) Google GSON - The following NOTICE information applies: - Copyright 2008 Google Inc. - - (ASLv2) Guava - The following NOTICE information applies: - Guava - Copyright 2015 The Guava Authors - - (ASLv2) OkHttp - The following NOTICE information applies: - OkHttp - Copyright (C) 2014 Square, Inc. - - (ASLv2) Okio - The following NOTICE information applies: - Okio - Copyright (C) 2014 Square, Inc. - - (ASLv2) Dropwizard Metrics - The following NOTICE information applies: - Dropwizard Metrics - Copyright 2010-2013 Coda Hale and Yammer, Inc., 2014-2017 Dropwizard Team - - (ASLv2) atinject (javax.inject:javax.inject) - The following NOTICE information applies: - atinject - Copyright - - (ASLv2) opencsv (net.sf.opencsv:opencsv:2.3) - - (ASLv2) JetBrains/java-annotations - The following NOTICE information applies: - JetBrains/java-annotations - Copyright 2000-2016 JetBrains s.r.o. - - (ASLv2) Apache Kerby - The following NOTICE information applies: - Apache Kerby - Copyright 2003-2018 The Apache Software Foundation - - (ASLv2) Carrotsearch HPPC - The following NOTICE information applies: - HPPC borrowed code, ideas or both from: - - * Apache Lucene, http://lucene.apache.org/ - (Apache license) - * Fastutil, http://fastutil.di.unimi.it/ - (Apache license) - * Koloboke, https://github.com/OpenHFT/Koloboke - (Apache license) - - (ASLv2) Ehcache 2.x - The following NOTICE information applies: - Copyright 2003-2010 Terracotta, Inc. - - (ASLv2) Google Guice - The following NOTICE information applies: - Google Guice - Core Library - Copyright 2006-2011 Google, Inc. - - Google Guice - Extensions - Servlet - Copyright 2006-2011 Google, Inc. - - (ASLv2) Apache Arrow - The following NOTICE information applies: - Copyright 2016-2019 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). - - - (ASLv2) Apache ORC - The following NOTICE information applies: - Copyright 2013-2019 The Apache Software Foundation - - This product includes software developed by The Apache Software - Foundation (http://www.apache.org/). - - This product includes software developed by Hewlett-Packard: - (c) Copyright [2014-2015] Hewlett-Packard Development Company, L.P - -************************ -Common Development and Distribution License 1.1 -************************ - - The following binary components are provided under the Common Development and Distribution License 1.1. See project link for details. - - (CDDL 1.1) (GPL2 w/ CPE) jersey-client (com.sun.jersey:jersey-client:jar:1.19 - https://jersey.java.net) - (CDDL 1.1) (GPL2 w/ CPE) jersey-core (com.sun.jersey:jersey-core:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) jersey-json (com.sun.jersey:jersey-json:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) jersey-server (com.sun.jersey:jersey-server:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) jersey-guice (com.sun.jersey.contribs:jersey-guice:jar:1.19 - https://jersey.java.net/) - (CDDL 1.1) (GPL2 w/ CPE) Java Architecture For XML Binding (javax.xml.bind:jaxb-api:jar:2.2.11 - https://jaxb.dev.java.net/) - -************************ -Common Development and Distribution License 1.0 -************************ - - The following binary components are provided under the Common Development and Distribution License 1.0. See project link for details. - - (CDDL 1.0) JavaServlet(TM) Specification (javax.servlet:servlet-api:jar:3.1.0 - no url available) - (CDDL 1.0) JavaServer Pages(TM) API (javax.servlet.jsp:jsp-api:jar:2.1 - http://jsp.java.net) - (CDDL 1.0) JSR311 API (javax.ws.rs:jsr311-api:jar:1.1.1 - https://jsr311.dev.java.net) - -***************** -Public Domain -***************** - - The following binary components are provided to the 'Public Domain'. See project link for details. - - (Public Domain) AOP Alliance 1.0 (http://aopalliance.sourceforge.net/) - - -************************ -Eclipse Distribution License 1.0 -************************ - - The following binary components are provided under the Eclipse Distribution License 1.0. - - (EDL 1.0) Jakarta Activation API (jakarta.activation:jakarta.activation-api:jar:1.2.1) - (EDL 1.0) Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3) - -************************ -Eclipse Public License 2.0 -************************ - - The following binary components are provided under the Eclipse Public License 2.0. - - (EPL 2.0) javax.ws.rs-api (https://github.com/eclipse-ee4j/jaxrs-api) javax.ws.rs:javax.ws.rs-api:bundle:2.1.1 - -************************ -BSD License -************************ - - (BSD) JSch - The following NOTICE information applies: - Copyright (c) 2002-2015 Atsuhiko Yamanaka, JCraft,Inc. - All rights reserved. - https://www.jcraft.com/jsch/ - - (BSD 3-Clause) JLine Bundle - The following NOTICE information applies: - Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved. - https://github.com/jline/jline1 - - (BSD 3-Clause) ThreeTen-Extra - The following NOTICE information applies: - Copyright (c) 2007-2022, Stephen Colebourne & Michael Nascimento Santos. - https://github.com/ThreeTen/threeten-extra/ - -************************ -Go License -************************ - -The following binary components are provided under the Go License. See project link for details. - - (Go) RE2/J - The following NOTICE information applies: - Copyright (c) 2009 The Go Authors. All rights reserved. - https://github.com/google/re2j \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/pom.xml deleted file mode 100644 index f4b7fc9484..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/pom.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - nifi-iceberg-bundle - org.apache.nifi - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-iceberg-services-api - jar - - - - - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogProperty.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogProperty.java deleted file mode 100644 index 0874f731ad..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogProperty.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.nifi.services.iceberg; - -public enum IcebergCatalogProperty { - - CATALOG_NAME, - METASTORE_URI("hive.metastore.uris"), - WAREHOUSE_LOCATION("hive.metastore.warehouse.dir"), - CLIENT_POOL_SERVICE; - - private static final String EMPTY_STRING = ""; - - private final String hadoopPropertyName; - - IcebergCatalogProperty() { - this.hadoopPropertyName = EMPTY_STRING; - } - - IcebergCatalogProperty(String hadoopPropertyName) { - this.hadoopPropertyName = hadoopPropertyName; - } - - public String getHadoopPropertyName() { - return hadoopPropertyName; - } - -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogService.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogService.java deleted file mode 100644 index 065d5290ef..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogService.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.nifi.services.iceberg; - -import org.apache.nifi.controller.ControllerService; - -import java.util.List; -import java.util.Map; - -/** - * Provides a basic connector to Iceberg catalog services. - */ -public interface IcebergCatalogService extends ControllerService { - - IcebergCatalogType getCatalogType(); - - Map getCatalogProperties(); - - List getConfigFilePaths(); -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogType.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogType.java deleted file mode 100644 index 8aad41049e..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-api/src/main/java/org/apache/nifi/services/iceberg/IcebergCatalogType.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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.nifi.services.iceberg; - -public enum IcebergCatalogType { - HIVE, - HADOOP, - JDBC -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/pom.xml deleted file mode 100644 index 1edbf0d3c8..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - nifi-iceberg-bundle - org.apache.nifi - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-iceberg-services-nar - nar - - - - org.apache.nifi - nifi-iceberg-services - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-iceberg-services-api-nar - 2.0.0-SNAPSHOT - nar - - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/src/main/resources/META-INF/LICENSE b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/src/main/resources/META-INF/LICENSE deleted file mode 100644 index 6effaa89d3..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/src/main/resources/META-INF/LICENSE +++ /dev/null @@ -1,209 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - -APACHE NIFI SUBCOMPONENTS: - -The Apache NiFi project contains subcomponents with separate copyright -notices and license terms. Your use of the source code for the these -subcomponents is subject to the terms and conditions of the following -licenses. \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/src/main/resources/META-INF/NOTICE b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/src/main/resources/META-INF/NOTICE deleted file mode 100644 index 9ca5225882..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services-nar/src/main/resources/META-INF/NOTICE +++ /dev/null @@ -1,17 +0,0 @@ -nifi-iceberg-services-nar -Copyright 2014-2024 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=========================================== -Apache Software License v2 -=========================================== - - (ASLv2) Apache Iceberg - The following NOTICE information applies: - Apache Iceberg - Copyright 2017-2022 The Apache Software Foundation - - This product includes software developed at - The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/pom.xml deleted file mode 100644 index dbc4a5419d..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - nifi-iceberg-bundle - org.apache.nifi - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-iceberg-services - jar - - - - org.apache.nifi - nifi-iceberg-services-api - 2.0.0-SNAPSHOT - provided - - - org.apache.nifi - nifi-dbcp-service-api - - - - org.apache.nifi - nifi-utils - - - org.apache.nifi - nifi-xml-processing - 2.0.0-SNAPSHOT - - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/AbstractCatalogService.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/AbstractCatalogService.java deleted file mode 100644 index d914348be9..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/AbstractCatalogService.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.nifi.services.iceberg; - -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.components.resource.ResourceCardinality; -import org.apache.nifi.components.resource.ResourceType; -import org.apache.nifi.controller.AbstractControllerService; -import org.apache.nifi.expression.ExpressionLanguageScope; -import org.apache.nifi.processor.exception.ProcessException; -import org.apache.nifi.processor.util.StandardValidators; -import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider; -import org.w3c.dom.Document; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Abstract class holding common properties and methods for Catalog Service implementations. - */ -public abstract class AbstractCatalogService extends AbstractControllerService implements IcebergCatalogService { - - protected Map catalogProperties = new HashMap<>(); - - protected List configFilePaths; - - public static final PropertyDescriptor HADOOP_CONFIGURATION_RESOURCES = new PropertyDescriptor.Builder() - .name("hadoop-config-resources") - .displayName("Hadoop Configuration Resources") - .description("A file, or comma separated list of files, which contain the Hadoop configuration (core-site.xml, etc.). Without this, default configuration will be used.") - .required(false) - .identifiesExternalResource(ResourceCardinality.MULTIPLE, ResourceType.FILE) - .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .build(); - - public static final PropertyDescriptor WAREHOUSE_PATH = new PropertyDescriptor.Builder() - .name("warehouse-path") - .displayName("Warehouse Path") - .description("Path to the location of the warehouse.") - .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .required(true) - .addValidator(StandardValidators.NON_BLANK_VALIDATOR) - .build(); - - protected List parseConfigFilePaths(String configFilePaths) { - List documentList = new ArrayList<>(); - for (final String configFile : createFilePathList(configFilePaths)) { - File file = new File(configFile.trim()); - try (final InputStream fis = new FileInputStream(file); - final InputStream in = new BufferedInputStream(fis)) { - final StandardDocumentProvider documentProvider = new StandardDocumentProvider(); - documentList.add(documentProvider.parse(in)); - } catch (IOException e) { - throw new ProcessException("Failed to load config files", e); - } - } - return documentList; - } - - protected List createFilePathList(String configFilePaths) { - List filePathList = new ArrayList<>(); - if (configFilePaths != null && !configFilePaths.trim().isEmpty()) { - for (final String configFile : configFilePaths.split(",")) { - filePathList.add(configFile.trim()); - } - } - return filePathList; - } - - @Override - public Map getCatalogProperties() { - return catalogProperties; - } - - @Override - public List getConfigFilePaths() { - return configFilePaths; - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/HadoopCatalogService.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/HadoopCatalogService.java deleted file mode 100644 index 42b364d23f..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/HadoopCatalogService.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.nifi.services.iceberg; - -import org.apache.nifi.annotation.documentation.CapabilityDescription; -import org.apache.nifi.annotation.documentation.Tags; -import org.apache.nifi.annotation.lifecycle.OnEnabled; -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.controller.ConfigurationContext; - -import java.util.List; - -import static org.apache.nifi.services.iceberg.IcebergCatalogProperty.WAREHOUSE_LOCATION; - -@Tags({"iceberg", "catalog", "service", "hadoop", "hdfs"}) -@CapabilityDescription("Catalog service that can use HDFS or similar file systems that support atomic rename.") -public class HadoopCatalogService extends AbstractCatalogService { - - private static final List PROPERTIES = List.of(WAREHOUSE_PATH, HADOOP_CONFIGURATION_RESOURCES); - - @Override - protected List getSupportedPropertyDescriptors() { - return PROPERTIES; - } - - @OnEnabled - public void onEnabled(final ConfigurationContext context) { - if (context.getProperty(HADOOP_CONFIGURATION_RESOURCES).isSet()) { - configFilePaths = createFilePathList(context.getProperty(HADOOP_CONFIGURATION_RESOURCES).evaluateAttributeExpressions().getValue()); - } - - catalogProperties.put(WAREHOUSE_LOCATION, context.getProperty(WAREHOUSE_PATH).evaluateAttributeExpressions().getValue()); - } - - @Override - public IcebergCatalogType getCatalogType() { - return IcebergCatalogType.HADOOP; - } - -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/HiveCatalogService.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/HiveCatalogService.java deleted file mode 100644 index c421c8c3b2..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/HiveCatalogService.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.nifi.services.iceberg; - -import org.apache.nifi.annotation.documentation.CapabilityDescription; -import org.apache.nifi.annotation.documentation.Tags; -import org.apache.nifi.annotation.lifecycle.OnEnabled; -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.components.ValidationContext; -import org.apache.nifi.components.ValidationResult; -import org.apache.nifi.controller.ConfigurationContext; -import org.apache.nifi.expression.ExpressionLanguageScope; -import org.apache.nifi.processor.util.StandardValidators; -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -@Tags({"iceberg", "catalog", "service", "metastore", "hive"}) -@CapabilityDescription("Catalog service that connects to a Hive metastore to keep track of Iceberg tables.") -public class HiveCatalogService extends AbstractCatalogService { - - public static final PropertyDescriptor METASTORE_URI = new PropertyDescriptor.Builder() - .name("hive-metastore-uri") - .displayName("Hive Metastore URI") - .description("The URI location(s) for the Hive metastore; note that this is not the location of the Hive Server. The default port for the Hive metastore is 9043.") - .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .addValidator(StandardValidators.URI_LIST_VALIDATOR) - .build(); - - public static final PropertyDescriptor WAREHOUSE_LOCATION = new PropertyDescriptor.Builder() - .name("warehouse-location") - .displayName("Default Warehouse Location") - .description("Location of default database for the warehouse. This field sets or overrides the 'hive.metastore.warehouse.dir' configuration property.") - .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .addValidator(StandardValidators.NON_BLANK_VALIDATOR) - .build(); - - private static final List PROPERTIES = List.of(METASTORE_URI, WAREHOUSE_LOCATION, HADOOP_CONFIGURATION_RESOURCES); - - @Override - protected List getSupportedPropertyDescriptors() { - return PROPERTIES; - } - - @Override - protected Collection customValidate(ValidationContext validationContext) { - - final List problems = new ArrayList<>(); - boolean configMetastoreUriPresent = false; - boolean configWarehouseLocationPresent = false; - - final String propertyMetastoreUri = validationContext.getProperty(METASTORE_URI).evaluateAttributeExpressions().getValue(); - final String propertyWarehouseLocation = validationContext.getProperty(WAREHOUSE_LOCATION).evaluateAttributeExpressions().getValue(); - - // Load the configurations for validation only if any config resource is provided and if either the metastore URI or the warehouse location property is missing - if (validationContext.getProperty(HADOOP_CONFIGURATION_RESOURCES).isSet() && (propertyMetastoreUri == null || propertyWarehouseLocation == null)) { - final String configFiles = validationContext.getProperty(HADOOP_CONFIGURATION_RESOURCES).evaluateAttributeExpressions().getValue(); - final List documents = parseConfigFilePaths(configFiles); - - for (Document document : documents) { - final NodeList nameNodeList = document.getElementsByTagName("name"); - - for (int i = 0; i < nameNodeList.getLength(); i++) { - final String nodeValue = nameNodeList.item(i).getFirstChild().getNodeValue(); - - if (nodeValue.equals(IcebergCatalogProperty.METASTORE_URI.getHadoopPropertyName())) { - configMetastoreUriPresent = true; - } - - if (nodeValue.equals(IcebergCatalogProperty.WAREHOUSE_LOCATION.getHadoopPropertyName())) { - configWarehouseLocationPresent = true; - } - - if (configMetastoreUriPresent && configWarehouseLocationPresent) { - break; - } - } - } - } - - if (!configMetastoreUriPresent && propertyMetastoreUri == null) { - problems.add(new ValidationResult.Builder() - .subject("Hive Metastore URI") - .valid(false) - .explanation("cannot find hive metastore uri, please provide it in the 'Hive Metastore URI' property" + - " or provide a configuration file which contains 'hive.metastore.uris' value.") - .build()); - } - - if (!configWarehouseLocationPresent && propertyWarehouseLocation == null) { - problems.add(new ValidationResult.Builder() - .subject("Default Warehouse Location") - .valid(false) - .explanation("cannot find default warehouse location, please provide it in the 'Default Warehouse Location' property" + - " or provide a configuration file which contains 'hive.metastore.warehouse.dir' value.") - .build()); - } - - return problems; - } - - @OnEnabled - public void onEnabled(final ConfigurationContext context) { - if (context.getProperty(METASTORE_URI).isSet()) { - catalogProperties.put(IcebergCatalogProperty.METASTORE_URI, context.getProperty(METASTORE_URI).evaluateAttributeExpressions().getValue()); - } - - if (context.getProperty(WAREHOUSE_LOCATION).isSet()) { - catalogProperties.put(IcebergCatalogProperty.WAREHOUSE_LOCATION, context.getProperty(WAREHOUSE_LOCATION).evaluateAttributeExpressions().getValue()); - } - - if (context.getProperty(HADOOP_CONFIGURATION_RESOURCES).isSet()) { - configFilePaths = createFilePathList(context.getProperty(HADOOP_CONFIGURATION_RESOURCES).evaluateAttributeExpressions().getValue()); - } - } - - @Override - public IcebergCatalogType getCatalogType() { - return IcebergCatalogType.HIVE; - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/JdbcCatalogService.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/JdbcCatalogService.java deleted file mode 100644 index 7f8be77e06..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/java/org/apache/nifi/services/iceberg/JdbcCatalogService.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.nifi.services.iceberg; - -import org.apache.nifi.annotation.documentation.CapabilityDescription; -import org.apache.nifi.annotation.documentation.Tags; -import org.apache.nifi.annotation.lifecycle.OnEnabled; -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.controller.ConfigurationContext; -import org.apache.nifi.dbcp.DBCPService; -import org.apache.nifi.expression.ExpressionLanguageScope; -import org.apache.nifi.processor.util.StandardValidators; - -import java.util.List; - -import static org.apache.nifi.services.iceberg.IcebergCatalogProperty.CLIENT_POOL_SERVICE; -import static org.apache.nifi.services.iceberg.IcebergCatalogProperty.WAREHOUSE_LOCATION; - -@Tags({"iceberg", "catalog", "service", "jdbc"}) -@CapabilityDescription("Catalog service using relational database to manage Iceberg tables through JDBC.") -public class JdbcCatalogService extends AbstractCatalogService { - - public static final PropertyDescriptor CATALOG_NAME = new PropertyDescriptor.Builder() - .name("Catalog Name") - .description("Name of the Iceberg catalog.") - .addValidator(StandardValidators.NON_BLANK_VALIDATOR) - .defaultValue("jdbc-catalog") - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .build(); - - public static final PropertyDescriptor CONNECTION_POOL = new PropertyDescriptor.Builder() - .name("Connection Pool") - .description("Specifies the JDBC Connection Pool to use in order to communicate with the Iceberg catalog.") - .identifiesControllerService(DBCPService.class) - .required(true) - .build(); - - private static final List PROPERTIES = List.of( - CATALOG_NAME, CONNECTION_POOL, WAREHOUSE_PATH, HADOOP_CONFIGURATION_RESOURCES); - - @Override - protected List getSupportedPropertyDescriptors() { - return PROPERTIES; - } - - @OnEnabled - public void onEnabled(final ConfigurationContext context) { - if (context.getProperty(HADOOP_CONFIGURATION_RESOURCES).isSet()) { - configFilePaths = createFilePathList(context.getProperty(HADOOP_CONFIGURATION_RESOURCES).evaluateAttributeExpressions().getValue()); - } - - catalogProperties.put(IcebergCatalogProperty.CATALOG_NAME, context.getProperty(CATALOG_NAME).evaluateAttributeExpressions().getValue()); - catalogProperties.put(CLIENT_POOL_SERVICE, context.getProperty(CONNECTION_POOL).asControllerService(DBCPService.class)); - catalogProperties.put(WAREHOUSE_LOCATION, context.getProperty(WAREHOUSE_PATH).evaluateAttributeExpressions().getValue()); - } - - @Override - public IcebergCatalogType getCatalogType() { - return IcebergCatalogType.JDBC; - } - -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService deleted file mode 100755 index 44a8e957cd..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-services/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService +++ /dev/null @@ -1,18 +0,0 @@ -# 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. - -org.apache.nifi.services.iceberg.HiveCatalogService -org.apache.nifi.services.iceberg.HadoopCatalogService -org.apache.nifi.services.iceberg.JdbcCatalogService \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/pom.xml deleted file mode 100644 index b3458a7a16..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/pom.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - nifi-iceberg-bundle - org.apache.nifi - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-iceberg-test-utils - jar - - - - org.apache.hive - hive-metastore - ${hive.version} - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - - - commons-logging - commons-logging - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-web - - - org.apache.logging.log4j - log4j-1.2-api - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.apache.orc - orc-core - - - org.apache.hbase - hbase-client - - - co.cask.tephra - tephra-api - - - co.cask.tephra - tephra-core - - - co.cask.tephra - tephra-hbase-compat-1.0 - - - org.apache.parquet - parquet-hadoop-bundle - - - com.tdunning - json - - - com.zaxxer - HikariCP - - - com.google.guava - guava - - - org.apache.groovy - groovy-all - - - org.apache.ivy - ivy - - - org.apache.hadoop - hadoop-yarn-server-resourcemanager - - - org.eclipse.jetty - jetty-server - - - org.eclipse.jetty - jetty-servlet - - - org.eclipse.jetty - jetty-webapp - - - org.eclipse.jetty - jetty-util - - - org.eclipse.jetty - jetty-http - - - org.eclipse.jetty - jetty-rewrite - - - org.apache.hive - hive-shims - - - com.jolbox - bonecp - - - commons-cli - commons-cli - - - com.google.protobuf - protobuf-java - - - - - org.apache.hadoop - hadoop-common - - - - org.apache.derby - derbytools - ${derby.version} - - - org.apache.derby - derby - ${derby.version} - - - org.junit.jupiter - junit-jupiter-api - compile - - - - \ No newline at end of file diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/MetastoreCore.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/MetastoreCore.java deleted file mode 100644 index 3d2908b3d1..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/MetastoreCore.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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.nifi.hive.metastore; - -import org.apache.commons.io.FileUtils; -import org.apache.derby.jdbc.EmbeddedDriver; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hive.conf.HiveConf; -import org.apache.hadoop.hive.metastore.HiveMetaStore; -import org.apache.hadoop.hive.metastore.HiveMetaStoreClient; -import org.apache.hadoop.hive.metastore.IHMSHandler; -import org.apache.hadoop.hive.metastore.RetryingHMSHandler; -import org.apache.hadoop.hive.metastore.TServerSocketKeepAlive; -import org.apache.hadoop.hive.metastore.TSetIpAddressProcessor; -import org.apache.hadoop.hive.metastore.api.Database; -import org.apache.hadoop.hive.metastore.api.MetaException; -import org.apache.thrift.TException; -import org.apache.thrift.protocol.TBinaryProtocol; -import org.apache.thrift.server.TServer; -import org.apache.thrift.server.TThreadPoolServer; -import org.apache.thrift.transport.TServerSocket; -import org.apache.thrift.transport.TTransportException; -import org.apache.thrift.transport.TTransportFactory; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.lang.reflect.InvocationTargetException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import static java.nio.file.Files.createTempDirectory; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.AUTO_CREATE_ALL; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.COMPACTOR_INITIATOR_ON; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.COMPACTOR_WORKER_THREADS; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.CONNECTION_DRIVER; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.CONNECTION_POOLING_TYPE; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.CONNECT_URL_KEY; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.HIVE_SUPPORT_CONCURRENCY; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.HIVE_TXN_MANAGER; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.HMS_HANDLER_FORCE_RELOAD_CONF; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.SCHEMA_VERIFICATION; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.THRIFT_URIS; -import static org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars.WAREHOUSE; - -/** - * This class wraps Metastore service core functionalities. - */ -class MetastoreCore { - - private final String DATABASE_NAME = "iceberg_test"; - - private String thriftConnectionUri; - private Configuration hiveConf; - private HiveMetaStoreClient metaStoreClient; - private File tempDir; - private ExecutorService thriftServer; - private TServer server; - - public void initialize(Map configOverrides) throws IOException, TException, InvocationTargetException, NoSuchMethodException, - IllegalAccessException, NoSuchFieldException, SQLException { - thriftServer = Executors.newSingleThreadExecutor(); - tempDir = createTempDirectory("metastore").toFile(); - setDerbyLogPath(); - setupDB("jdbc:derby:" + getDerbyPath() + ";create=true"); - - server = thriftServer(configOverrides); - thriftServer.submit(() -> server.serve()); - - metaStoreClient = new HiveMetaStoreClient(hiveConf); - metaStoreClient.createDatabase(new Database(DATABASE_NAME, "description", getDBPath(), new HashMap<>())); - } - - public void shutdown() { - metaStoreClient.close(); - - if (server != null) { - server.stop(); - } - - thriftServer.shutdown(); - - FileUtils.deleteQuietly(tempDir); - } - - private HiveConf hiveConf(int port, Map configOverrides) throws IOException { - thriftConnectionUri = "thrift://localhost:" + port; - - final HiveConf hiveConf = new HiveConf(new Configuration(), this.getClass()); - hiveConf.set(THRIFT_URIS.getVarname(), thriftConnectionUri); - hiveConf.set(WAREHOUSE.getVarname(), "file:" + tempDir.getAbsolutePath()); - hiveConf.set(WAREHOUSE.getHiveName(), "file:" + tempDir.getAbsolutePath()); - hiveConf.set(CONNECTION_DRIVER.getVarname(), EmbeddedDriver.class.getName()); - hiveConf.set(CONNECT_URL_KEY.getVarname(), "jdbc:derby:" + getDerbyPath() + ";create=true"); - hiveConf.set(AUTO_CREATE_ALL.getVarname(), "false"); - hiveConf.set(SCHEMA_VERIFICATION.getVarname(), "false"); - hiveConf.set(HIVE_TXN_MANAGER.getVarname(), "org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager"); - hiveConf.set(COMPACTOR_INITIATOR_ON.getVarname(), "true"); - hiveConf.set(COMPACTOR_WORKER_THREADS.getVarname(), "1"); - hiveConf.set(HIVE_SUPPORT_CONCURRENCY.getVarname(), "true"); - hiveConf.setBoolean("hcatalog.hive.client.cache.disabled", true); - - hiveConf.set(CONNECTION_POOLING_TYPE.getVarname(), "NONE"); - hiveConf.set(HMS_HANDLER_FORCE_RELOAD_CONF.getVarname(), "true"); - - configOverrides.forEach(hiveConf::set); - - writeHiveConfFile(hiveConf); - return hiveConf; - } - - private void setDerbyLogPath() throws IOException { - final String derbyLog = Files.createTempFile(tempDir.toPath(), "derby", ".log").toString(); - System.setProperty("derby.stream.error.file", derbyLog); - } - - private String getDerbyPath() { - return new File(tempDir, "metastore_db").getPath(); - } - - private TServer thriftServer(Map configOverrides) throws TTransportException, MetaException, InvocationTargetException, - NoSuchMethodException, IllegalAccessException, NoSuchFieldException, IOException { - final TServerSocketKeepAlive socket = new TServerSocketKeepAlive(new TServerSocket(0)); - hiveConf = hiveConf(socket.getServerSocket().getLocalPort(), configOverrides); - final HiveMetaStore.HMSHandler baseHandler = new HiveMetaStore.HMSHandler("new db based metaserver", hiveConf); - final IHMSHandler handler = RetryingHMSHandler.getProxy(hiveConf, baseHandler, true); - final TTransportFactory transportFactory = new TTransportFactory(); - final TSetIpAddressProcessor processor = new TSetIpAddressProcessor<>(handler); - - TThreadPoolServer.Args args = new TThreadPoolServer.Args(socket) - .processor(processor) - .transportFactory(transportFactory) - .protocolFactory(new TBinaryProtocol.Factory()) - .minWorkerThreads(3) - .maxWorkerThreads(5); - - return new TThreadPoolServer(args); - } - - private void setupDB(String dbURL) throws SQLException, IOException { - final Connection connection = DriverManager.getConnection(dbURL); - final ScriptRunner scriptRunner = new ScriptRunner(connection); - - final InputStream inputStream = getClass().getClassLoader().getResourceAsStream("hive-schema-4.0.0-alpha-2.derby.sql"); - final Reader reader = new BufferedReader(new InputStreamReader(inputStream)); - scriptRunner.runScript(reader); - } - - private String getDBPath() { - return Paths.get(tempDir.getAbsolutePath(), DATABASE_NAME + ".db").toAbsolutePath().toString(); - } - - private void writeHiveConfFile(HiveConf hiveConf) throws IOException { - File file = new File(tempDir.toPath() + "/hive-site.xml"); - hiveConf.writeXml(Files.newOutputStream(file.toPath())); - } - - public String getThriftConnectionUri() { - return thriftConnectionUri; - } - - public String getWarehouseLocation() { - return tempDir.getAbsolutePath(); - } - - public HiveMetaStoreClient getMetaStoreClient() { - return metaStoreClient; - } - - public Configuration getConfiguration() { - return hiveConf; - } - - public String getConfigurationLocation() { - return tempDir.toPath() + "/hive-site.xml"; - } - -} - diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/ScriptRunner.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/ScriptRunner.java deleted file mode 100644 index d3666fdbe4..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/ScriptRunner.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.nifi.hive.metastore; - -import java.io.IOException; -import java.io.LineNumberReader; -import java.io.Reader; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; - -/** This class is responsible for metastore init script processing and execution. */ -public class ScriptRunner { - - private static final String DEFAULT_DELIMITER = ";"; - - private final Connection connection; - - public ScriptRunner(Connection connection) throws SQLException { - this.connection = connection; - if (!this.connection.getAutoCommit()) { - // May throw SQLFeatureNotSupportedException which is a subclass of SQLException - this.connection.setAutoCommit(true); - } - } - - public void runScript(Reader reader) throws IOException, SQLException { - try { - StringBuilder command = new StringBuilder(); - LineNumberReader lineReader = new LineNumberReader(reader); - String line; - while ((line = lineReader.readLine()) != null) { - String trimmedLine = line.trim(); - if (trimmedLine.isEmpty() || trimmedLine.startsWith("--") || trimmedLine.startsWith("//")) { - continue; //Skip comment line - } else if (trimmedLine.endsWith(getDelimiter())) { - command.append(line, 0, line.lastIndexOf(getDelimiter())); - command.append(" "); - Statement statement = connection.createStatement(); - - statement.execute(command.toString()); - connection.commit(); - - command = new StringBuilder(); - - statement.close(); - } else { - command.append(line); - command.append(" "); - } - } - } catch (IOException | SQLException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException("Error running metastore init script.", e); - } finally { - connection.rollback(); - } - } - - private String getDelimiter() { - return DEFAULT_DELIMITER; - } -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/ThriftMetastore.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/ThriftMetastore.java deleted file mode 100644 index 2b3dc4da5c..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/java/org/apache/nifi/hive/metastore/ThriftMetastore.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.nifi.hive.metastore; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hive.metastore.HiveMetaStoreClient; -import org.junit.jupiter.api.extension.AfterAllCallback; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.ExtensionContext; - -import java.util.HashMap; -import java.util.Map; - -/** A JUnit Extension that creates a Hive Metastore Thrift service backed by a Hive Metastore using an in-memory Derby database. */ -public class ThriftMetastore implements BeforeAllCallback, AfterAllCallback { - - private final MetastoreCore metastoreCore; - - private Map configOverrides = new HashMap<>(); - - public ThriftMetastore() { - metastoreCore = new MetastoreCore(); - } - - public ThriftMetastore withConfigOverrides(Map configs) { - configOverrides = configs; - return this; - } - - @Override - public void beforeAll(ExtensionContext context) throws Exception { - metastoreCore.initialize(configOverrides); - } - - @Override - public void afterAll(ExtensionContext context) { - metastoreCore.shutdown(); - } - - public String getThriftConnectionUri() { - return metastoreCore.getThriftConnectionUri(); - } - - public String getWarehouseLocation() { - return metastoreCore.getWarehouseLocation(); - } - - public HiveMetaStoreClient getMetaStoreClient() { - return metastoreCore.getMetaStoreClient(); - } - - public Configuration getConfiguration() { - return metastoreCore.getConfiguration(); - } - - public String getConfigurationLocation() { - return metastoreCore.getConfigurationLocation(); - } - -} diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/resources/hive-schema-4.0.0-alpha-2.derby.sql b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/resources/hive-schema-4.0.0-alpha-2.derby.sql deleted file mode 100644 index c1cc235a6f..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-test-utils/src/main/resources/hive-schema-4.0.0-alpha-2.derby.sql +++ /dev/null @@ -1,791 +0,0 @@ --- 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. - --- Timestamp: 2011-09-22 15:32:02.024 --- Source database is: /home/carl/Work/repos/hive1/metastore/scripts/upgrade/derby/mdb --- Connection URL is: jdbc:derby:/home/carl/Work/repos/hive1/metastore/scripts/upgrade/derby/mdb --- Specified schema is: APP --- appendLogs: false - --- ---------------------------------------------- --- DDL Statements for functions --- ---------------------------------------------- - -CREATE FUNCTION "APP"."NUCLEUS_ASCII" (C CHAR(1)) RETURNS INTEGER LANGUAGE JAVA PARAMETER STYLE JAVA READS SQL DATA CALLED ON NULL INPUT EXTERNAL NAME 'org.datanucleus.store.rdbms.adapter.DerbySQLFunction.ascii' ; - -CREATE FUNCTION "APP"."NUCLEUS_MATCHES" (TEXT VARCHAR(8000),PATTERN VARCHAR(8000)) RETURNS INTEGER LANGUAGE JAVA PARAMETER STYLE JAVA READS SQL DATA CALLED ON NULL INPUT EXTERNAL NAME 'org.datanucleus.store.rdbms.adapter.DerbySQLFunction.matches' ; - --- ---------------------------------------------- --- DDL Statements for tables --- ---------------------------------------------- -CREATE TABLE "APP"."DBS" ( - "DB_ID" BIGINT NOT NULL, - "DESC" VARCHAR(4000), - "DB_LOCATION_URI" VARCHAR(4000) NOT NULL, - "NAME" VARCHAR(128), - "OWNER_NAME" VARCHAR(128), - "OWNER_TYPE" VARCHAR(10), - "CTLG_NAME" VARCHAR(256) NOT NULL DEFAULT 'hive', - "CREATE_TIME" INTEGER, - "DB_MANAGED_LOCATION_URI" VARCHAR(4000), - "TYPE" VARCHAR(32) DEFAULT 'NATIVE' NOT NULL, - "DATACONNECTOR_NAME" VARCHAR(128), - "REMOTE_DBNAME" VARCHAR(128) -); - -CREATE TABLE "APP"."TBL_PRIVS" ("TBL_GRANT_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "TBL_PRIV" VARCHAR(128), "TBL_ID" BIGINT, "AUTHORIZER" VARCHAR(128)); - -CREATE TABLE "APP"."DATABASE_PARAMS" ("DB_ID" BIGINT NOT NULL, "PARAM_KEY" VARCHAR(180) NOT NULL, "PARAM_VALUE" VARCHAR(4000)); - -CREATE TABLE "APP"."TBL_COL_PRIVS" ("TBL_COLUMN_GRANT_ID" BIGINT NOT NULL, "COLUMN_NAME" VARCHAR(767), "CREATE_TIME" INTEGER NOT NULL, "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "TBL_COL_PRIV" VARCHAR(128), "TBL_ID" BIGINT, "AUTHORIZER" VARCHAR(128)); - -CREATE TABLE "APP"."SERDE_PARAMS" ("SERDE_ID" BIGINT NOT NULL, "PARAM_KEY" VARCHAR(256) NOT NULL, "PARAM_VALUE" CLOB); - -CREATE TABLE "APP"."COLUMNS_V2" ("CD_ID" BIGINT NOT NULL, "COMMENT" VARCHAR(4000), "COLUMN_NAME" VARCHAR(767) NOT NULL, "TYPE_NAME" CLOB, "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."SORT_COLS" ("SD_ID" BIGINT NOT NULL, "COLUMN_NAME" VARCHAR(767), "ORDER" INTEGER NOT NULL, "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."CDS" ("CD_ID" BIGINT NOT NULL); - -CREATE TABLE "APP"."PARTITION_KEY_VALS" ("PART_ID" BIGINT NOT NULL, "PART_KEY_VAL" VARCHAR(256), "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."DB_PRIVS" ("DB_GRANT_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "DB_ID" BIGINT, "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "DB_PRIV" VARCHAR(128), "AUTHORIZER" VARCHAR(128)); - -CREATE TABLE "APP"."DC_PRIVS" ("DC_GRANT_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "NAME" VARCHAR(128), "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "DC_PRIV" VARCHAR(128), "AUTHORIZER" VARCHAR(128)); - -CREATE TABLE "APP"."IDXS" ("INDEX_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "DEFERRED_REBUILD" CHAR(1) NOT NULL, "INDEX_HANDLER_CLASS" VARCHAR(4000), "INDEX_NAME" VARCHAR(128), "INDEX_TBL_ID" BIGINT, "LAST_ACCESS_TIME" INTEGER NOT NULL, "ORIG_TBL_ID" BIGINT, "SD_ID" BIGINT); - -CREATE TABLE "APP"."INDEX_PARAMS" ("INDEX_ID" BIGINT NOT NULL, "PARAM_KEY" VARCHAR(256) NOT NULL, "PARAM_VALUE" VARCHAR(4000)); - -CREATE TABLE "APP"."PARTITIONS" ("PART_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "LAST_ACCESS_TIME" INTEGER NOT NULL, "PART_NAME" VARCHAR(767), "SD_ID" BIGINT, "TBL_ID" BIGINT, "WRITE_ID" BIGINT DEFAULT 0); - -CREATE TABLE "APP"."SERDES" ("SERDE_ID" BIGINT NOT NULL, "NAME" VARCHAR(128), "SLIB" VARCHAR(4000), "DESCRIPTION" VARCHAR(4000), "SERIALIZER_CLASS" VARCHAR(4000), "DESERIALIZER_CLASS" VARCHAR(4000), SERDE_TYPE INTEGER); - -CREATE TABLE "APP"."PART_PRIVS" ("PART_GRANT_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PART_ID" BIGINT, "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "PART_PRIV" VARCHAR(128), "AUTHORIZER" VARCHAR(128)); - -CREATE TABLE "APP"."ROLE_MAP" ("ROLE_GRANT_ID" BIGINT NOT NULL, "ADD_TIME" INTEGER NOT NULL, "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "ROLE_ID" BIGINT); - -CREATE TABLE "APP"."TYPES" ("TYPES_ID" BIGINT NOT NULL, "TYPE_NAME" VARCHAR(128), "TYPE1" VARCHAR(767), "TYPE2" VARCHAR(767)); - -CREATE TABLE "APP"."GLOBAL_PRIVS" ("USER_GRANT_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "USER_PRIV" VARCHAR(128), "AUTHORIZER" VARCHAR(128)); - -CREATE TABLE "APP"."PARTITION_PARAMS" ("PART_ID" BIGINT NOT NULL, "PARAM_KEY" VARCHAR(256) NOT NULL, "PARAM_VALUE" CLOB); - -CREATE TABLE "APP"."PARTITION_EVENTS" ( - "PART_NAME_ID" BIGINT NOT NULL, - "CAT_NAME" VARCHAR(256), - "DB_NAME" VARCHAR(128), - "EVENT_TIME" BIGINT NOT NULL, - "EVENT_TYPE" INTEGER NOT NULL, - "PARTITION_NAME" VARCHAR(767), - "TBL_NAME" VARCHAR(256) -); - -CREATE TABLE "APP"."COLUMNS" ("SD_ID" BIGINT NOT NULL, "COMMENT" VARCHAR(256), "COLUMN_NAME" VARCHAR(128) NOT NULL, "TYPE_NAME" VARCHAR(4000) NOT NULL, "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."ROLES" ("ROLE_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "OWNER_NAME" VARCHAR(128), "ROLE_NAME" VARCHAR(128)); - -CREATE TABLE "APP"."TBLS" ("TBL_ID" BIGINT NOT NULL, "CREATE_TIME" INTEGER NOT NULL, "DB_ID" BIGINT, "LAST_ACCESS_TIME" INTEGER NOT NULL, "OWNER" VARCHAR(767), "OWNER_TYPE" VARCHAR(10), "RETENTION" INTEGER NOT NULL, "SD_ID" BIGINT, "TBL_NAME" VARCHAR(256), "TBL_TYPE" VARCHAR(128), "VIEW_EXPANDED_TEXT" LONG VARCHAR, "VIEW_ORIGINAL_TEXT" LONG VARCHAR, "IS_REWRITE_ENABLED" CHAR(1) NOT NULL DEFAULT 'N', "WRITE_ID" BIGINT DEFAULT 0); - -CREATE TABLE "APP"."PARTITION_KEYS" ("TBL_ID" BIGINT NOT NULL, "PKEY_COMMENT" VARCHAR(4000), "PKEY_NAME" VARCHAR(128) NOT NULL, "PKEY_TYPE" VARCHAR(767) NOT NULL, "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."PART_COL_PRIVS" ("PART_COLUMN_GRANT_ID" BIGINT NOT NULL, "COLUMN_NAME" VARCHAR(767), "CREATE_TIME" INTEGER NOT NULL, "GRANT_OPTION" SMALLINT NOT NULL, "GRANTOR" VARCHAR(128), "GRANTOR_TYPE" VARCHAR(128), "PART_ID" BIGINT, "PRINCIPAL_NAME" VARCHAR(128), "PRINCIPAL_TYPE" VARCHAR(128), "PART_COL_PRIV" VARCHAR(128), "AUTHORIZER" VARCHAR(128)); - -CREATE TABLE "APP"."SDS" ("SD_ID" BIGINT NOT NULL, "INPUT_FORMAT" VARCHAR(4000), "IS_COMPRESSED" CHAR(1) NOT NULL, "LOCATION" VARCHAR(4000), "NUM_BUCKETS" INTEGER NOT NULL, "OUTPUT_FORMAT" VARCHAR(4000), "SERDE_ID" BIGINT, "CD_ID" BIGINT, "IS_STOREDASSUBDIRECTORIES" CHAR(1) NOT NULL); - -CREATE TABLE "APP"."SEQUENCE_TABLE" ("SEQUENCE_NAME" VARCHAR(256) NOT NULL, "NEXT_VAL" BIGINT NOT NULL); - -CREATE TABLE "APP"."TAB_COL_STATS"( - "CAT_NAME" VARCHAR(256) NOT NULL, - "DB_NAME" VARCHAR(128) NOT NULL, - "TABLE_NAME" VARCHAR(256) NOT NULL, - "COLUMN_NAME" VARCHAR(767) NOT NULL, - "COLUMN_TYPE" VARCHAR(128) NOT NULL, - "LONG_LOW_VALUE" BIGINT, - "LONG_HIGH_VALUE" BIGINT, - "DOUBLE_LOW_VALUE" DOUBLE, - "DOUBLE_HIGH_VALUE" DOUBLE, - "BIG_DECIMAL_LOW_VALUE" VARCHAR(4000), - "BIG_DECIMAL_HIGH_VALUE" VARCHAR(4000), - "NUM_DISTINCTS" BIGINT, - "NUM_NULLS" BIGINT NOT NULL, - "AVG_COL_LEN" DOUBLE, - "MAX_COL_LEN" BIGINT, - "NUM_TRUES" BIGINT, - "NUM_FALSES" BIGINT, - "LAST_ANALYZED" BIGINT, - "CS_ID" BIGINT NOT NULL, - "TBL_ID" BIGINT NOT NULL, - "BIT_VECTOR" BLOB, - "ENGINE" VARCHAR(128) NOT NULL -); - -CREATE TABLE "APP"."TABLE_PARAMS" ("TBL_ID" BIGINT NOT NULL, "PARAM_KEY" VARCHAR(256) NOT NULL, "PARAM_VALUE" CLOB); - -CREATE TABLE "APP"."BUCKETING_COLS" ("SD_ID" BIGINT NOT NULL, "BUCKET_COL_NAME" VARCHAR(256), "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."TYPE_FIELDS" ("TYPE_NAME" BIGINT NOT NULL, "COMMENT" VARCHAR(256), "FIELD_NAME" VARCHAR(128) NOT NULL, "FIELD_TYPE" VARCHAR(767) NOT NULL, "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."NUCLEUS_TABLES" ("CLASS_NAME" VARCHAR(128) NOT NULL, "TABLE_NAME" VARCHAR(128) NOT NULL, "TYPE" VARCHAR(4) NOT NULL, "OWNER" VARCHAR(2) NOT NULL, "VERSION" VARCHAR(20) NOT NULL, "INTERFACE_NAME" VARCHAR(256) DEFAULT NULL); - -CREATE TABLE "APP"."SD_PARAMS" ("SD_ID" BIGINT NOT NULL, "PARAM_KEY" VARCHAR(256) NOT NULL, "PARAM_VALUE" CLOB); - -CREATE TABLE "APP"."SKEWED_STRING_LIST" ("STRING_LIST_ID" BIGINT NOT NULL); - -CREATE TABLE "APP"."SKEWED_STRING_LIST_VALUES" ("STRING_LIST_ID" BIGINT NOT NULL, "STRING_LIST_VALUE" VARCHAR(256), "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."SKEWED_COL_NAMES" ("SD_ID" BIGINT NOT NULL, "SKEWED_COL_NAME" VARCHAR(256), "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."SKEWED_COL_VALUE_LOC_MAP" ("SD_ID" BIGINT NOT NULL, "STRING_LIST_ID_KID" BIGINT NOT NULL, "LOCATION" VARCHAR(4000)); - -CREATE TABLE "APP"."SKEWED_VALUES" ("SD_ID_OID" BIGINT NOT NULL, "STRING_LIST_ID_EID" BIGINT NOT NULL, "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."MASTER_KEYS" ("KEY_ID" INTEGER NOT NULL generated always as identity (start with 1), "MASTER_KEY" VARCHAR(767)); - -CREATE TABLE "APP"."DELEGATION_TOKENS" ( "TOKEN_IDENT" VARCHAR(767) NOT NULL, "TOKEN" VARCHAR(767)); - -CREATE TABLE "APP"."PART_COL_STATS"( - "CAT_NAME" VARCHAR(256) NOT NULL, - "DB_NAME" VARCHAR(128) NOT NULL, - "TABLE_NAME" VARCHAR(256) NOT NULL, - "PARTITION_NAME" VARCHAR(767) NOT NULL, - "COLUMN_NAME" VARCHAR(767) NOT NULL, - "COLUMN_TYPE" VARCHAR(128) NOT NULL, - "LONG_LOW_VALUE" BIGINT, - "LONG_HIGH_VALUE" BIGINT, - "DOUBLE_LOW_VALUE" DOUBLE, - "DOUBLE_HIGH_VALUE" DOUBLE, - "BIG_DECIMAL_LOW_VALUE" VARCHAR(4000), - "BIG_DECIMAL_HIGH_VALUE" VARCHAR(4000), - "NUM_DISTINCTS" BIGINT, - "BIT_VECTOR" BLOB, - "NUM_NULLS" BIGINT NOT NULL, - "AVG_COL_LEN" DOUBLE, - "MAX_COL_LEN" BIGINT, - "NUM_TRUES" BIGINT, - "NUM_FALSES" BIGINT, - "LAST_ANALYZED" BIGINT, - "CS_ID" BIGINT NOT NULL, - "PART_ID" BIGINT NOT NULL, - "ENGINE" VARCHAR(128) NOT NULL -); - -CREATE TABLE "APP"."VERSION" ("VER_ID" BIGINT NOT NULL, "SCHEMA_VERSION" VARCHAR(127) NOT NULL, "VERSION_COMMENT" VARCHAR(255)); - -CREATE TABLE "APP"."FUNCS" ("FUNC_ID" BIGINT NOT NULL, "CLASS_NAME" VARCHAR(4000), "CREATE_TIME" INTEGER NOT NULL, "DB_ID" BIGINT, "FUNC_NAME" VARCHAR(128), "FUNC_TYPE" INTEGER NOT NULL, "OWNER_NAME" VARCHAR(128), "OWNER_TYPE" VARCHAR(10)); - -CREATE TABLE "APP"."FUNC_RU" ("FUNC_ID" BIGINT NOT NULL, "RESOURCE_TYPE" INTEGER NOT NULL, "RESOURCE_URI" VARCHAR(4000), "INTEGER_IDX" INTEGER NOT NULL); - -CREATE TABLE "APP"."NOTIFICATION_LOG" ( - "NL_ID" BIGINT NOT NULL, - "CAT_NAME" VARCHAR(256), - "DB_NAME" VARCHAR(128), - "EVENT_ID" BIGINT NOT NULL, - "EVENT_TIME" INTEGER NOT NULL, - "EVENT_TYPE" VARCHAR(32) NOT NULL, - "MESSAGE" CLOB, - "TBL_NAME" VARCHAR(256), - "MESSAGE_FORMAT" VARCHAR(16) -); - -CREATE UNIQUE INDEX "APP"."NOTIFICATION_LOG_EVENT_ID" ON "APP"."NOTIFICATION_LOG" ("EVENT_ID"); - -CREATE TABLE "APP"."NOTIFICATION_SEQUENCE" ("NNI_ID" BIGINT NOT NULL, "NEXT_EVENT_ID" BIGINT NOT NULL); - -CREATE TABLE "APP"."KEY_CONSTRAINTS" ( - "CHILD_CD_ID" BIGINT, - "CHILD_INTEGER_IDX" INTEGER, - "CHILD_TBL_ID" BIGINT, - "PARENT_CD_ID" BIGINT, - "PARENT_INTEGER_IDX" INTEGER, - "PARENT_TBL_ID" BIGINT NOT NULL, - "POSITION" BIGINT NOT NULL, - "CONSTRAINT_NAME" VARCHAR(400) NOT NULL, - "CONSTRAINT_TYPE" SMALLINT NOT NULL, - "UPDATE_RULE" SMALLINT, - "DELETE_RULE" SMALLINT, - "ENABLE_VALIDATE_RELY" SMALLINT NOT NULL, - "DEFAULT_VALUE" VARCHAR(400) -); - -CREATE TABLE "APP"."METASTORE_DB_PROPERTIES" ("PROPERTY_KEY" VARCHAR(255) NOT NULL, "PROPERTY_VALUE" VARCHAR(1000) NOT NULL, "DESCRIPTION" VARCHAR(1000)); - -CREATE TABLE "APP"."WM_RESOURCEPLAN" (RP_ID BIGINT NOT NULL, NS VARCHAR(128), NAME VARCHAR(128) NOT NULL, QUERY_PARALLELISM INTEGER, STATUS VARCHAR(20) NOT NULL, DEFAULT_POOL_ID BIGINT); - -CREATE TABLE "APP"."WM_POOL" (POOL_ID BIGINT NOT NULL, RP_ID BIGINT NOT NULL, PATH VARCHAR(1024) NOT NULL, ALLOC_FRACTION DOUBLE, QUERY_PARALLELISM INTEGER, SCHEDULING_POLICY VARCHAR(1024)); - -CREATE TABLE "APP"."WM_TRIGGER" (TRIGGER_ID BIGINT NOT NULL, RP_ID BIGINT NOT NULL, NAME VARCHAR(128) NOT NULL, TRIGGER_EXPRESSION VARCHAR(1024), ACTION_EXPRESSION VARCHAR(1024), IS_IN_UNMANAGED INTEGER NOT NULL DEFAULT 0); - -CREATE TABLE "APP"."WM_POOL_TO_TRIGGER" (POOL_ID BIGINT NOT NULL, TRIGGER_ID BIGINT NOT NULL); - -CREATE TABLE "APP"."WM_MAPPING" (MAPPING_ID BIGINT NOT NULL, RP_ID BIGINT NOT NULL, ENTITY_TYPE VARCHAR(128) NOT NULL, ENTITY_NAME VARCHAR(128) NOT NULL, POOL_ID BIGINT, ORDERING INTEGER); - -CREATE TABLE "APP"."MV_CREATION_METADATA" ( - "MV_CREATION_METADATA_ID" BIGINT NOT NULL, - "CAT_NAME" VARCHAR(256) NOT NULL, - "DB_NAME" VARCHAR(128) NOT NULL, - "TBL_NAME" VARCHAR(256) NOT NULL, - "TXN_LIST" CLOB, - "MATERIALIZATION_TIME" BIGINT NOT NULL -); - -CREATE TABLE "APP"."MV_TABLES_USED" ( - "MV_CREATION_METADATA_ID" BIGINT NOT NULL, - "TBL_ID" BIGINT NOT NULL, - "INSERTED_COUNT" BIGINT NOT NULL DEFAULT 0, - "UPDATED_COUNT" BIGINT NOT NULL DEFAULT 0, - "DELETED_COUNT" BIGINT NOT NULL DEFAULT 0 -); - -CREATE TABLE "APP"."CTLGS" ( - "CTLG_ID" BIGINT NOT NULL, - "NAME" VARCHAR(256) UNIQUE, - "DESC" VARCHAR(4000), - "LOCATION_URI" VARCHAR(4000) NOT NULL, - "CREATE_TIME" INTEGER); - --- Insert a default value. The location is TBD. Hive will fix this when it starts -INSERT INTO "APP"."CTLGS" ("CTLG_ID", "NAME", "DESC", "LOCATION_URI", "CREATE_TIME") -VALUES (1, 'hive', 'Default catalog for Hive', 'TBD', NULL); - --- ---------------------------------------------- --- DML Statements --- ---------------------------------------------- - -INSERT INTO "APP"."NOTIFICATION_SEQUENCE" ("NNI_ID", "NEXT_EVENT_ID") SELECT * FROM (VALUES (1,1)) tmp_table WHERE NOT EXISTS ( SELECT "NEXT_EVENT_ID" FROM "APP"."NOTIFICATION_SEQUENCE"); - -INSERT INTO "APP"."SEQUENCE_TABLE" ("SEQUENCE_NAME", "NEXT_VAL") SELECT * FROM (VALUES ('org.apache.hadoop.hive.metastore.model.MNotificationLog', 1)) tmp_table WHERE NOT EXISTS ( SELECT "NEXT_VAL" FROM "APP"."SEQUENCE_TABLE" WHERE "SEQUENCE_NAME" = 'org.apache.hadoop.hive.metastore.model.MNotificationLog'); - --- ---------------------------------------------- --- DDL Statements for indexes --- ---------------------------------------------- - -CREATE UNIQUE INDEX "APP"."UNIQUEINDEX" ON "APP"."IDXS" ("INDEX_NAME", "ORIG_TBL_ID"); - -CREATE INDEX "APP"."TABLECOLUMNPRIVILEGEINDEX" ON "APP"."TBL_COL_PRIVS" ("AUTHORIZER", "TBL_ID", "COLUMN_NAME", "PRINCIPAL_NAME", "PRINCIPAL_TYPE", "TBL_COL_PRIV", "GRANTOR", "GRANTOR_TYPE"); - -CREATE UNIQUE INDEX "APP"."DBPRIVILEGEINDEX" ON "APP"."DB_PRIVS" ("AUTHORIZER", "DB_ID", "PRINCIPAL_NAME", "PRINCIPAL_TYPE", "DB_PRIV", "GRANTOR", "GRANTOR_TYPE"); - -CREATE UNIQUE INDEX "APP"."DCPRIVILEGEINDEX" ON "APP"."DC_PRIVS" ("AUTHORIZER", "NAME", "PRINCIPAL_NAME", "PRINCIPAL_TYPE", "DC_PRIV", "GRANTOR", "GRANTOR_TYPE"); - -CREATE INDEX "APP"."PCS_STATS_IDX" ON "APP"."PART_COL_STATS" ("CAT_NAME", "DB_NAME","TABLE_NAME","COLUMN_NAME","PARTITION_NAME"); - -CREATE INDEX "APP"."TAB_COL_STATS_IDX" ON "APP"."TAB_COL_STATS" ("CAT_NAME", "DB_NAME", "TABLE_NAME", "COLUMN_NAME"); - -CREATE INDEX "APP"."PARTPRIVILEGEINDEX" ON "APP"."PART_PRIVS" ("AUTHORIZER", "PART_ID", "PRINCIPAL_NAME", "PRINCIPAL_TYPE", "PART_PRIV", "GRANTOR", "GRANTOR_TYPE"); - -CREATE UNIQUE INDEX "APP"."ROLEENTITYINDEX" ON "APP"."ROLES" ("ROLE_NAME"); - -CREATE INDEX "APP"."TABLEPRIVILEGEINDEX" ON "APP"."TBL_PRIVS" ("AUTHORIZER", "TBL_ID", "PRINCIPAL_NAME", "PRINCIPAL_TYPE", "TBL_PRIV", "GRANTOR", "GRANTOR_TYPE"); - -CREATE UNIQUE INDEX "APP"."UNIQUETABLE" ON "APP"."TBLS" ("TBL_NAME", "DB_ID"); - -CREATE UNIQUE INDEX "APP"."UNIQUE_DATABASE" ON "APP"."DBS" ("NAME", "CTLG_NAME"); - -CREATE UNIQUE INDEX "APP"."USERROLEMAPINDEX" ON "APP"."ROLE_MAP" ("PRINCIPAL_NAME", "ROLE_ID", "GRANTOR", "GRANTOR_TYPE"); - -CREATE UNIQUE INDEX "APP"."GLOBALPRIVILEGEINDEX" ON "APP"."GLOBAL_PRIVS" ("AUTHORIZER", "PRINCIPAL_NAME", "PRINCIPAL_TYPE", "USER_PRIV", "GRANTOR", "GRANTOR_TYPE"); - -CREATE UNIQUE INDEX "APP"."UNIQUE_TYPE" ON "APP"."TYPES" ("TYPE_NAME"); - -CREATE INDEX "APP"."PARTITIONCOLUMNPRIVILEGEINDEX" ON "APP"."PART_COL_PRIVS" ("AUTHORIZER", "PART_ID", "COLUMN_NAME", "PRINCIPAL_NAME", "PRINCIPAL_TYPE", "PART_COL_PRIV", "GRANTOR", "GRANTOR_TYPE"); - -CREATE UNIQUE INDEX "APP"."UNIQUEPARTITION" ON "APP"."PARTITIONS" ("PART_NAME", "TBL_ID"); - -CREATE UNIQUE INDEX "APP"."UNIQUEFUNCTION" ON "APP"."FUNCS" ("FUNC_NAME", "DB_ID"); - -CREATE INDEX "APP"."FUNCS_N49" ON "APP"."FUNCS" ("DB_ID"); - -CREATE INDEX "APP"."FUNC_RU_N49" ON "APP"."FUNC_RU" ("FUNC_ID"); - -CREATE INDEX "APP"."CONSTRAINTS_PARENT_TBL_ID_INDEX" ON "APP"."KEY_CONSTRAINTS"("PARENT_TBL_ID"); - -CREATE INDEX "APP"."CONSTRAINTS_CONSTRAINT_TYPE_INDEX" ON "APP"."KEY_CONSTRAINTS"("CONSTRAINT_TYPE"); - -CREATE UNIQUE INDEX "APP"."UNIQUE_WM_RESOURCEPLAN" ON "APP"."WM_RESOURCEPLAN" ("NS", "NAME"); - -CREATE UNIQUE INDEX "APP"."UNIQUE_WM_POOL" ON "APP"."WM_POOL" ("RP_ID", "PATH"); - -CREATE UNIQUE INDEX "APP"."UNIQUE_WM_TRIGGER" ON "APP"."WM_TRIGGER" ("RP_ID", "NAME"); - -CREATE UNIQUE INDEX "APP"."UNIQUE_WM_MAPPING" ON "APP"."WM_MAPPING" ("RP_ID", "ENTITY_TYPE", "ENTITY_NAME"); - -CREATE UNIQUE INDEX "APP"."MV_UNIQUE_TABLE" ON "APP"."MV_CREATION_METADATA" ("TBL_NAME", "DB_NAME"); - -CREATE UNIQUE INDEX "APP"."UNIQUE_CATALOG" ON "APP"."CTLGS" ("NAME"); - - --- ---------------------------------------------- --- DDL Statements for keys --- ---------------------------------------------- - --- primary/unique -ALTER TABLE "APP"."IDXS" ADD CONSTRAINT "IDXS_PK" PRIMARY KEY ("INDEX_ID"); - -ALTER TABLE "APP"."TBL_COL_PRIVS" ADD CONSTRAINT "TBL_COL_PRIVS_PK" PRIMARY KEY ("TBL_COLUMN_GRANT_ID"); - -ALTER TABLE "APP"."CDS" ADD CONSTRAINT "SQL110922153006460" PRIMARY KEY ("CD_ID"); - -ALTER TABLE "APP"."DB_PRIVS" ADD CONSTRAINT "DB_PRIVS_PK" PRIMARY KEY ("DB_GRANT_ID"); - -ALTER TABLE "APP"."DC_PRIVS" ADD CONSTRAINT "DC_PRIVS_PK" PRIMARY KEY ("DC_GRANT_ID"); - -ALTER TABLE "APP"."INDEX_PARAMS" ADD CONSTRAINT "INDEX_PARAMS_PK" PRIMARY KEY ("INDEX_ID", "PARAM_KEY"); - -ALTER TABLE "APP"."PARTITION_KEYS" ADD CONSTRAINT "PARTITION_KEY_PK" PRIMARY KEY ("TBL_ID", "PKEY_NAME"); - -ALTER TABLE "APP"."SEQUENCE_TABLE" ADD CONSTRAINT "SEQUENCE_TABLE_PK" PRIMARY KEY ("SEQUENCE_NAME"); - -ALTER TABLE "APP"."PART_PRIVS" ADD CONSTRAINT "PART_PRIVS_PK" PRIMARY KEY ("PART_GRANT_ID"); - -ALTER TABLE "APP"."SDS" ADD CONSTRAINT "SDS_PK" PRIMARY KEY ("SD_ID"); - -ALTER TABLE "APP"."SERDES" ADD CONSTRAINT "SERDES_PK" PRIMARY KEY ("SERDE_ID"); - -ALTER TABLE "APP"."COLUMNS" ADD CONSTRAINT "COLUMNS_PK" PRIMARY KEY ("SD_ID", "COLUMN_NAME"); - -ALTER TABLE "APP"."PARTITION_EVENTS" ADD CONSTRAINT "PARTITION_EVENTS_PK" PRIMARY KEY ("PART_NAME_ID"); - -ALTER TABLE "APP"."TYPE_FIELDS" ADD CONSTRAINT "TYPE_FIELDS_PK" PRIMARY KEY ("TYPE_NAME", "FIELD_NAME"); - -ALTER TABLE "APP"."ROLES" ADD CONSTRAINT "ROLES_PK" PRIMARY KEY ("ROLE_ID"); - -ALTER TABLE "APP"."TBL_PRIVS" ADD CONSTRAINT "TBL_PRIVS_PK" PRIMARY KEY ("TBL_GRANT_ID"); - -ALTER TABLE "APP"."SERDE_PARAMS" ADD CONSTRAINT "SERDE_PARAMS_PK" PRIMARY KEY ("SERDE_ID", "PARAM_KEY"); - -ALTER TABLE "APP"."NUCLEUS_TABLES" ADD CONSTRAINT "NUCLEUS_TABLES_PK" PRIMARY KEY ("CLASS_NAME"); - -ALTER TABLE "APP"."TBLS" ADD CONSTRAINT "TBLS_PK" PRIMARY KEY ("TBL_ID"); - -ALTER TABLE "APP"."SD_PARAMS" ADD CONSTRAINT "SD_PARAMS_PK" PRIMARY KEY ("SD_ID", "PARAM_KEY"); - -ALTER TABLE "APP"."DATABASE_PARAMS" ADD CONSTRAINT "DATABASE_PARAMS_PK" PRIMARY KEY ("DB_ID", "PARAM_KEY"); - -ALTER TABLE "APP"."DBS" ADD CONSTRAINT "DBS_PK" PRIMARY KEY ("DB_ID"); - -ALTER TABLE "APP"."ROLE_MAP" ADD CONSTRAINT "ROLE_MAP_PK" PRIMARY KEY ("ROLE_GRANT_ID"); - -ALTER TABLE "APP"."GLOBAL_PRIVS" ADD CONSTRAINT "GLOBAL_PRIVS_PK" PRIMARY KEY ("USER_GRANT_ID"); - -ALTER TABLE "APP"."BUCKETING_COLS" ADD CONSTRAINT "BUCKETING_COLS_PK" PRIMARY KEY ("SD_ID", "INTEGER_IDX"); - -ALTER TABLE "APP"."SORT_COLS" ADD CONSTRAINT "SORT_COLS_PK" PRIMARY KEY ("SD_ID", "INTEGER_IDX"); - -ALTER TABLE "APP"."PARTITION_KEY_VALS" ADD CONSTRAINT "PARTITION_KEY_VALS_PK" PRIMARY KEY ("PART_ID", "INTEGER_IDX"); - -ALTER TABLE "APP"."TYPES" ADD CONSTRAINT "TYPES_PK" PRIMARY KEY ("TYPES_ID"); - -ALTER TABLE "APP"."COLUMNS_V2" ADD CONSTRAINT "SQL110922153006740" PRIMARY KEY ("CD_ID", "COLUMN_NAME"); - -ALTER TABLE "APP"."PART_COL_PRIVS" ADD CONSTRAINT "PART_COL_PRIVS_PK" PRIMARY KEY ("PART_COLUMN_GRANT_ID"); - -ALTER TABLE "APP"."PARTITION_PARAMS" ADD CONSTRAINT "PARTITION_PARAMS_PK" PRIMARY KEY ("PART_ID", "PARAM_KEY"); - -ALTER TABLE "APP"."PARTITIONS" ADD CONSTRAINT "PARTITIONS_PK" PRIMARY KEY ("PART_ID"); - -ALTER TABLE "APP"."TABLE_PARAMS" ADD CONSTRAINT "TABLE_PARAMS_PK" PRIMARY KEY ("TBL_ID", "PARAM_KEY"); - -ALTER TABLE "APP"."SKEWED_STRING_LIST" ADD CONSTRAINT "SKEWED_STRING_LIST_PK" PRIMARY KEY ("STRING_LIST_ID"); - -ALTER TABLE "APP"."SKEWED_STRING_LIST_VALUES" ADD CONSTRAINT "SKEWED_STRING_LIST_VALUES_PK" PRIMARY KEY ("STRING_LIST_ID", "INTEGER_IDX"); - -ALTER TABLE "APP"."SKEWED_COL_NAMES" ADD CONSTRAINT "SKEWED_COL_NAMES_PK" PRIMARY KEY ("SD_ID", "INTEGER_IDX"); - -ALTER TABLE "APP"."SKEWED_COL_VALUE_LOC_MAP" ADD CONSTRAINT "SKEWED_COL_VALUE_LOC_MAP_PK" PRIMARY KEY ("SD_ID", "STRING_LIST_ID_KID"); - -ALTER TABLE "APP"."SKEWED_VALUES" ADD CONSTRAINT "SKEWED_VALUES_PK" PRIMARY KEY ("SD_ID_OID", "INTEGER_IDX"); - -ALTER TABLE "APP"."TAB_COL_STATS" ADD CONSTRAINT "TAB_COL_STATS_PK" PRIMARY KEY ("CS_ID"); - -ALTER TABLE "APP"."PART_COL_STATS" ADD CONSTRAINT "PART_COL_STATS_PK" PRIMARY KEY ("CS_ID"); - -ALTER TABLE "APP"."FUNCS" ADD CONSTRAINT "FUNCS_PK" PRIMARY KEY ("FUNC_ID"); - -ALTER TABLE "APP"."FUNC_RU" ADD CONSTRAINT "FUNC_RU_PK" PRIMARY KEY ("FUNC_ID", "INTEGER_IDX"); - -ALTER TABLE "APP"."NOTIFICATION_LOG" ADD CONSTRAINT "NOTIFICATION_LOG_PK" PRIMARY KEY ("NL_ID"); - -ALTER TABLE "APP"."NOTIFICATION_SEQUENCE" ADD CONSTRAINT "NOTIFICATION_SEQUENCE_PK" PRIMARY KEY ("NNI_ID"); - -ALTER TABLE "APP"."NOTIFICATION_SEQUENCE" ADD CONSTRAINT "ONE_ROW_CONSTRAINT" CHECK (NNI_ID = 1); - -ALTER TABLE "APP"."KEY_CONSTRAINTS" ADD CONSTRAINT "CONSTRAINTS_PK" PRIMARY KEY ("PARENT_TBL_ID", "CONSTRAINT_NAME", "POSITION"); - -ALTER TABLE "APP"."METASTORE_DB_PROPERTIES" ADD CONSTRAINT "PROPERTY_KEY_PK" PRIMARY KEY ("PROPERTY_KEY"); - -ALTER TABLE "APP"."MV_CREATION_METADATA" ADD CONSTRAINT "MV_CREATION_METADATA_PK" PRIMARY KEY ("MV_CREATION_METADATA_ID"); - -ALTER TABLE "APP"."CTLGS" ADD CONSTRAINT "CTLG_PK" PRIMARY KEY ("CTLG_ID"); - - --- foreign -ALTER TABLE "APP"."IDXS" ADD CONSTRAINT "IDXS_FK1" FOREIGN KEY ("ORIG_TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."IDXS" ADD CONSTRAINT "IDXS_FK2" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."IDXS" ADD CONSTRAINT "IDXS_FK3" FOREIGN KEY ("INDEX_TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."TBL_COL_PRIVS" ADD CONSTRAINT "TBL_COL_PRIVS_FK1" FOREIGN KEY ("TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."DB_PRIVS" ADD CONSTRAINT "DB_PRIVS_FK1" FOREIGN KEY ("DB_ID") REFERENCES "APP"."DBS" ("DB_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."INDEX_PARAMS" ADD CONSTRAINT "INDEX_PARAMS_FK1" FOREIGN KEY ("INDEX_ID") REFERENCES "APP"."IDXS" ("INDEX_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PARTITION_KEYS" ADD CONSTRAINT "PARTITION_KEYS_FK1" FOREIGN KEY ("TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PART_PRIVS" ADD CONSTRAINT "PART_PRIVS_FK1" FOREIGN KEY ("PART_ID") REFERENCES "APP"."PARTITIONS" ("PART_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SDS" ADD CONSTRAINT "SDS_FK1" FOREIGN KEY ("SERDE_ID") REFERENCES "APP"."SERDES" ("SERDE_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SDS" ADD CONSTRAINT "SDS_FK2" FOREIGN KEY ("CD_ID") REFERENCES "APP"."CDS" ("CD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."COLUMNS" ADD CONSTRAINT "COLUMNS_FK1" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."TYPE_FIELDS" ADD CONSTRAINT "TYPE_FIELDS_FK1" FOREIGN KEY ("TYPE_NAME") REFERENCES "APP"."TYPES" ("TYPES_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."TBL_PRIVS" ADD CONSTRAINT "TBL_PRIVS_FK1" FOREIGN KEY ("TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SERDE_PARAMS" ADD CONSTRAINT "SERDE_PARAMS_FK1" FOREIGN KEY ("SERDE_ID") REFERENCES "APP"."SERDES" ("SERDE_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."TBLS" ADD CONSTRAINT "TBLS_FK2" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."TBLS" ADD CONSTRAINT "TBLS_FK1" FOREIGN KEY ("DB_ID") REFERENCES "APP"."DBS" ("DB_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."DBS" ADD CONSTRAINT "DBS_FK1" FOREIGN KEY ("CTLG_NAME") REFERENCES "APP"."CTLGS" ("NAME") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SD_PARAMS" ADD CONSTRAINT "SD_PARAMS_FK1" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."DATABASE_PARAMS" ADD CONSTRAINT "DATABASE_PARAMS_FK1" FOREIGN KEY ("DB_ID") REFERENCES "APP"."DBS" ("DB_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."ROLE_MAP" ADD CONSTRAINT "ROLE_MAP_FK1" FOREIGN KEY ("ROLE_ID") REFERENCES "APP"."ROLES" ("ROLE_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."BUCKETING_COLS" ADD CONSTRAINT "BUCKETING_COLS_FK1" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SORT_COLS" ADD CONSTRAINT "SORT_COLS_FK1" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PARTITION_KEY_VALS" ADD CONSTRAINT "PARTITION_KEY_VALS_FK1" FOREIGN KEY ("PART_ID") REFERENCES "APP"."PARTITIONS" ("PART_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."COLUMNS_V2" ADD CONSTRAINT "COLUMNS_V2_FK1" FOREIGN KEY ("CD_ID") REFERENCES "APP"."CDS" ("CD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PART_COL_PRIVS" ADD CONSTRAINT "PART_COL_PRIVS_FK1" FOREIGN KEY ("PART_ID") REFERENCES "APP"."PARTITIONS" ("PART_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PARTITION_PARAMS" ADD CONSTRAINT "PARTITION_PARAMS_FK1" FOREIGN KEY ("PART_ID") REFERENCES "APP"."PARTITIONS" ("PART_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PARTITIONS" ADD CONSTRAINT "PARTITIONS_FK1" FOREIGN KEY ("TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PARTITIONS" ADD CONSTRAINT "PARTITIONS_FK2" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."TABLE_PARAMS" ADD CONSTRAINT "TABLE_PARAMS_FK1" FOREIGN KEY ("TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SKEWED_STRING_LIST_VALUES" ADD CONSTRAINT "SKEWED_STRING_LIST_VALUES_FK1" FOREIGN KEY ("STRING_LIST_ID") REFERENCES "APP"."SKEWED_STRING_LIST" ("STRING_LIST_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SKEWED_COL_NAMES" ADD CONSTRAINT "SKEWED_COL_NAMES_FK1" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SKEWED_COL_VALUE_LOC_MAP" ADD CONSTRAINT "SKEWED_COL_VALUE_LOC_MAP_FK1" FOREIGN KEY ("SD_ID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SKEWED_COL_VALUE_LOC_MAP" ADD CONSTRAINT "SKEWED_COL_VALUE_LOC_MAP_FK2" FOREIGN KEY ("STRING_LIST_ID_KID") REFERENCES "APP"."SKEWED_STRING_LIST" ("STRING_LIST_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SKEWED_VALUES" ADD CONSTRAINT "SKEWED_VALUES_FK1" FOREIGN KEY ("SD_ID_OID") REFERENCES "APP"."SDS" ("SD_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."SKEWED_VALUES" ADD CONSTRAINT "SKEWED_VALUES_FK2" FOREIGN KEY ("STRING_LIST_ID_EID") REFERENCES "APP"."SKEWED_STRING_LIST" ("STRING_LIST_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."TAB_COL_STATS" ADD CONSTRAINT "TAB_COL_STATS_FK" FOREIGN KEY ("TBL_ID") REFERENCES TBLS("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."PART_COL_STATS" ADD CONSTRAINT "PART_COL_STATS_FK" FOREIGN KEY ("PART_ID") REFERENCES PARTITIONS("PART_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."VERSION" ADD CONSTRAINT "VERSION_PK" PRIMARY KEY ("VER_ID"); - -ALTER TABLE "APP"."FUNCS" ADD CONSTRAINT "FUNCS_FK1" FOREIGN KEY ("DB_ID") REFERENCES "APP"."DBS" ("DB_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."FUNC_RU" ADD CONSTRAINT "FUNC_RU_FK1" FOREIGN KEY ("FUNC_ID") REFERENCES "APP"."FUNCS" ("FUNC_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."WM_RESOURCEPLAN" ADD CONSTRAINT "WM_RESOURCEPLAN_PK" PRIMARY KEY ("RP_ID"); - -ALTER TABLE "APP"."WM_POOL" ADD CONSTRAINT "WM_POOL_PK" PRIMARY KEY ("POOL_ID"); - -ALTER TABLE "APP"."WM_POOL" ADD CONSTRAINT "WM_POOL_FK1" FOREIGN KEY ("RP_ID") REFERENCES "APP"."WM_RESOURCEPLAN" ("RP_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."WM_RESOURCEPLAN" ADD CONSTRAINT "WM_RESOURCEPLAN_FK1" FOREIGN KEY ("DEFAULT_POOL_ID") REFERENCES "APP"."WM_POOL" ("POOL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."WM_TRIGGER" ADD CONSTRAINT "WM_TRIGGER_PK" PRIMARY KEY ("TRIGGER_ID"); - -ALTER TABLE "APP"."WM_TRIGGER" ADD CONSTRAINT "WM_TRIGGER_FK1" FOREIGN KEY ("RP_ID") REFERENCES "APP"."WM_RESOURCEPLAN" ("RP_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."WM_POOL_TO_TRIGGER" ADD CONSTRAINT "WM_POOL_TO_TRIGGER_FK1" FOREIGN KEY ("POOL_ID") REFERENCES "APP"."WM_POOL" ("POOL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."WM_POOL_TO_TRIGGER" ADD CONSTRAINT "WM_POOL_TO_TRIGGER_FK2" FOREIGN KEY ("TRIGGER_ID") REFERENCES "APP"."WM_TRIGGER" ("TRIGGER_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."WM_MAPPING" ADD CONSTRAINT "WM_MAPPING_PK" PRIMARY KEY ("MAPPING_ID"); - -ALTER TABLE "APP"."WM_MAPPING" ADD CONSTRAINT "WM_MAPPING_FK1" FOREIGN KEY ("RP_ID") REFERENCES "APP"."WM_RESOURCEPLAN" ("RP_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."WM_MAPPING" ADD CONSTRAINT "WM_MAPPING_FK2" FOREIGN KEY ("POOL_ID") REFERENCES "APP"."WM_POOL" ("POOL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."MV_TABLES_USED" ADD CONSTRAINT "MV_TABLES_USED_PK" PRIMARY KEY ("TBL_ID", "MV_CREATION_METADATA_ID"); - -ALTER TABLE "APP"."MV_TABLES_USED" ADD CONSTRAINT "MV_TABLES_USED_FK1" FOREIGN KEY ("MV_CREATION_METADATA_ID") REFERENCES "APP"."MV_CREATION_METADATA" ("MV_CREATION_METADATA_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."MV_TABLES_USED" ADD CONSTRAINT "MV_TABLES_USED_FK2" FOREIGN KEY ("TBL_ID") REFERENCES "APP"."TBLS" ("TBL_ID") ON DELETE NO ACTION ON UPDATE NO ACTION; - -ALTER TABLE "APP"."DBS" ADD CONSTRAINT "DBS_CTLG_FK" FOREIGN KEY ("CTLG_NAME") REFERENCES "APP"."CTLGS" ("NAME") ON DELETE NO ACTION ON UPDATE NO ACTION; - --- ---------------------------------------------- --- DDL Statements for checks --- ---------------------------------------------- - -ALTER TABLE "APP"."IDXS" ADD CONSTRAINT "SQL110318025504980" CHECK (DEFERRED_REBUILD IN ('Y','N')); - -ALTER TABLE "APP"."SDS" ADD CONSTRAINT "SQL110318025505550" CHECK (IS_COMPRESSED IN ('Y','N')); - --- ---------------------------- --- Transaction and Lock Tables --- ---------------------------- -CREATE TABLE TXNS ( - TXN_ID bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, - TXN_STATE char(1) NOT NULL, - TXN_STARTED bigint NOT NULL, - TXN_LAST_HEARTBEAT bigint NOT NULL, - TXN_USER varchar(128) NOT NULL, - TXN_HOST varchar(128) NOT NULL, - TXN_AGENT_INFO varchar(128), - TXN_META_INFO varchar(128), - TXN_HEARTBEAT_COUNT integer, - TXN_TYPE integer -); - -INSERT INTO TXNS (TXN_ID, TXN_STATE, TXN_STARTED, TXN_LAST_HEARTBEAT, TXN_USER, TXN_HOST) - VALUES(0, 'c', 0, 0, '', ''); - -CREATE TABLE TXN_COMPONENTS ( - TC_TXNID bigint NOT NULL REFERENCES TXNS (TXN_ID), - TC_DATABASE varchar(128) NOT NULL, - TC_TABLE varchar(256), - TC_PARTITION varchar(767), - TC_OPERATION_TYPE char(1) NOT NULL, - TC_WRITEID bigint -); - -CREATE INDEX TC_TXNID_INDEX ON TXN_COMPONENTS (TC_TXNID); - -CREATE TABLE COMPLETED_TXN_COMPONENTS ( - CTC_TXNID bigint NOT NULL, - CTC_DATABASE varchar(128) NOT NULL, - CTC_TABLE varchar(256), - CTC_PARTITION varchar(767), - CTC_TIMESTAMP timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, - CTC_WRITEID bigint, - CTC_UPDATE_DELETE char(1) NOT NULL -); - -CREATE INDEX COMPLETED_TXN_COMPONENTS_IDX ON COMPLETED_TXN_COMPONENTS (CTC_DATABASE, CTC_TABLE, CTC_PARTITION); - -CREATE TABLE TXN_LOCK_TBL ( - TXN_LOCK bigint NOT NULL -); -INSERT INTO TXN_LOCK_TBL VALUES(1); - -CREATE TABLE HIVE_LOCKS ( - HL_LOCK_EXT_ID bigint NOT NULL, - HL_LOCK_INT_ID bigint NOT NULL, - HL_TXNID bigint NOT NULL, - HL_DB varchar(128) NOT NULL, - HL_TABLE varchar(256), - HL_PARTITION varchar(767), - HL_LOCK_STATE char(1) NOT NULL, - HL_LOCK_TYPE char(1) NOT NULL, - HL_LAST_HEARTBEAT bigint NOT NULL, - HL_ACQUIRED_AT bigint, - HL_USER varchar(128) NOT NULL, - HL_HOST varchar(128) NOT NULL, - HL_HEARTBEAT_COUNT integer, - HL_AGENT_INFO varchar(128), - HL_BLOCKEDBY_EXT_ID bigint, - HL_BLOCKEDBY_INT_ID bigint, - PRIMARY KEY(HL_LOCK_EXT_ID, HL_LOCK_INT_ID) -); - -CREATE INDEX HL_TXNID_INDEX ON HIVE_LOCKS (HL_TXNID); - -CREATE TABLE NEXT_LOCK_ID ( - NL_NEXT bigint NOT NULL -); -INSERT INTO NEXT_LOCK_ID VALUES(1); - -CREATE TABLE COMPACTION_QUEUE ( - CQ_ID bigint PRIMARY KEY, - CQ_DATABASE varchar(128) NOT NULL, - CQ_TABLE varchar(256) NOT NULL, - CQ_PARTITION varchar(767), - CQ_STATE char(1) NOT NULL, - CQ_TYPE char(1) NOT NULL, - CQ_TBLPROPERTIES varchar(2048), - CQ_WORKER_ID varchar(128), - CQ_ENQUEUE_TIME bigint, - CQ_START bigint, - CQ_RUN_AS varchar(128), - CQ_HIGHEST_WRITE_ID bigint, - CQ_META_INFO varchar(2048) for bit data, - CQ_HADOOP_JOB_ID varchar(32), - CQ_ERROR_MESSAGE clob, - CQ_NEXT_TXN_ID bigint, - CQ_TXN_ID bigint, - CQ_COMMIT_TIME bigint, - CQ_INITIATOR_ID varchar(128), - CQ_INITIATOR_VERSION varchar(128), - CQ_WORKER_VERSION varchar(128), - CQ_CLEANER_START bigint, - CQ_RETRY_RETENTION bigint NOT NULL DEFAULT 0 -); - -CREATE TABLE NEXT_COMPACTION_QUEUE_ID ( - NCQ_NEXT bigint NOT NULL -); -INSERT INTO NEXT_COMPACTION_QUEUE_ID VALUES(1); - -CREATE TABLE COMPLETED_COMPACTIONS ( - CC_ID bigint PRIMARY KEY, - CC_DATABASE varchar(128) NOT NULL, - CC_TABLE varchar(256) NOT NULL, - CC_PARTITION varchar(767), - CC_STATE char(1) NOT NULL, - CC_TYPE char(1) NOT NULL, - CC_TBLPROPERTIES varchar(2048), - CC_WORKER_ID varchar(128), - CC_ENQUEUE_TIME bigint, - CC_START bigint, - CC_END bigint, - CC_RUN_AS varchar(128), - CC_HIGHEST_WRITE_ID bigint, - CC_META_INFO varchar(2048) for bit data, - CC_HADOOP_JOB_ID varchar(32), - CC_ERROR_MESSAGE clob, - CC_NEXT_TXN_ID bigint, - CC_TXN_ID bigint, - CC_COMMIT_TIME bigint, - CC_INITIATOR_ID varchar(128), - CC_INITIATOR_VERSION varchar(128), - CC_WORKER_VERSION varchar(128) -); - -CREATE INDEX COMPLETED_COMPACTIONS_RES ON COMPLETED_COMPACTIONS (CC_DATABASE,CC_TABLE,CC_PARTITION); - --- HIVE-25842 -CREATE TABLE COMPACTION_METRICS_CACHE ( - CMC_DATABASE varchar(128) NOT NULL, - CMC_TABLE varchar(256) NOT NULL, - CMC_PARTITION varchar(767), - CMC_METRIC_TYPE varchar(128) NOT NULL, - CMC_METRIC_VALUE integer NOT NULL, - CMC_VERSION integer NOT NULL -); - -CREATE TABLE AUX_TABLE ( - MT_KEY1 varchar(128) NOT NULL, - MT_KEY2 bigint NOT NULL, - MT_COMMENT varchar(255), - PRIMARY KEY(MT_KEY1, MT_KEY2) -); - ---1st 4 cols make up a PK but since WS_PARTITION is nullable we can't declare such PK ---This is a good candidate for Index orgainzed table -CREATE TABLE WRITE_SET ( - WS_DATABASE varchar(128) NOT NULL, - WS_TABLE varchar(256) NOT NULL, - WS_PARTITION varchar(767), - WS_TXNID bigint NOT NULL, - WS_COMMIT_ID bigint NOT NULL, - WS_OPERATION_TYPE char(1) NOT NULL -); - -CREATE TABLE TXN_TO_WRITE_ID ( - T2W_TXNID bigint NOT NULL, - T2W_DATABASE varchar(128) NOT NULL, - T2W_TABLE varchar(256) NOT NULL, - T2W_WRITEID bigint NOT NULL -); - -CREATE UNIQUE INDEX TBL_TO_TXN_ID_IDX ON TXN_TO_WRITE_ID (T2W_DATABASE, T2W_TABLE, T2W_TXNID); -CREATE UNIQUE INDEX TBL_TO_WRITE_ID_IDX ON TXN_TO_WRITE_ID (T2W_DATABASE, T2W_TABLE, T2W_WRITEID); - -CREATE TABLE NEXT_WRITE_ID ( - NWI_DATABASE varchar(128) NOT NULL, - NWI_TABLE varchar(256) NOT NULL, - NWI_NEXT bigint NOT NULL -); - -CREATE UNIQUE INDEX NEXT_WRITE_ID_IDX ON NEXT_WRITE_ID (NWI_DATABASE, NWI_TABLE); - -CREATE TABLE MIN_HISTORY_LEVEL ( - MHL_TXNID bigint NOT NULL, - MHL_MIN_OPEN_TXNID bigint NOT NULL, - PRIMARY KEY(MHL_TXNID) -); - -CREATE INDEX MIN_HISTORY_LEVEL_IDX ON MIN_HISTORY_LEVEL (MHL_MIN_OPEN_TXNID); - -CREATE TABLE MATERIALIZATION_REBUILD_LOCKS ( - MRL_TXN_ID BIGINT NOT NULL, - MRL_DB_NAME VARCHAR(128) NOT NULL, - MRL_TBL_NAME VARCHAR(256) NOT NULL, - MRL_LAST_HEARTBEAT BIGINT NOT NULL, - PRIMARY KEY(MRL_TXN_ID) -); - -CREATE TABLE "APP"."I_SCHEMA" ( - "SCHEMA_ID" bigint primary key, - "SCHEMA_TYPE" integer not null, - "NAME" varchar(256) unique, - "DB_ID" bigint references "APP"."DBS" ("DB_ID"), - "COMPATIBILITY" integer not null, - "VALIDATION_LEVEL" integer not null, - "CAN_EVOLVE" char(1) not null, - "SCHEMA_GROUP" varchar(256), - "DESCRIPTION" varchar(4000) -); - -CREATE TABLE "APP"."SCHEMA_VERSION" ( - "SCHEMA_VERSION_ID" bigint primary key, - "SCHEMA_ID" bigint references "APP"."I_SCHEMA" ("SCHEMA_ID"), - "VERSION" integer not null, - "CREATED_AT" bigint not null, - "CD_ID" bigint references "APP"."CDS" ("CD_ID"), - "STATE" integer not null, - "DESCRIPTION" varchar(4000), - "SCHEMA_TEXT" clob, - "FINGERPRINT" varchar(256), - "SCHEMA_VERSION_NAME" varchar(256), - "SERDE_ID" bigint references "APP"."SERDES" ("SERDE_ID") -); - -CREATE UNIQUE INDEX "APP"."UNIQUE_SCHEMA_VERSION" ON "APP"."SCHEMA_VERSION" ("SCHEMA_ID", "VERSION"); - -CREATE TABLE TXN_WRITE_NOTIFICATION_LOG ( - WNL_ID bigint NOT NULL, - WNL_TXNID bigint NOT NULL, - WNL_WRITEID bigint NOT NULL, - WNL_DATABASE varchar(128) NOT NULL, - WNL_TABLE varchar(256) NOT NULL, - WNL_PARTITION varchar(767) NOT NULL, - WNL_TABLE_OBJ clob NOT NULL, - WNL_PARTITION_OBJ clob, - WNL_FILES clob, - WNL_EVENT_TIME integer NOT NULL, - PRIMARY KEY (WNL_TXNID, WNL_DATABASE, WNL_TABLE, WNL_PARTITION) -); -INSERT INTO SEQUENCE_TABLE (SEQUENCE_NAME, NEXT_VAL) VALUES ('org.apache.hadoop.hive.metastore.model.MTxnWriteNotificationLog', 1); - --- ----------------------------------------------------------------- --- Record schema version. Should be the last step in the init script --- ----------------------------------------------------------------- -INSERT INTO "APP"."VERSION" (VER_ID, SCHEMA_VERSION, VERSION_COMMENT) VALUES (1, '4.0.0-alpha-2', 'Hive release version 4.0.0-alpha-2'); diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/pom.xml b/nifi-extension-bundles/nifi-iceberg-bundle/pom.xml deleted file mode 100644 index db24c40564..0000000000 --- a/nifi-extension-bundles/nifi-iceberg-bundle/pom.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - org.apache.nifi - nifi-standard-services-api-bom - 2.0.0-SNAPSHOT - ../nifi-standard-services-api-bom - - 4.0.0 - - nifi-iceberg-bundle - pom - - - 1.6.1 - 3.1.3 - - - - nifi-iceberg-services-api - nifi-iceberg-services-api-nar - nifi-iceberg-services - nifi-iceberg-services-nar - nifi-iceberg-processors - nifi-iceberg-processors-nar - nifi-iceberg-common - nifi-iceberg-test-utils - - - - - - io.netty - netty - ${netty.3.version} - - - - org.glassfish - javax.el - 3.0.1-b12 - - - - commons-beanutils - commons-beanutils - 1.9.4 - - - - org.apache.derby - derby - ${derby.version} - - - - org.apache.ant - ant - 1.10.15 - - - - org.codehaus.jettison - jettison - 1.5.4 - - - - com.nimbusds - nimbus-jose-jwt - 9.41.2 - - - - org.apache.hadoop - hadoop-yarn-server-resourcemanager - ${hadoop.version} - - - org.bouncycastle - bcprov-jdk15on - - - org.bouncycastle - bcpkix-jdk15on - - - org.eclipse.jetty - jetty-util-ajax - - - - - org.apache.hadoop - hadoop-common - ${hadoop.version} - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - - - org.slf4j - slf4j-reload4j - - - commons-logging - commons-logging - - - org.eclipse.jetty - jetty-server - - - org.eclipse.jetty - jetty-servlet - - - org.eclipse.jetty - jetty-webapp - - - org.eclipse.jetty - jetty-util - - - org.eclipse.jetty - jetty-http - - - org.eclipse.jetty - jetty-rewrite - - - - org.bouncycastle - bcprov-jdk15on - - - - - - com.google.guava - guava - 33.3.1-jre - - - - org.codehaus.groovy - groovy-all - 2.4.21 - - - - diff --git a/nifi-extension-bundles/nifi-protobuf-bundle/nifi-protobuf-services-nar/src/main/resources/META-INF/NOTICE b/nifi-extension-bundles/nifi-protobuf-bundle/nifi-protobuf-services-nar/src/main/resources/META-INF/NOTICE index b57ec55464..1d9f0842ac 100644 --- a/nifi-extension-bundles/nifi-protobuf-bundle/nifi-protobuf-services-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-extension-bundles/nifi-protobuf-bundle/nifi-protobuf-services-nar/src/main/resources/META-INF/NOTICE @@ -1,4 +1,4 @@ -nifi-iceberg-processors-nar +nifi-protobuf-services-nar Copyright 2014-2023 The Apache Software Foundation This product includes software developed at diff --git a/nifi-extension-bundles/pom.xml b/nifi-extension-bundles/pom.xml index b125514a09..87e58db751 100755 --- a/nifi-extension-bundles/pom.xml +++ b/nifi-extension-bundles/pom.xml @@ -84,7 +84,6 @@ nifi-box-bundle nifi-flow-registry-client-bundle nifi-shopify-bundle - nifi-iceberg-bundle nifi-jslt-bundle nifi-iotdb-bundle nifi-cipher-bundle