Skip to content

Commit

Permalink
Add licence header to TestIcebergMultipartNamespaces
Browse files Browse the repository at this point in the history
  • Loading branch information
sftwrdvlpr committed Sep 28, 2024
1 parent 8f940d0 commit 173c66d
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import org.apache.iceberg.view.ViewRepresentation;
import org.apache.iceberg.view.ViewVersion;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
Expand All @@ -87,6 +88,7 @@
import static io.trino.plugin.iceberg.IcebergErrorCode.ICEBERG_CATALOG_ERROR;
import static io.trino.plugin.iceberg.IcebergErrorCode.ICEBERG_UNSUPPORTED_VIEW_DIALECT;
import static io.trino.plugin.iceberg.IcebergUtil.quotedTableName;
import static io.trino.plugin.iceberg.IcebergUtil.toNamespace;
import static io.trino.plugin.iceberg.catalog.AbstractTrinoCatalog.ICEBERG_VIEW_RUN_AS_OWNER;
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
import static java.lang.String.format;
Expand Down Expand Up @@ -134,22 +136,34 @@ public TrinoRestCatalog(
@Override
public boolean namespaceExists(ConnectorSession session, String namespace)
{
return restSessionCatalog.namespaceExists(convert(session), Namespace.of(namespace));
return restSessionCatalog.namespaceExists(convert(session), toNamespace(namespace));
}

@Override
public List<String> listNamespaces(ConnectorSession session)
{
return restSessionCatalog.listNamespaces(convert(session)).stream()
.map(Namespace::toString)
.collect(toImmutableList());
return collectNamespaces(session, Namespace.empty());
}

private List<String> collectNamespaces(ConnectorSession session, Namespace parentNamespace)
{
ArrayList<String> namespacesList = new ArrayList<>();

List<Namespace> childNamespaces = restSessionCatalog.listNamespaces(convert(session), parentNamespace);

for (Namespace childNamespace : childNamespaces) {
namespacesList.add(childNamespace.toString());
namespacesList.addAll(collectNamespaces(session, childNamespace));
}

return namespacesList;
}

@Override
public void dropNamespace(ConnectorSession session, String namespace)
{
try {
restSessionCatalog.dropNamespace(convert(session), Namespace.of(namespace));
restSessionCatalog.dropNamespace(convert(session), toNamespace(namespace));
}
catch (NoSuchNamespaceException e) {
throw new SchemaNotFoundException(namespace);
Expand All @@ -164,7 +178,7 @@ public Map<String, Object> loadNamespaceMetadata(ConnectorSession session, Strin
{
try {
// Return immutable metadata as direct modifications will not be reflected on the namespace
return ImmutableMap.copyOf(restSessionCatalog.loadNamespaceMetadata(convert(session), Namespace.of(namespace)));
return ImmutableMap.copyOf(restSessionCatalog.loadNamespaceMetadata(convert(session), toNamespace(namespace)));
}
catch (NoSuchNamespaceException e) {
throw new SchemaNotFoundException(namespace);
Expand All @@ -183,7 +197,7 @@ public void createNamespace(ConnectorSession session, String namespace, Map<Stri
{
restSessionCatalog.createNamespace(
convert(session),
Namespace.of(namespace),
toNamespace(namespace),
Maps.transformValues(properties, property -> {
if (property instanceof String stringProperty) {
return stringProperty;
Expand Down Expand Up @@ -431,7 +445,7 @@ public void createView(ConnectorSession session, SchemaTableName schemaViewName,
ViewBuilder viewBuilder = restSessionCatalog.buildView(convert(session), toIdentifier(schemaViewName));
viewBuilder = viewBuilder.withSchema(schema)
.withQuery("trino", definition.getOriginalSql())
.withDefaultNamespace(Namespace.of(schemaViewName.getSchemaName()))
.withDefaultNamespace(toNamespace(schemaViewName.getSchemaName()))
.withDefaultCatalog(definition.getCatalog().orElse(null))
.withProperties(properties.buildOrThrow())
.withLocation(defaultTableLocation(session, schemaViewName));
Expand Down Expand Up @@ -655,17 +669,17 @@ private void invalidateTableCache(SchemaTableName schemaTableName)

private static TableIdentifier toIdentifier(SchemaTableName schemaTableName)
{
return TableIdentifier.of(schemaTableName.getSchemaName(), schemaTableName.getTableName());
return TableIdentifier.of(toNamespace(schemaTableName.getSchemaName()), schemaTableName.getTableName());
}

private List<Namespace> listNamespaces(ConnectorSession session, Optional<String> namespace)
{
if (namespace.isEmpty()) {
return listNamespaces(session).stream()
.map(Namespace::of)
.map(IcebergUtil::toNamespace)
.collect(toImmutableList());
}

return ImmutableList.of(Namespace.of(namespace.get()));
return ImmutableList.of(toNamespace(namespace.get()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* 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.
*/
package io.trino.plugin.iceberg;

import com.google.common.collect.ImmutableSet;
import io.trino.testing.AbstractTestQueryFramework;
import io.trino.testing.QueryRunner;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static io.trino.testing.TestingNames.randomNameSuffix;
import static org.assertj.core.api.Assertions.assertThat;

public class TestIcebergMultipartNamespaces
extends AbstractTestQueryFramework
{
private static final String LEVEL_1_NAMESPACE = "level_1_%s".formatted(randomNameSuffix());
private static final String LEVEL_2_NAMESPACE = "level_2_%s".formatted(randomNameSuffix());

@Override
protected QueryRunner createQueryRunner()
throws Exception
{
return IcebergQueryRunner.builder().build();
}

@BeforeAll
public void setUp()
{
assertUpdate("CREATE SCHEMA " + LEVEL_1_NAMESPACE);
assertUpdate("CREATE SCHEMA \"%s\"".formatted(buildNamespace(LEVEL_2_NAMESPACE, NamespaceLevel.SECOND)));
}

@AfterAll
public void tearDown()
{
assertUpdate("DROP SCHEMA \"%s\"".formatted(buildNamespace(LEVEL_2_NAMESPACE, NamespaceLevel.SECOND)));
assertUpdate("DROP SCHEMA " + LEVEL_1_NAMESPACE);
}

@Test
public void testCreateNestedNamespace()
{
String nestedNamespace = buildNamespace("level_3_%s".formatted(randomNameSuffix()), NamespaceLevel.THIRD);
ImmutableSet<String> expectedSchemas = ImmutableSet.of(LEVEL_1_NAMESPACE, buildNamespace(LEVEL_2_NAMESPACE, NamespaceLevel.SECOND), nestedNamespace);

assertUpdate("CREATE SCHEMA \"%s\"".formatted(nestedNamespace));

ImmutableSet<String> actualSchemas = computeActual("show schemas")
.getOnlyColumnAsSet()
.stream()
.map(String.class::cast)
.collect(toImmutableSet());

assertThat(actualSchemas).containsAll(expectedSchemas);

assertUpdate("DROP SCHEMA \"%s\"".formatted(nestedNamespace));
}

@Test
public void testCreateTable()
{
String nestedNamespace = buildNamespace("level_3_%s".formatted(randomNameSuffix()), NamespaceLevel.THIRD);
String tableFullPath = "\"%s\".%s".formatted(nestedNamespace, "test_table_%s".formatted(randomNameSuffix()));

assertUpdate("CREATE SCHEMA \"%s\"".formatted(nestedNamespace));
assertUpdate("CREATE TABLE %s (field_1 int, field_2 varchar)".formatted(tableFullPath));
assertUpdate("INSERT INTO %s (field_1, field_2) VALUES (1, 'first_value')".formatted(tableFullPath), 1);
assertUpdate("INSERT INTO %s (field_1, field_2) VALUES (2, 'second_value')".formatted(tableFullPath), 1);

int rowsCount = computeActual("SELECT * FROM %s".formatted(tableFullPath)).getRowCount();

assertThat(rowsCount).isEqualTo(2);
assertUpdate("DROP TABLE %s".formatted(tableFullPath));
assertUpdate("DROP SCHEMA \"%s\"".formatted(nestedNamespace));
}

@Test
public void testCreateView()
{
String nestedNamespace = buildNamespace("level_3_%s".formatted(randomNameSuffix()), NamespaceLevel.THIRD);
String tableFullPath = "\"%s\".%s".formatted(nestedNamespace, "test_table_%s".formatted(randomNameSuffix()));
String viewFullPath = "\"%s\".%s".formatted(nestedNamespace, "test_table_view_%s".formatted(randomNameSuffix()));

assertUpdate("CREATE SCHEMA \"%s\"".formatted(nestedNamespace));
assertUpdate("CREATE TABLE %s (field_1 int, field_2 varchar)".formatted(tableFullPath));
assertUpdate("INSERT INTO %s (field_1, field_2) VALUES (1, '%s')".formatted(tableFullPath, randomNameSuffix()), 1);
assertUpdate("INSERT INTO %s (field_1, field_2) VALUES (2, '%s')".formatted(tableFullPath, randomNameSuffix()), 1);
assertUpdate("CREATE VIEW %s AS SELECT * FROM %s".formatted(viewFullPath, tableFullPath));

int rowsCount = computeActual("SELECT * FROM %s".formatted(viewFullPath)).getRowCount();

assertThat(rowsCount).isEqualTo(2);
assertUpdate("DROP TABLE %s".formatted(tableFullPath));
assertUpdate("DROP VIEW %s".formatted(viewFullPath));
assertUpdate("DROP SCHEMA \"%s\"".formatted(nestedNamespace));
}

@Test
public void testCreateMaterializedView()
{
String nestedNamespace = buildNamespace("level_3_%s".formatted(randomNameSuffix()), NamespaceLevel.THIRD);
String tableFullPath = "\"%s\".%s".formatted(nestedNamespace, "test_table_%s".formatted(randomNameSuffix()));
String viewFullPath = "\"%s\".%s".formatted(nestedNamespace, "test_table_view_%s".formatted(randomNameSuffix()));

assertUpdate("CREATE SCHEMA \"%s\"".formatted(nestedNamespace));
assertUpdate("CREATE TABLE %s (field_1 int, field_2 varchar)".formatted(tableFullPath));
assertUpdate("INSERT INTO %s (field_1, field_2) VALUES (1, '%s')".formatted(tableFullPath, randomNameSuffix()), 1);
assertUpdate("INSERT INTO %s (field_1, field_2) VALUES (2, '%s')".formatted(tableFullPath, randomNameSuffix()), 1);
assertUpdate("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s".formatted(viewFullPath, tableFullPath));

int rowsCount = computeActual("SELECT * FROM %s".formatted(viewFullPath)).getRowCount();

assertThat(rowsCount).isEqualTo(2);
assertUpdate("DROP TABLE %s".formatted(tableFullPath));
assertUpdate("DROP MATERIALIZED VIEW %s".formatted(viewFullPath));
assertUpdate("DROP SCHEMA \"%s\"".formatted(nestedNamespace));
}

private String buildNamespace(String namespace, NamespaceLevel level)
{
return switch (level) {
case FIRST -> namespace;
case SECOND -> "%s.%s".formatted(LEVEL_1_NAMESPACE, namespace);
case THIRD -> "%s.%s.%s".formatted(LEVEL_1_NAMESPACE, LEVEL_2_NAMESPACE, namespace);
};
}

private enum NamespaceLevel
{
FIRST, SECOND, THIRD
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,24 +206,24 @@ public void testMultipartNamespace()
String dotSeparator = ".";
TrinoCatalog catalog = createTrinoCatalog(false);

String firstLevel = "level-1" + randomNameSuffix();
String secondLevel = "level-2" + randomNameSuffix();
String thirdLevel = "level-3" + randomNameSuffix();

ImmutableList<String> namespacesList = ImmutableList.of(
"level-1" + randomNameSuffix(),
"level-1" + randomNameSuffix() + dotSeparator + "level-2" + randomNameSuffix(),
"level-1" + randomNameSuffix() + dotSeparator + "level-2" + randomNameSuffix() + dotSeparator + "level-3" + randomNameSuffix());
firstLevel,
firstLevel + dotSeparator + secondLevel,
firstLevel + dotSeparator + secondLevel + dotSeparator + thirdLevel);

for (String namespace : namespacesList) {
catalog.createNamespace(SESSION, namespace, Map.of(), new TrinoPrincipal(PrincipalType.USER, SESSION.getUser()));
}
namespacesList.forEach(namespace -> catalog.createNamespace(SESSION, namespace, Map.of(), new TrinoPrincipal(PrincipalType.USER, SESSION.getUser())));

try {
assertThat(catalog.listNamespaces(SESSION)).as("catalog.listNamespaces")
.hasSize(namespacesList.size())
.containsAll(namespacesList);
}
finally {
for (String namespace : namespacesList) {
catalog.dropNamespace(SESSION, namespace);
}
namespacesList.reverse().forEach(namespace -> catalog.dropNamespace(SESSION, namespace));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,31 @@ public void testPrefix()
.as("should fail as the prefix dev is not implemented for the current endpoint")
.hasMessageContaining("Malformed request: No route for request: POST v1/dev/namespaces");
}

@Test
public void testMultipartNamespace()
{
String dotSeparator = ".";
TrinoCatalog catalog = createTrinoCatalog(false);

String firstLevel = "level-1" + randomNameSuffix();
String secondLevel = "level-2" + randomNameSuffix();
String thirdLevel = "level-3" + randomNameSuffix();

ImmutableList<String> namespacesList = ImmutableList.of(
firstLevel,
firstLevel + dotSeparator + secondLevel,
firstLevel + dotSeparator + secondLevel + dotSeparator + thirdLevel);

namespacesList.forEach(namespace -> catalog.createNamespace(SESSION, namespace, ImmutableMap.of(), new TrinoPrincipal(PrincipalType.USER, SESSION.getUser())));

try {
assertThat(catalog.listNamespaces(SESSION)).as("catalog.listNamespaces")
.hasSize(namespacesList.size())
.containsAll(namespacesList);
}
finally {
namespacesList.reverse().forEach(namespace -> catalog.dropNamespace(SESSION, namespace));
}
}
}

0 comments on commit 173c66d

Please sign in to comment.