From e3b219bfbd71a079de5d89b57772219487663e3f Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Sat, 11 Sep 2021 01:15:47 -0700 Subject: [PATCH 1/5] refactor sql authorization to get resource type from schema, refactor resource type from enum to string --- .../druid/benchmark/query/SqlBenchmark.java | 7 ++- .../query/SqlExpressionBenchmark.java | 8 ++- .../benchmark/query/SqlVsNativeBenchmark.java | 8 ++- .../BasicRoleBasedAuthorizer.java | 3 +- .../druid/security/BasicAuthUtilsTest.java | 11 ++-- .../ranger/authorizer/RangerAuthorizer.java | 2 +- .../server/security/AuthorizationUtils.java | 61 ++++++------------- .../druid/server/security/Resource.java | 14 ++--- .../druid/server/security/ResourceType.java | 48 +++++++++++---- .../security/AuthorizationUtilsTest.java | 15 ++++- .../sql/calcite/planner/DruidPlanner.java | 2 +- .../sql/calcite/planner/PlannerContext.java | 12 ++++ .../sql/calcite/planner/PlannerFactory.java | 11 ++++ .../planner/SqlResourceCollectorShuttle.java | 14 ++--- .../sql/calcite/schema/NamedDruidSchema.java | 11 +++- .../sql/calcite/schema/NamedLookupSchema.java | 4 +- .../druid/sql/calcite/schema/NamedSchema.java | 8 +++ .../sql/calcite/schema/NamedSystemSchema.java | 6 +- .../sql/calcite/schema/NamedViewSchema.java | 9 ++- .../sql/avatica/DruidAvaticaHandlerTest.java | 19 ++++-- .../druid/sql/avatica/DruidStatementTest.java | 8 ++- .../sql/calcite/BaseCalciteQueryTest.java | 7 ++- .../SqlVectorizedExpressionSanityTest.java | 8 ++- .../expression/ExpressionTestHelper.java | 1 + .../planner/CalcitePlannerModuleTest.java | 3 + .../druid/sql/calcite/util/CalciteTests.java | 56 ++++++++++++----- .../druid/sql/http/SqlResourceTest.java | 7 ++- 27 files changed, 241 insertions(+), 122 deletions(-) diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java index 7d9a55d904b1..720f0de40c46 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap; import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; +import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; import org.apache.druid.java.util.common.io.Closer; @@ -46,6 +47,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.timeline.DataSegment; @@ -421,10 +423,11 @@ public void setup() ); closer.register(walker); - final SchemaPlus rootSchema = + final Pair> rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); plannerFactory = new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java index cb5ce5f45d6d..cad156327d6e 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap; import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; +import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; import org.apache.druid.java.util.common.io.Closer; @@ -42,6 +43,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.timeline.DataSegment; @@ -64,6 +66,7 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -264,10 +267,11 @@ public void setup() ); closer.register(walker); - final SchemaPlus rootSchema = + final Pair> rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); plannerFactory = new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java index dda14ff0b4b8..5be5b4942f6f 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java @@ -22,6 +22,7 @@ import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; import org.apache.druid.java.util.common.Intervals; +import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; import org.apache.druid.java.util.common.io.Closer; @@ -43,6 +44,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.timeline.DataSegment; @@ -62,6 +64,7 @@ import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -111,10 +114,11 @@ public void setup() final PlannerConfig plannerConfig = new PlannerConfig(); this.walker = closer.register(new SpecificSegmentsQuerySegmentWalker(conglomerate).add(dataSegment, index)); - final SchemaPlus rootSchema = + final Pair> rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); plannerFactory = new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/BasicRoleBasedAuthorizer.java b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/BasicRoleBasedAuthorizer.java index f307b9ea029e..206e89544675 100644 --- a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/BasicRoleBasedAuthorizer.java +++ b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/BasicRoleBasedAuthorizer.java @@ -36,6 +36,7 @@ import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -116,7 +117,7 @@ private boolean permissionCheck(Resource resource, Action action, BasicAuthorize } Resource permissionResource = permission.getResourceAction().getResource(); - if (permissionResource.getType() != resource.getType()) { + if (!Objects.equals(permissionResource.getType(), resource.getType())) { return false; } diff --git a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java index 7bcb1e24c778..a73e94a11c67 100644 --- a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java +++ b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java @@ -60,6 +60,7 @@ public void testPermissionSerdeIsChillAboutUnknownEnumStuffs() throws JsonProces final String thirdRoleName = "third-role"; final ResourceAction fooRead = new ResourceAction(new Resource("foo", ResourceType.DATASOURCE), Action.READ); final ResourceAction barRead = new ResourceAction(new Resource("bar", ResourceType.DATASOURCE), Action.READ); + final ResourceAction customRead = new ResourceAction(new Resource("bar", "CUSTOM"), Action.READ); final ObjectMapper mapper = TestHelper.makeJsonMapper(); mapper.registerModules(new BasicSecurityDruidModule().getJacksonModules()); @@ -76,7 +77,7 @@ public void testPermissionSerdeIsChillAboutUnknownEnumStuffs() throws JsonProces ) ) ); - // bad ResourceType + // custom ResourceType rawMap.put( otherRoleName, ImmutableMap.of( @@ -92,7 +93,7 @@ public void testPermissionSerdeIsChillAboutUnknownEnumStuffs() throws JsonProces "resourceAction", ImmutableMap.of( "resource", - ImmutableMap.of("name", "bar", "type", "UNKNOWN"), + ImmutableMap.of("name", "bar", "type", "CUSTOM"), "action", "READ" ), "resourceNamePattern", "bar" @@ -141,11 +142,11 @@ public void testPermissionSerdeIsChillAboutUnknownEnumStuffs() throws JsonProces roleMap.get(someRoleName).getPermissions() ); - // this one has an unknown ResourceType, expect only 1 permission to deserialize correctly and failure ignored + // this one has custom resource type... this test is somewhat pointless, it made more sense when type was an enum Assert.assertTrue(roleMap.containsKey(otherRoleName)); - Assert.assertEquals(1, roleMap.get(otherRoleName).getPermissions().size()); + Assert.assertEquals(2, roleMap.get(otherRoleName).getPermissions().size()); Assert.assertEquals( - BasicAuthorizerPermission.makePermissionList(ImmutableList.of(fooRead)), + BasicAuthorizerPermission.makePermissionList(ImmutableList.of(fooRead, customRead)), roleMap.get(otherRoleName).getPermissions() ); diff --git a/extensions-core/druid-ranger-security/src/main/java/org/apache/druid/security/ranger/authorizer/RangerAuthorizer.java b/extensions-core/druid-ranger-security/src/main/java/org/apache/druid/security/ranger/authorizer/RangerAuthorizer.java index 330a7c0250d5..1d4bf1578b26 100644 --- a/extensions-core/druid-ranger-security/src/main/java/org/apache/druid/security/ranger/authorizer/RangerAuthorizer.java +++ b/extensions-core/druid-ranger-security/src/main/java/org/apache/druid/security/ranger/authorizer/RangerAuthorizer.java @@ -126,7 +126,7 @@ class RangerDruidResource extends RangerAccessResourceImpl { public RangerDruidResource(Resource resource) { - setValue(resource.getType().name().toLowerCase(Locale.ENGLISH), resource.getName()); + setValue(resource.getType().toLowerCase(Locale.ENGLISH), resource.getName()); } } diff --git a/server/src/main/java/org/apache/druid/server/security/AuthorizationUtils.java b/server/src/main/java/org/apache/druid/server/security/AuthorizationUtils.java index 6ba34f6794f4..2b4449826476 100644 --- a/server/src/main/java/org/apache/druid/server/security/AuthorizationUtils.java +++ b/server/src/main/java/org/apache/druid/server/security/AuthorizationUtils.java @@ -25,6 +25,7 @@ import org.apache.druid.java.util.common.ISE; import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -359,49 +360,27 @@ public static Map> filterAuthorizedRes return filteredResources; } + /** + * This method constructs a 'superuser' set of permissions composed of {@link Action#READ} and {@link Action#WRITE} + * permissions for all known {@link ResourceType#knownTypes()} for any {@link Authorizer} implementation which is + * built on pattern matching with a regex. + * + * Note that if any {@link Resource} exist that use custom types not registered with + * {@link ResourceType#registerResourceType}, those permissions will not be included in this list and will need to + * be added manually. + */ public static List makeSuperUserPermissions() { - ResourceAction datasourceR = new ResourceAction( - new Resource(".*", ResourceType.DATASOURCE), - Action.READ - ); - - ResourceAction datasourceW = new ResourceAction( - new Resource(".*", ResourceType.DATASOURCE), - Action.WRITE - ); - - ResourceAction viewR = new ResourceAction( - new Resource(".*", ResourceType.VIEW), - Action.READ - ); - - ResourceAction viewW = new ResourceAction( - new Resource(".*", ResourceType.VIEW), - Action.WRITE - ); - - ResourceAction configR = new ResourceAction( - new Resource(".*", ResourceType.CONFIG), - Action.READ - ); - - ResourceAction configW = new ResourceAction( - new Resource(".*", ResourceType.CONFIG), - Action.WRITE - ); - - ResourceAction stateR = new ResourceAction( - new Resource(".*", ResourceType.STATE), - Action.READ - ); - - ResourceAction stateW = new ResourceAction( - new Resource(".*", ResourceType.STATE), - Action.WRITE - ); - - return Lists.newArrayList(datasourceR, datasourceW, viewR, viewW, configR, configW, stateR, stateW); + List allReadAndWrite = new ArrayList<>(ResourceType.knownTypes().size() * 2); + for (String type : ResourceType.knownTypes()) { + allReadAndWrite.add( + new ResourceAction(new Resource(".*", type), Action.READ) + ); + allReadAndWrite.add( + new ResourceAction(new Resource(".*", type), Action.WRITE) + ); + } + return allReadAndWrite; } /** diff --git a/server/src/main/java/org/apache/druid/server/security/Resource.java b/server/src/main/java/org/apache/druid/server/security/Resource.java index 6770bdaf5cbc..710673f52b4d 100644 --- a/server/src/main/java/org/apache/druid/server/security/Resource.java +++ b/server/src/main/java/org/apache/druid/server/security/Resource.java @@ -22,17 +22,19 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Objects; + public class Resource { public static final Resource STATE_RESOURCE = new Resource("STATE", ResourceType.STATE); private final String name; - private final ResourceType type; + private final String type; @JsonCreator public Resource( @JsonProperty("name") String name, - @JsonProperty("type") ResourceType type + @JsonProperty("type") String type ) { this.name = name; @@ -46,7 +48,7 @@ public String getName() } @JsonProperty - public ResourceType getType() + public String getType() { return type; } @@ -66,16 +68,14 @@ public boolean equals(Object o) if (!name.equals(resource.name)) { return false; } - return type == resource.type; + return Objects.equals(type, resource.type); } @Override public int hashCode() { - int result = name.hashCode(); - result = 31 * result + type.hashCode(); - return result; + return Objects.hash(name, type); } @Override diff --git a/server/src/main/java/org/apache/druid/server/security/ResourceType.java b/server/src/main/java/org/apache/druid/server/security/ResourceType.java index 04cf43af184b..0e02572b6151 100644 --- a/server/src/main/java/org/apache/druid/server/security/ResourceType.java +++ b/server/src/main/java/org/apache/druid/server/security/ResourceType.java @@ -19,22 +19,44 @@ package org.apache.druid.server.security; -import com.fasterxml.jackson.annotation.JsonCreator; -import org.apache.druid.java.util.common.StringUtils; +import com.google.common.collect.Sets; -public enum ResourceType +import java.util.Set; + +/** + * Set of built-in and 'registered' {@link Resource} types for use by {@link Authorizer} + */ +public class ResourceType { - DATASOURCE, - VIEW, - CONFIG, - STATE; + public static final String DATASOURCE = "DATASOURCE"; + public static final String VIEW = "VIEW"; + public static final String CONFIG = "CONFIG"; + public static final String STATE = "STATE"; + + private static final Set KNOWN_TYPES = Sets.newConcurrentHashSet(); + + // initialize built-ins + static { + registerResourceType(DATASOURCE); + registerResourceType(VIEW); + registerResourceType(CONFIG); + registerResourceType(STATE); + } + + /** + * Set of 'known' {@link Resource} types which have been registered with {@link #registerResourceType}, for use by + * utility methods looking to construct permission sets for all types (e.g. 'superuser' permission set) + */ + public static Set knownTypes() + { + return KNOWN_TYPES; + } - @JsonCreator - public static ResourceType fromString(String name) + /** + * 'register' a 'known' type of {@link Resource} to make available via {@link #knownTypes()} + */ + public static void registerResourceType(String type) { - if (name == null) { - return null; - } - return valueOf(StringUtils.toUpperCase(name)); + KNOWN_TYPES.add(type); } } diff --git a/server/src/test/java/org/apache/druid/server/security/AuthorizationUtilsTest.java b/server/src/test/java/org/apache/druid/server/security/AuthorizationUtilsTest.java index 8c6ec8169e80..a9d87a4fd79f 100644 --- a/server/src/test/java/org/apache/druid/server/security/AuthorizationUtilsTest.java +++ b/server/src/test/java/org/apache/druid/server/security/AuthorizationUtilsTest.java @@ -30,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; public class AuthorizationUtilsTest { @@ -88,16 +89,26 @@ public Iterable apply(@Nullable String input) @Test public void testMakeSuperuserPermissions() { + final String customType = "CUSTOM"; + ResourceType.registerResourceType(customType); final List permissions = AuthorizationUtils.makeSuperUserPermissions(); // every type and action should have a wildcard pattern - for (ResourceType type : ResourceType.values()) { + for (String type : ResourceType.knownTypes()) { for (Action action : Action.values()) { Assert.assertTrue( permissions.stream() - .filter(ra -> type == ra.getResource().getType()) + .filter(ra -> Objects.equals(type, ra.getResource().getType())) .anyMatch(ra -> action == ra.getAction() && ".*".equals(ra.getResource().getName())) ); } } + // custom type should be there too + for (Action action : Action.values()) { + Assert.assertTrue( + permissions.stream() + .filter(ra -> Objects.equals(customType, ra.getResource().getType())) + .anyMatch(ra -> action == ra.getAction() && ".*".equals(ra.getResource().getName())) + ); + } } } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java index 1618e6107907..a1b9149be6ac 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java @@ -120,7 +120,7 @@ public ValidationResult validate(final String sql) throws SqlParseException, Val throw new ValidationException(e); } SqlResourceCollectorShuttle resourceCollectorShuttle = - new SqlResourceCollectorShuttle(validator, frameworkConfig.getDefaultSchema().getName()); + new SqlResourceCollectorShuttle(validator, plannerContext); validated.accept(resourceCollectorShuttle); plannerContext.setResources(resourceCollectorShuttle.getResources()); return new ValidationResult(resourceCollectorShuttle.getResources()); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java index 59d4bd8f0194..c69ab06002b3 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java @@ -37,6 +37,7 @@ import org.joda.time.DateTimeZone; import org.joda.time.Interval; +import javax.annotation.Nullable; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -68,6 +69,7 @@ public class PlannerContext private final ExprMacroTable macroTable; private final PlannerConfig plannerConfig; private final DateTime localNow; + private final Map schemaResourceTypes; private final Map queryContext; private final String sqlQueryId; private final boolean stringifyArrays; @@ -87,12 +89,14 @@ private PlannerContext( final PlannerConfig plannerConfig, final DateTime localNow, final boolean stringifyArrays, + final Map schemaResourceTypes, final Map queryContext ) { this.operatorTable = operatorTable; this.macroTable = macroTable; this.plannerConfig = Preconditions.checkNotNull(plannerConfig, "plannerConfig"); + this.schemaResourceTypes = schemaResourceTypes; this.queryContext = queryContext != null ? new HashMap<>(queryContext) : new HashMap<>(); this.localNow = Preconditions.checkNotNull(localNow, "localNow"); this.stringifyArrays = stringifyArrays; @@ -109,6 +113,7 @@ public static PlannerContext create( final DruidOperatorTable operatorTable, final ExprMacroTable macroTable, final PlannerConfig plannerConfig, + final Map schemaResourceTypes, final Map queryContext ) { @@ -150,6 +155,7 @@ public static PlannerContext create( plannerConfig.withOverrides(queryContext), utcNow.withZone(timeZone), stringifyArrays, + schemaResourceTypes, queryContext ); } @@ -179,6 +185,12 @@ public DateTimeZone getTimeZone() return localNow.getZone(); } + @Nullable + public String getSchemaResourceType(String schema) + { + return schemaResourceTypes.get(schema); + } + public Map getQueryContext() { return queryContext; diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java index 9f86eda98bfd..394578627443 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Maps; import com.google.inject.Inject; import org.apache.calcite.avatica.util.Casing; import org.apache.calcite.avatica.util.Quoting; @@ -45,9 +46,11 @@ import org.apache.druid.server.security.NoopEscalator; import org.apache.druid.sql.calcite.rel.QueryMaker; import org.apache.druid.sql.calcite.schema.DruidSchemaName; +import org.apache.druid.sql.calcite.schema.NamedSchema; import java.util.Map; import java.util.Properties; +import java.util.Set; public class PlannerFactory { @@ -61,6 +64,7 @@ public class PlannerFactory .build(); private final SchemaPlus rootSchema; + private final Map schemaResourceTypes; private final QueryLifecycleFactory queryLifecycleFactory; private final DruidOperatorTable operatorTable; private final ExprMacroTable macroTable; @@ -72,6 +76,7 @@ public class PlannerFactory @Inject public PlannerFactory( final SchemaPlus rootSchema, + final Set schemas, final QueryLifecycleFactory queryLifecycleFactory, final DruidOperatorTable operatorTable, final ExprMacroTable macroTable, @@ -89,6 +94,11 @@ public PlannerFactory( this.authorizerMapper = authorizerMapper; this.jsonMapper = jsonMapper; this.druidSchemaName = druidSchemaName; + + this.schemaResourceTypes = Maps.newHashMapWithExpectedSize(schemas.size()); + for (NamedSchema schema : schemas) { + schemaResourceTypes.put(schema.getSchemaName(), schema.getSchemaResourceType()); + } } /** @@ -100,6 +110,7 @@ public DruidPlanner createPlanner(final Map queryContext) operatorTable, macroTable, plannerConfig, + schemaResourceTypes, queryContext ); final QueryMaker queryMaker = new QueryMaker(queryLifecycleFactory, plannerContext, jsonMapper); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java index aba6689aaf42..f4584c9906d6 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java @@ -28,7 +28,6 @@ import org.apache.calcite.sql.validate.SqlValidatorTable; import org.apache.druid.server.security.Resource; import org.apache.druid.server.security.ResourceType; -import org.apache.druid.sql.calcite.schema.NamedViewSchema; import java.util.HashSet; import java.util.List; @@ -45,14 +44,14 @@ public class SqlResourceCollectorShuttle extends SqlShuttle { private final Set resources; + private final PlannerContext plannerContext; private final SqlValidator validator; - private final String druidSchemaName; - public SqlResourceCollectorShuttle(SqlValidator validator, String druidSchemaName) + public SqlResourceCollectorShuttle(SqlValidator validator, PlannerContext plannerContext) { this.validator = validator; this.resources = new HashSet<>(); - this.druidSchemaName = druidSchemaName; + this.plannerContext = plannerContext; } @Override @@ -69,10 +68,9 @@ public SqlNode visit(SqlIdentifier id) // 'schema'.'identifier' if (qualifiedNameParts.size() == 2) { final String schema = qualifiedNameParts.get(0); - if (druidSchemaName.equals(schema)) { - resources.add(new Resource(qualifiedNameParts.get(1), ResourceType.DATASOURCE)); - } else if (NamedViewSchema.NAME.equals(schema)) { - resources.add(new Resource(qualifiedNameParts.get(1), ResourceType.VIEW)); + final String resourceType = plannerContext.getSchemaResourceType(schema); + if (resourceType != null) { + resources.add(new Resource(qualifiedNameParts.get(1), resourceType)); } } } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java index a48ccf23d648..4110c721d924 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java @@ -21,17 +21,18 @@ import com.google.inject.Inject; import org.apache.calcite.schema.Schema; +import org.apache.druid.server.security.ResourceType; /** * The schema for Druid tables to be accessible via SQL. */ -class NamedDruidSchema implements NamedSchema +public class NamedDruidSchema implements NamedSchema { private final DruidSchema druidSchema; private final String druidSchemaName; @Inject - NamedDruidSchema(DruidSchema druidSchema, @DruidSchemaName String druidSchemaName) + public NamedDruidSchema(DruidSchema druidSchema, @DruidSchemaName String druidSchemaName) { this.druidSchema = druidSchema; this.druidSchemaName = druidSchemaName; @@ -43,6 +44,12 @@ public String getSchemaName() return druidSchemaName; } + @Override + public String getSchemaResourceType() + { + return ResourceType.DATASOURCE; + } + @Override public Schema getSchema() { diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java index a1448661be2a..eb91949126b7 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java @@ -27,12 +27,12 @@ */ public class NamedLookupSchema implements NamedSchema { - private static final String NAME = "lookup"; + public static final String NAME = "lookup"; private final LookupSchema lookupSchema; @Inject - NamedLookupSchema(LookupSchema lookupSchema) + public NamedLookupSchema(LookupSchema lookupSchema) { this.lookupSchema = lookupSchema; } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java index c4ba8271eb80..8e2c6b4ed9e3 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java @@ -21,6 +21,8 @@ import org.apache.calcite.schema.Schema; +import javax.annotation.Nullable; + /** * This interface provides everything that is needed to register a {@link Schema} as a sub schema to the root schema * of Druid SQL. The {@link #getSchemaName()} will be used to access the provided {@link Schema} via SQL. @@ -32,6 +34,12 @@ public interface NamedSchema */ String getSchemaName(); + @Nullable + default String getSchemaResourceType() + { + return null; + } + /** * @return The Schema that Calcite should use. */ diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java index 1bb02233def1..3d42f47e0673 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java @@ -25,14 +25,14 @@ /** * The schema for Druid system tables to be accessible via SQL. */ -class NamedSystemSchema implements NamedSchema +public class NamedSystemSchema implements NamedSchema { - private static final String NAME = "sys"; + public static final String NAME = "sys"; private final SystemSchema systemSchema; @Inject - NamedSystemSchema(SystemSchema systemSchema) + public NamedSystemSchema(SystemSchema systemSchema) { this.systemSchema = systemSchema; } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java index 06959afa44be..cb68e3e2ec26 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java @@ -21,6 +21,7 @@ import com.google.inject.Inject; import org.apache.calcite.schema.Schema; +import org.apache.druid.server.security.ResourceType; public class NamedViewSchema implements NamedSchema { @@ -28,7 +29,7 @@ public class NamedViewSchema implements NamedSchema private final ViewSchema viewSchema; @Inject - NamedViewSchema(ViewSchema viewSchema) + public NamedViewSchema(ViewSchema viewSchema) { this.viewSchema = viewSchema; } @@ -39,6 +40,12 @@ public String getSchemaName() return NAME; } + @Override + public String getSchemaResourceType() + { + return ResourceType.VIEW; + } + @Override public Schema getSchema() { diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java index 3278bb6a80f3..a210fa3468de 100644 --- a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java +++ b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java @@ -30,6 +30,7 @@ import com.google.inject.Binder; import com.google.inject.Injector; import com.google.inject.Module; +import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import org.apache.calcite.avatica.AvaticaClientRuntimeException; import org.apache.calcite.avatica.Meta; @@ -65,6 +66,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.schema.DruidSchemaName; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.QueryLogHook; @@ -168,7 +170,7 @@ public void setUp() throws Exception final PlannerConfig plannerConfig = new PlannerConfig(); final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); - final SchemaPlus rootSchema = + final Pair> rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, CalciteTests.TEST_AUTHORIZER_MAPPER); testRequestLogger = new TestRequestLogger(); @@ -187,7 +189,10 @@ public void configure(Binder binder) binder.bind(AuthorizerMapper.class).toInstance(CalciteTests.TEST_AUTHORIZER_MAPPER); binder.bind(Escalator.class).toInstance(CalciteTests.TEST_AUTHENTICATOR_ESCALATOR); binder.bind(RequestLogger.class).toInstance(testRequestLogger); - binder.bind(SchemaPlus.class).toInstance(rootSchema); + binder.bind(SchemaPlus.class).toInstance(rootSchema.lhs); + for (NamedSchema schema : rootSchema.rhs) { + Multibinder.newSetBinder(binder, NamedSchema.class).addBinding().toInstance(schema); + } binder.bind(QueryLifecycleFactory.class) .toInstance(CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate)); binder.bind(DruidOperatorTable.class).toInstance(operatorTable); @@ -865,12 +870,13 @@ public int getMaxRowsPerFrame() final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); final List frames = new ArrayList<>(); - SchemaPlus rootSchema = + Pair> rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); DruidMeta smallFrameDruidMeta = new DruidMeta( CalciteTests.createSqlLifecycleFactory( new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, @@ -954,12 +960,13 @@ public int getMinRowsPerFrame() final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); final List frames = new ArrayList<>(); - SchemaPlus rootSchema = + Pair> rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); DruidMeta smallFrameDruidMeta = new DruidMeta( CalciteTests.createSqlLifecycleFactory( new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java index 44002866a32c..10fad022da39 100644 --- a/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java +++ b/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java @@ -26,6 +26,7 @@ import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; import org.apache.druid.java.util.common.DateTimes; +import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.io.Closer; import org.apache.druid.math.expr.ExprMacroTable; import org.apache.druid.query.QueryRunnerFactoryConglomerate; @@ -36,6 +37,7 @@ import org.apache.druid.sql.calcite.planner.DruidOperatorTable; import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.QueryLogHook; @@ -52,6 +54,7 @@ import java.io.IOException; import java.util.Collections; import java.util.List; +import java.util.Set; public class DruidStatementTest extends CalciteTestBase { @@ -87,10 +90,11 @@ public void setUp() throws Exception final PlannerConfig plannerConfig = new PlannerConfig(); final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); - SchemaPlus rootSchema = + Pair> rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); final PlannerFactory plannerFactory = new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java index 876ea5c91443..8e1d755ef26a 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java @@ -29,6 +29,7 @@ import org.apache.druid.hll.VersionOneHyperLogLogCollector; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.java.util.common.Intervals; +import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.granularity.Granularity; import org.apache.druid.java.util.common.io.Closer; @@ -80,6 +81,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.planner.PlannerFactory; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.QueryLogHook; @@ -896,7 +898,7 @@ public SqlLifecycleFactory getSqlLifecycleFactory( { final InProcessViewManager viewManager = new InProcessViewManager(CalciteTests.TEST_AUTHENTICATOR_ESCALATOR, CalciteTests.DRUID_VIEW_MACRO_FACTORY); - SchemaPlus rootSchema = CalciteTests.createMockRootSchema( + Pair> rootSchema = CalciteTests.createMockRootSchema( conglomerate, walker, plannerConfig, @@ -905,7 +907,8 @@ public SqlLifecycleFactory getSqlLifecycleFactory( ); final PlannerFactory plannerFactory = new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java index de788fadc7b9..161e18bf8a8f 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java @@ -25,6 +25,7 @@ import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.tools.RelConversionException; import org.apache.calcite.tools.ValidationException; +import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; @@ -45,6 +46,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.testing.InitializedNullHandlingTest; @@ -61,6 +63,7 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; @RunWith(Parameterized.class) @@ -128,10 +131,11 @@ public static void setupClass() CLOSER.register(WALKER); final PlannerConfig plannerConfig = new PlannerConfig(); - final SchemaPlus rootSchema = + final Pair> rootSchema = CalciteTests.createMockRootSchema(CONGLOMERATE, WALKER, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); PLANNER_FACTORY = new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(WALKER, CONGLOMERATE), CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java index dc56fe7bd711..17ba1fc2511e 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java @@ -67,6 +67,7 @@ class ExpressionTestHelper CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), new PlannerConfig(), + CalciteTests.createSchemaResourceTypes(), ImmutableMap.of() ); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java index e081e1fd0617..3ec172498296 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java @@ -32,6 +32,7 @@ import org.apache.druid.math.expr.ExprMacroTable; import org.apache.druid.server.QueryLifecycleFactory; import org.apache.druid.server.security.AuthorizerMapper; +import org.apache.druid.server.security.ResourceType; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; import org.apache.druid.sql.calcite.expression.SqlOperatorConversion; import org.apache.druid.sql.calcite.schema.DruidSchemaName; @@ -87,6 +88,8 @@ public void setUp() EasyMock.expect(druidSchema2.getSchema()).andStubReturn(schema2); EasyMock.expect(druidSchema1.getSchemaName()).andStubReturn(SCHEMA_1); EasyMock.expect(druidSchema2.getSchemaName()).andStubReturn(SCHEMA_2); + EasyMock.expect(druidSchema1.getSchemaResourceType()).andStubReturn(ResourceType.DATASOURCE); + EasyMock.expect(druidSchema2.getSchemaResourceType()).andStubReturn("test"); EasyMock.replay(druidSchema1, druidSchema2); calciteSchemas = ImmutableSet.of(druidSchema1, druidSchema2); aggregators = ImmutableSet.of(); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java index 4e394825ee4a..bf2782f6867d 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java @@ -54,6 +54,7 @@ import org.apache.druid.guice.ExpressionModule; import org.apache.druid.guice.annotations.Json; import org.apache.druid.java.util.common.DateTimes; +import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.emitter.core.NoopEmitter; import org.apache.druid.java.util.emitter.service.ServiceEmitter; import org.apache.druid.java.util.http.client.HttpClient; @@ -118,6 +119,11 @@ import org.apache.druid.sql.calcite.schema.InformationSchema; import org.apache.druid.sql.calcite.schema.LookupSchema; import org.apache.druid.sql.calcite.schema.MetadataSegmentView; +import org.apache.druid.sql.calcite.schema.NamedDruidSchema; +import org.apache.druid.sql.calcite.schema.NamedLookupSchema; +import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.NamedSystemSchema; +import org.apache.druid.sql.calcite.schema.NamedViewSchema; import org.apache.druid.sql.calcite.schema.SystemSchema; import org.apache.druid.sql.calcite.schema.ViewSchema; import org.apache.druid.sql.calcite.view.DruidViewMacroFactory; @@ -131,7 +137,6 @@ import org.joda.time.chrono.ISOChronology; import javax.annotation.Nullable; - import java.io.File; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -165,9 +170,6 @@ public class CalciteTests public static final String USERVISITDATASOURCE = "visits"; public static final String DRUID_SCHEMA_NAME = "druid"; public static final String INFORMATION_SCHEMA_NAME = "INFORMATION_SCHEMA"; - public static final String SYSTEM_SCHEMA_NAME = "sys"; - public static final String LOOKUP_SCHEMA_NAME = "lookup"; - public static final String VIEW_SCHEMA_NAME = "view"; public static final String TEST_SUPERUSER_NAME = "testSuperuser"; public static final AuthorizerMapper TEST_AUTHORIZER_MAPPER = new AuthorizerMapper(null) @@ -180,9 +182,9 @@ public Authorizer getAuthorizer(String name) return Access.OK; } - if (resource.getType() == ResourceType.DATASOURCE && resource.getName().equals(FORBIDDEN_DATASOURCE)) { + if (ResourceType.DATASOURCE.equals(resource.getType()) && resource.getName().equals(FORBIDDEN_DATASOURCE)) { return new Access(false); - } else if (resource.getType() == ResourceType.VIEW && resource.getName().equals("forbiddenView")) { + } else if (ResourceType.VIEW.equals(resource.getType()) && resource.getName().equals("forbiddenView")) { return new Access(false); } else { return Access.OK; @@ -1030,6 +1032,14 @@ public static DruidOperatorTable createOperatorTable() } } + public static Map createSchemaResourceTypes() + { + return ImmutableMap.of( + "druid", ResourceType.DATASOURCE, + NamedViewSchema.NAME, ResourceType.VIEW + ); + } + public static InputRow createRow(final ImmutableMap map) { return PARSER.parseBatch((Map) map).get(0); @@ -1123,7 +1133,7 @@ public String findCurrentLeader() ); } - public static SchemaPlus createMockRootSchema( + public static Pair> createMockRootSchema( final QueryRunnerFactoryConglomerate conglomerate, final SpecificSegmentsQuerySegmentWalker walker, final PlannerConfig plannerConfig, @@ -1144,12 +1154,19 @@ public static SchemaPlus createMockRootSchema( LookupSchema lookupSchema = CalciteTests.createMockLookupSchema(); rootSchema.add(CalciteTests.DRUID_SCHEMA_NAME, druidSchema); rootSchema.add(CalciteTests.INFORMATION_SCHEMA_NAME, informationSchema); - rootSchema.add(CalciteTests.SYSTEM_SCHEMA_NAME, systemSchema); - rootSchema.add(CalciteTests.LOOKUP_SCHEMA_NAME, lookupSchema); - return rootSchema; + rootSchema.add(NamedSystemSchema.NAME, systemSchema); + rootSchema.add(NamedLookupSchema.NAME, lookupSchema); + return Pair.of( + rootSchema, + ImmutableSet.of( + new NamedDruidSchema(druidSchema, CalciteTests.DRUID_SCHEMA_NAME), + new NamedSystemSchema(systemSchema), + new NamedLookupSchema(lookupSchema) + ) + ); } - public static SchemaPlus createMockRootSchema( + public static Pair> createMockRootSchema( final QueryRunnerFactoryConglomerate conglomerate, final SpecificSegmentsQuerySegmentWalker walker, final PlannerConfig plannerConfig, @@ -1168,12 +1185,21 @@ public static SchemaPlus createMockRootSchema( CalciteTests.DRUID_SCHEMA_NAME ); LookupSchema lookupSchema = CalciteTests.createMockLookupSchema(); + ViewSchema viewSchema = new ViewSchema(viewManager); rootSchema.add(CalciteTests.DRUID_SCHEMA_NAME, druidSchema); rootSchema.add(CalciteTests.INFORMATION_SCHEMA_NAME, informationSchema); - rootSchema.add(CalciteTests.SYSTEM_SCHEMA_NAME, systemSchema); - rootSchema.add(CalciteTests.LOOKUP_SCHEMA_NAME, lookupSchema); - rootSchema.add(CalciteTests.VIEW_SCHEMA_NAME, new ViewSchema(viewManager)); - return rootSchema; + rootSchema.add(NamedSystemSchema.NAME, systemSchema); + rootSchema.add(NamedLookupSchema.NAME, lookupSchema); + rootSchema.add(NamedViewSchema.NAME, viewSchema); + return Pair.of( + rootSchema, + ImmutableSet.of( + new NamedDruidSchema(druidSchema, CalciteTests.DRUID_SCHEMA_NAME), + new NamedSystemSchema(systemSchema), + new NamedLookupSchema(lookupSchema), + new NamedViewSchema(viewSchema) + ) + ); } /** diff --git a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java index 02f596adbdaa..9aa0aeccaa4c 100644 --- a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java +++ b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java @@ -70,6 +70,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.planner.PlannerFactory; +import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.QueryLogHook; @@ -95,6 +96,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -180,7 +182,7 @@ public boolean shouldSerializeComplexValues() return false; } }; - final SchemaPlus rootSchema = CalciteTests.createMockRootSchema( + final Pair> rootSchema = CalciteTests.createMockRootSchema( conglomerate, walker, plannerConfig, @@ -210,7 +212,8 @@ public boolean shouldSerializeComplexValues() testRequestLogger = new TestRequestLogger(); final PlannerFactory plannerFactory = new PlannerFactory( - rootSchema, + rootSchema.lhs, + rootSchema.rhs, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, From fa1e7a3b6a59d4720bf0afc3e9e3c68c9fd36e97 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Sat, 11 Sep 2021 03:28:01 -0700 Subject: [PATCH 2/5] information schema auth filtering adjustments --- .../sql/calcite/schema/InformationSchema.java | 42 ++++++++++--------- .../druid/sql/calcite/util/CalciteTests.java | 40 ++++++++++-------- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java index 9aa411bb8263..6a25c6f94794 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java @@ -23,7 +23,6 @@ import com.google.common.base.Preconditions; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -49,9 +48,11 @@ import org.apache.druid.java.util.emitter.EmittingLogger; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.segment.column.ValueType; +import org.apache.druid.server.security.Action; import org.apache.druid.server.security.AuthenticationResult; import org.apache.druid.server.security.AuthorizationUtils; import org.apache.druid.server.security.AuthorizerMapper; +import org.apache.druid.server.security.Resource; import org.apache.druid.server.security.ResourceAction; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.table.DruidTable; @@ -62,6 +63,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; public class InformationSchema extends AbstractSchema { @@ -111,26 +113,20 @@ public class InformationSchema extends AbstractSchema .add("JDBC_TYPE", ValueType.LONG) .build(); private static final RelDataTypeSystem TYPE_SYSTEM = RelDataTypeSystem.DEFAULT; - private static final Function> DRUID_TABLE_RA_GENERATOR = datasourceName -> { - return Collections.singletonList(AuthorizationUtils.DATASOURCE_READ_RA_GENERATOR.apply(datasourceName)); - }; - private static final Function> VIEW_TABLE_RA_GENERATOR = viewName -> { - return Collections.singletonList(AuthorizationUtils.VIEW_READ_RA_GENERATOR.apply(viewName)); - }; private static final String INFO_TRUE = "YES"; private static final String INFO_FALSE = "NO"; private final SchemaPlus rootSchema; private final Map tableMap; + private final Map namedSchemaMap; private final AuthorizerMapper authorizerMapper; - private final String druidSchemaName; @Inject public InformationSchema( @Named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA) final SchemaPlus rootSchema, - final AuthorizerMapper authorizerMapper, - @DruidSchemaName String druidSchemaName + Set namedSchemas, + final AuthorizerMapper authorizerMapper ) { this.rootSchema = Preconditions.checkNotNull(rootSchema, "rootSchema"); @@ -140,7 +136,7 @@ TABLES_TABLE, new TablesTable(), COLUMNS_TABLE, new ColumnsTable() ); this.authorizerMapper = authorizerMapper; - this.druidSchemaName = druidSchemaName; + this.namedSchemaMap = namedSchemas.stream().collect(Collectors.toMap(NamedSchema::getSchemaName, s -> s)); } @Override @@ -364,7 +360,7 @@ public Iterable apply(final String functionName) return generateColumnMetadata( schemaName, functionName, - viewMacro.apply(ImmutableList.of()), + viewMacro.apply(Collections.emptyList()), typeFactory ); } @@ -483,18 +479,21 @@ private Set getAuthorizedTableNamesFromSubSchema( final AuthenticationResult authenticationResult ) { - if (druidSchemaName.equals(subSchema.getName())) { - // The "druid" schema's tables represent Druid datasources which require authorization + final NamedSchema schema = namedSchemaMap.get(subSchema.getName()); + if (schema != null && schema.getSchemaResourceType() != null) { return ImmutableSet.copyOf( AuthorizationUtils.filterAuthorizedResources( authenticationResult, subSchema.getTableNames(), - DRUID_TABLE_RA_GENERATOR, + name -> + Collections.singletonList( + new ResourceAction(new Resource(name, schema.getSchemaResourceType()), Action.READ) + ), authorizerMapper ) ); } else { - // for non "druid" schema, we don't filter anything + // for schemas with no resource type, or that are not named schemas, we don't filter anything return subSchema.getTableNames(); } } @@ -504,18 +503,21 @@ private Set getAuthorizedFunctionNamesFromSubSchema( final AuthenticationResult authenticationResult ) { - if (NamedViewSchema.NAME.equals(subSchema.getName())) { - // The "view" subschema functions represent views on Druid datasources + final NamedSchema schema = namedSchemaMap.get(subSchema.getName()); + if (schema != null && schema.getSchemaResourceType() != null) { return ImmutableSet.copyOf( AuthorizationUtils.filterAuthorizedResources( authenticationResult, subSchema.getFunctionNames(), - VIEW_TABLE_RA_GENERATOR, + name -> + Collections.singletonList( + new ResourceAction(new Resource(name, schema.getSchemaResourceType()), Action.READ) + ), authorizerMapper ) ); } else { - // for non "druid" schema, we don't filter anything + // for schemas with no resource type, or that are not named schemas, we don't filter anything return subSchema.getFunctionNames(); } } diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java index bf2782f6867d..8667d732684d 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java @@ -1144,25 +1144,26 @@ public static Pair> createMockRootSchema( SystemSchema systemSchema = CalciteTests.createMockSystemSchema(druidSchema, walker, plannerConfig, authorizerMapper); + LookupSchema lookupSchema = CalciteTests.createMockLookupSchema(); SchemaPlus rootSchema = CalciteSchema.createRootSchema(false, false).plus(); + Set namedSchemas = ImmutableSet.of( + new NamedDruidSchema(druidSchema, CalciteTests.DRUID_SCHEMA_NAME), + new NamedSystemSchema(systemSchema), + new NamedLookupSchema(lookupSchema) + ); InformationSchema informationSchema = new InformationSchema( rootSchema, - authorizerMapper, - CalciteTests.DRUID_SCHEMA_NAME + namedSchemas, + authorizerMapper ); - LookupSchema lookupSchema = CalciteTests.createMockLookupSchema(); rootSchema.add(CalciteTests.DRUID_SCHEMA_NAME, druidSchema); rootSchema.add(CalciteTests.INFORMATION_SCHEMA_NAME, informationSchema); rootSchema.add(NamedSystemSchema.NAME, systemSchema); rootSchema.add(NamedLookupSchema.NAME, lookupSchema); return Pair.of( rootSchema, - ImmutableSet.of( - new NamedDruidSchema(druidSchema, CalciteTests.DRUID_SCHEMA_NAME), - new NamedSystemSchema(systemSchema), - new NamedLookupSchema(lookupSchema) - ) + namedSchemas ); } @@ -1177,15 +1178,23 @@ public static Pair> createMockRootSchema( DruidSchema druidSchema = createMockSchema(conglomerate, walker, plannerConfig, viewManager); SystemSchema systemSchema = CalciteTests.createMockSystemSchema(druidSchema, walker, plannerConfig, authorizerMapper); + + LookupSchema lookupSchema = CalciteTests.createMockLookupSchema(); + ViewSchema viewSchema = new ViewSchema(viewManager); + SchemaPlus rootSchema = CalciteSchema.createRootSchema(false, false).plus(); + Set namedSchemas = ImmutableSet.of( + new NamedDruidSchema(druidSchema, CalciteTests.DRUID_SCHEMA_NAME), + new NamedSystemSchema(systemSchema), + new NamedLookupSchema(lookupSchema), + new NamedViewSchema(viewSchema) + ); InformationSchema informationSchema = new InformationSchema( rootSchema, - authorizerMapper, - CalciteTests.DRUID_SCHEMA_NAME + namedSchemas, + authorizerMapper ); - LookupSchema lookupSchema = CalciteTests.createMockLookupSchema(); - ViewSchema viewSchema = new ViewSchema(viewManager); rootSchema.add(CalciteTests.DRUID_SCHEMA_NAME, druidSchema); rootSchema.add(CalciteTests.INFORMATION_SCHEMA_NAME, informationSchema); rootSchema.add(NamedSystemSchema.NAME, systemSchema); @@ -1193,12 +1202,7 @@ public static Pair> createMockRootSchema( rootSchema.add(NamedViewSchema.NAME, viewSchema); return Pair.of( rootSchema, - ImmutableSet.of( - new NamedDruidSchema(druidSchema, CalciteTests.DRUID_SCHEMA_NAME), - new NamedSystemSchema(systemSchema), - new NamedLookupSchema(lookupSchema), - new NamedViewSchema(viewSchema) - ) + namedSchemas ); } From 81f376b7d377be14ab8b38e08ee4c798810a3848 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Thu, 16 Sep 2021 00:20:28 -0700 Subject: [PATCH 3/5] refactor --- .../druid/benchmark/query/SqlBenchmark.java | 9 +- .../query/SqlExpressionBenchmark.java | 10 +- .../benchmark/query/SqlVsNativeBenchmark.java | 10 +- .../sql/calcite/planner/PlannerContext.java | 15 +- .../sql/calcite/planner/PlannerFactory.java | 18 +-- .../planner/SqlResourceCollectorShuttle.java | 7 +- .../schema/DruidCalciteSchemaModule.java | 7 +- .../calcite/schema/DruidSchemaCatalog.java | 138 +++++++++++++++++- .../sql/calcite/schema/InformationSchema.java | 64 ++++---- .../sql/calcite/schema/NamedDruidSchema.java | 2 +- .../druid/sql/calcite/schema/NamedSchema.java | 2 +- .../sql/calcite/schema/NamedViewSchema.java | 2 +- .../calcite/schema/RootSchemaProvider.java | 31 ++-- .../sql/avatica/DruidAvaticaHandlerTest.java | 18 +-- .../druid/sql/avatica/DruidStatementTest.java | 10 +- .../sql/calcite/BaseCalciteQueryTest.java | 9 +- .../SqlVectorizedExpressionSanityTest.java | 10 +- .../expression/ExpressionTestHelper.java | 15 +- .../planner/CalcitePlannerModuleTest.java | 13 +- .../schema/DruidCalciteSchemaModuleTest.java | 17 +-- .../schema/RootSchemaProviderTest.java | 7 +- .../druid/sql/calcite/util/CalciteTests.java | 39 ++--- .../druid/sql/http/SqlResourceTest.java | 9 +- 23 files changed, 284 insertions(+), 178 deletions(-) diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java index 720f0de40c46..12b717ec002f 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlBenchmark.java @@ -21,9 +21,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; -import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; import org.apache.druid.java.util.common.io.Closer; @@ -47,7 +45,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; -import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.timeline.DataSegment; @@ -423,11 +421,10 @@ public void setup() ); closer.register(walker); - final Pair> rootSchema = + final DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); plannerFactory = new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java index cad156327d6e..3f99b241f7dc 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java @@ -21,9 +21,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; -import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; import org.apache.druid.java.util.common.io.Closer; @@ -43,7 +41,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; -import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.timeline.DataSegment; @@ -66,7 +64,6 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -267,11 +264,10 @@ public void setup() ); closer.register(walker); - final Pair> rootSchema = + final DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); plannerFactory = new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java index 5be5b4942f6f..9e805d8daf00 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlVsNativeBenchmark.java @@ -19,10 +19,8 @@ package org.apache.druid.benchmark.query; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; import org.apache.druid.java.util.common.Intervals; -import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; import org.apache.druid.java.util.common.io.Closer; @@ -44,7 +42,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; -import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.timeline.DataSegment; @@ -64,7 +62,6 @@ import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; -import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -114,11 +111,10 @@ public void setup() final PlannerConfig plannerConfig = new PlannerConfig(); this.walker = closer.register(new SpecificSegmentsQuerySegmentWalker(conglomerate).add(dataSegment, index)); - final Pair> rootSchema = + final DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); plannerFactory = new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java index c69ab06002b3..0ec442e7c6b9 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java @@ -33,6 +33,7 @@ import org.apache.druid.server.security.Access; import org.apache.druid.server.security.AuthenticationResult; import org.apache.druid.server.security.Resource; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Interval; @@ -69,7 +70,7 @@ public class PlannerContext private final ExprMacroTable macroTable; private final PlannerConfig plannerConfig; private final DateTime localNow; - private final Map schemaResourceTypes; + private final DruidSchemaCatalog rootSchema; private final Map queryContext; private final String sqlQueryId; private final boolean stringifyArrays; @@ -89,14 +90,14 @@ private PlannerContext( final PlannerConfig plannerConfig, final DateTime localNow, final boolean stringifyArrays, - final Map schemaResourceTypes, + final DruidSchemaCatalog rootSchema, final Map queryContext ) { this.operatorTable = operatorTable; this.macroTable = macroTable; this.plannerConfig = Preconditions.checkNotNull(plannerConfig, "plannerConfig"); - this.schemaResourceTypes = schemaResourceTypes; + this.rootSchema = rootSchema; this.queryContext = queryContext != null ? new HashMap<>(queryContext) : new HashMap<>(); this.localNow = Preconditions.checkNotNull(localNow, "localNow"); this.stringifyArrays = stringifyArrays; @@ -113,7 +114,7 @@ public static PlannerContext create( final DruidOperatorTable operatorTable, final ExprMacroTable macroTable, final PlannerConfig plannerConfig, - final Map schemaResourceTypes, + final DruidSchemaCatalog rootSchema, final Map queryContext ) { @@ -155,7 +156,7 @@ public static PlannerContext create( plannerConfig.withOverrides(queryContext), utcNow.withZone(timeZone), stringifyArrays, - schemaResourceTypes, + rootSchema, queryContext ); } @@ -186,9 +187,9 @@ public DateTimeZone getTimeZone() } @Nullable - public String getSchemaResourceType(String schema) + public String getSchemaResourceType(String schema, String resourceName) { - return schemaResourceTypes.get(schema); + return rootSchema.getResourceType(schema, resourceName); } public Map getQueryContext() diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java index 394578627443..a96818e2e856 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerFactory.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Maps; import com.google.inject.Inject; import org.apache.calcite.avatica.util.Casing; import org.apache.calcite.avatica.util.Quoting; @@ -30,7 +29,6 @@ import org.apache.calcite.plan.Context; import org.apache.calcite.plan.ConventionTraitDef; import org.apache.calcite.rel.RelCollationTraitDef; -import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.validate.SqlConformance; @@ -45,12 +43,11 @@ import org.apache.druid.server.security.AuthorizerMapper; import org.apache.druid.server.security.NoopEscalator; import org.apache.druid.sql.calcite.rel.QueryMaker; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.schema.DruidSchemaName; -import org.apache.druid.sql.calcite.schema.NamedSchema; import java.util.Map; import java.util.Properties; -import java.util.Set; public class PlannerFactory { @@ -63,8 +60,7 @@ public class PlannerFactory .setConformance(DruidConformance.instance()) .build(); - private final SchemaPlus rootSchema; - private final Map schemaResourceTypes; + private final DruidSchemaCatalog rootSchema; private final QueryLifecycleFactory queryLifecycleFactory; private final DruidOperatorTable operatorTable; private final ExprMacroTable macroTable; @@ -75,8 +71,7 @@ public class PlannerFactory @Inject public PlannerFactory( - final SchemaPlus rootSchema, - final Set schemas, + final DruidSchemaCatalog rootSchema, final QueryLifecycleFactory queryLifecycleFactory, final DruidOperatorTable operatorTable, final ExprMacroTable macroTable, @@ -94,11 +89,6 @@ public PlannerFactory( this.authorizerMapper = authorizerMapper; this.jsonMapper = jsonMapper; this.druidSchemaName = druidSchemaName; - - this.schemaResourceTypes = Maps.newHashMapWithExpectedSize(schemas.size()); - for (NamedSchema schema : schemas) { - schemaResourceTypes.put(schema.getSchemaName(), schema.getSchemaResourceType()); - } } /** @@ -110,7 +100,7 @@ public DruidPlanner createPlanner(final Map queryContext) operatorTable, macroTable, plannerConfig, - schemaResourceTypes, + rootSchema, queryContext ); final QueryMaker queryMaker = new QueryMaker(queryLifecycleFactory, plannerContext, jsonMapper); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java index f4584c9906d6..6b10c7a5f4b6 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java @@ -65,12 +65,13 @@ public SqlNode visit(SqlIdentifier id) // this should not probably be null if the namespace was not null, if (validatorTable != null) { List qualifiedNameParts = validatorTable.getQualifiedName(); - // 'schema'.'identifier' + // 'schema'.'identifier' d if (qualifiedNameParts.size() == 2) { final String schema = qualifiedNameParts.get(0); - final String resourceType = plannerContext.getSchemaResourceType(schema); + final String resourceName = qualifiedNameParts.get(1); + final String resourceType = plannerContext.getSchemaResourceType(schema, resourceName); if (resourceType != null) { - resources.add(new Resource(qualifiedNameParts.get(1), resourceType)); + resources.add(new Resource(resourceName, resourceType)); } } } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModule.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModule.java index 43e8ad7d8910..0a8de2922713 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModule.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModule.java @@ -26,7 +26,6 @@ import com.google.inject.Singleton; import com.google.inject.name.Named; import com.google.inject.name.Names; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.guice.LifecycleModule; import org.apache.druid.sql.guice.SqlBindings; @@ -45,7 +44,7 @@ public void configure(Binder binder) binder.bind(String.class).annotatedWith(DruidSchemaName.class).toInstance(DRUID_SCHEMA_NAME); // Should only be used by the information schema - binder.bind(SchemaPlus.class) + binder.bind(DruidSchemaCatalog.class) .annotatedWith(Names.named(INCOMPLETE_SCHEMA)) .toProvider(RootSchemaProvider.class) .in(Scopes.SINGLETON); @@ -65,9 +64,9 @@ public void configure(Binder binder) @Provides @Singleton - private SchemaPlus getRootSchema(@Named(INCOMPLETE_SCHEMA) SchemaPlus rootSchema, InformationSchema informationSchema) + private DruidSchemaCatalog getRootSchema(@Named(INCOMPLETE_SCHEMA) DruidSchemaCatalog rootSchema, InformationSchema informationSchema) { - rootSchema.add(INFORMATION_SCHEMA_NAME, informationSchema); + rootSchema.getRootSchema().add(INFORMATION_SCHEMA_NAME, informationSchema); return rootSchema; } } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java index d94d15afcdf4..34f15af4baf0 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java @@ -1,2 +1,138 @@ -package org.apache.druid.sql.calcite.schema;public class RootSchema { +/* + * 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.druid.sql.calcite.schema; + +import org.apache.calcite.schema.SchemaPlus; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * The Druid 'catalog', containing information about all Druid schemas which are available. This packages both the 'root + * level' Calcite {@link SchemaPlus} and a map of the {@link NamedSchema} which were used to populate it, keyed by + * {@link NamedSchema#getSchemaName()}. + * + * The {@link #rootSchema} is a top level Calcite schema, which contains all {@link NamedSchema#getSchema()} and + * {@link InformationSchema} added as sub-schemas, and this class provides convenience methods to do things like + * fetch a specific {@link SchemaPlus} by name or list the set of all schemas available, and is used during query + * planning and execution. + * + * {@link #namedSchemas} contains all {@link NamedSchema}, which should be everything except {@link InformationSchema}. + * These are used primarily for {@link #getResourceType(String, String)}, which given the name of a table or function + * that belongs to some {@link NamedSchema}, lookup the most appropriate value to use for + * {@link org.apache.druid.server.security.Resource#getType()} to use for authorization. + */ +public class DruidSchemaCatalog +{ + private final SchemaPlus rootSchema; + private final Map namedSchemas; + + public DruidSchemaCatalog( + SchemaPlus rootSchema, + Map schemas + ) + { + this.rootSchema = rootSchema; + this.namedSchemas = schemas; + } + + /** + * Root calcite schema, used to plan and execute queries + */ + public SchemaPlus getRootSchema() + { + return rootSchema; + } + + /** + * Get all {@link NamedSchema} which belong to the Druid catalog + */ + public Map getNamedSchemas() + { + return namedSchemas; + } + + /** + * Get a {@link NamedSchema} by {@link NamedSchema#getSchemaName()} + */ + public NamedSchema getNamedSchema(String schemaName) + { + return namedSchemas.get(schemaName); + } + + /** + * Get a specific {@link SchemaPlus} by {@link NamedSchema#getSchemaName()} + */ + public SchemaPlus getSubSchema(String name) + { + return rootSchema.getSubSchema(name); + } + + /** + * Get all sub-schemas defined on {@link #rootSchema} + */ + public Set getSubSchemaNames() + { + return rootSchema.getSubSchemaNames(); + } + + /** + * Given the name of a {@link NamedSchema} and the name of a table or function that belongs to that schema, return + * the appropriate value to use for {@link org.apache.druid.server.security.Resource#getType()} during authorization + */ + @Nullable + public String getResourceType(String schema, String resourceName) + { + if (namedSchemas.containsKey(schema)) { + return namedSchemas.get(schema).getSchemaResourceType(resourceName); + } + return null; + } + + + @Override + public boolean equals(Object o) + { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DruidSchemaCatalog that = (DruidSchemaCatalog) o; + return rootSchema.equals(that.rootSchema) && namedSchemas.equals(that.namedSchemas); + } + + @Override + public int hashCode() + { + return Objects.hash(rootSchema, namedSchemas); + } + + @Override + public String toString() + { + return "DruidSchemaCatalog{" + + "schemas=" + getSubSchemaNames() + + '}'; + } } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java index 6a25c6f94794..96fe42c07160 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java @@ -63,7 +63,6 @@ import java.util.Collections; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; public class InformationSchema extends AbstractSchema { @@ -117,15 +116,13 @@ public class InformationSchema extends AbstractSchema private static final String INFO_TRUE = "YES"; private static final String INFO_FALSE = "NO"; - private final SchemaPlus rootSchema; + private final DruidSchemaCatalog rootSchema; private final Map tableMap; - private final Map namedSchemaMap; private final AuthorizerMapper authorizerMapper; @Inject public InformationSchema( - @Named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA) final SchemaPlus rootSchema, - Set namedSchemas, + @Named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA) final DruidSchemaCatalog rootSchema, final AuthorizerMapper authorizerMapper ) { @@ -136,7 +133,6 @@ TABLES_TABLE, new TablesTable(), COLUMNS_TABLE, new ColumnsTable() ); this.authorizerMapper = authorizerMapper; - this.namedSchemaMap = namedSchemas.stream().collect(Collectors.toMap(NamedSchema::getSchemaName, s -> s)); } @Override @@ -479,23 +475,11 @@ private Set getAuthorizedTableNamesFromSubSchema( final AuthenticationResult authenticationResult ) { - final NamedSchema schema = namedSchemaMap.get(subSchema.getName()); - if (schema != null && schema.getSchemaResourceType() != null) { - return ImmutableSet.copyOf( - AuthorizationUtils.filterAuthorizedResources( - authenticationResult, - subSchema.getTableNames(), - name -> - Collections.singletonList( - new ResourceAction(new Resource(name, schema.getSchemaResourceType()), Action.READ) - ), - authorizerMapper - ) - ); - } else { - // for schemas with no resource type, or that are not named schemas, we don't filter anything - return subSchema.getTableNames(); - } + return getAuthorizedNamesFromNamedSchema( + authenticationResult, + rootSchema.getNamedSchema(subSchema.getName()), + subSchema.getTableNames() + ); } private Set getAuthorizedFunctionNamesFromSubSchema( @@ -503,22 +487,40 @@ private Set getAuthorizedFunctionNamesFromSubSchema( final AuthenticationResult authenticationResult ) { - final NamedSchema schema = namedSchemaMap.get(subSchema.getName()); - if (schema != null && schema.getSchemaResourceType() != null) { + return getAuthorizedNamesFromNamedSchema( + authenticationResult, + rootSchema.getNamedSchema(subSchema.getName()), + subSchema.getFunctionNames() + ); + } + + private Set getAuthorizedNamesFromNamedSchema( + final AuthenticationResult authenticationResult, + final NamedSchema schema, + final Set names + ) + { + if (schema != null) { return ImmutableSet.copyOf( AuthorizationUtils.filterAuthorizedResources( authenticationResult, - subSchema.getFunctionNames(), - name -> - Collections.singletonList( - new ResourceAction(new Resource(name, schema.getSchemaResourceType()), Action.READ) - ), + names, + name -> { + final String resoureType = schema.getSchemaResourceType(name); + if (resoureType != null) { + return Collections.singletonList( + new ResourceAction(new Resource(name, resoureType), Action.READ) + ); + } else { + return Collections.emptyList(); + } + }, authorizerMapper ) ); } else { // for schemas with no resource type, or that are not named schemas, we don't filter anything - return subSchema.getFunctionNames(); + return names; } } } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java index 4110c721d924..2e8de70c2feb 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java @@ -45,7 +45,7 @@ public String getSchemaName() } @Override - public String getSchemaResourceType() + public String getSchemaResourceType(String resourceName) { return ResourceType.DATASOURCE; } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java index 8e2c6b4ed9e3..b40f589dd1fc 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java @@ -35,7 +35,7 @@ public interface NamedSchema String getSchemaName(); @Nullable - default String getSchemaResourceType() + default String getSchemaResourceType(String resourceName) { return null; } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java index cb68e3e2ec26..fb6ae9cae28d 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java @@ -41,7 +41,7 @@ public String getSchemaName() } @Override - public String getSchemaResourceType() + public String getSchemaResourceType(String resourceName) { return ResourceType.VIEW; } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/RootSchemaProvider.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/RootSchemaProvider.java index 595e7ae52295..0c6176335880 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/RootSchemaProvider.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/RootSchemaProvider.java @@ -19,14 +19,15 @@ package org.apache.druid.sql.calcite.schema; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; import com.google.inject.Inject; import com.google.inject.Provider; import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.java.util.common.ISE; -import java.util.HashSet; -import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -37,7 +38,7 @@ * * All the provided schema are added to the rootSchema. */ -public class RootSchemaProvider implements Provider +public class RootSchemaProvider implements Provider { private final Set namedSchemas; @@ -48,18 +49,20 @@ public class RootSchemaProvider implements Provider } @Override - public SchemaPlus get() + public DruidSchemaCatalog get() { - SchemaPlus rootSchema = CalciteSchema.createRootSchema(false, false).plus(); - List schemaNames = namedSchemas.stream() - .map(NamedSchema::getSchemaName) - .collect(Collectors.toList()); - Set uniqueSchemaNames = new HashSet<>(schemaNames); - if (uniqueSchemaNames.size() < schemaNames.size()) { - throw new ISE("Found multiple schemas registered to the same name. " - + "The list of registered schemas are %s", schemaNames); + final SchemaPlus rootSchema = CalciteSchema.createRootSchema(false, false).plus(); + final Map schemasByName = Maps.newHashMapWithExpectedSize(namedSchemas.size()); + for (NamedSchema schema : namedSchemas) { + if (schemasByName.containsKey(schema.getSchemaName())) { + throw new ISE( + "Found multiple schemas registered to the same name. The list of registered schemas are %s", + namedSchemas.stream().map(NamedSchema::getSchemaName).collect(Collectors.toList()) + ); + } + schemasByName.put(schema.getSchemaName(), schema); + rootSchema.add(schema.getSchemaName(), schema.getSchema()); } - namedSchemas.forEach(schema -> rootSchema.add(schema.getSchemaName(), schema.getSchema())); - return rootSchema; + return new DruidSchemaCatalog(rootSchema, ImmutableMap.copyOf(schemasByName)); } } diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java index a210fa3468de..3934665da486 100644 --- a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java +++ b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java @@ -37,7 +37,6 @@ import org.apache.calcite.avatica.MissingResultsException; import org.apache.calcite.avatica.NoSuchStatementException; import org.apache.calcite.avatica.server.AbstractAvaticaHandler; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; import org.apache.druid.guice.GuiceInjectors; import org.apache.druid.guice.LazySingleton; @@ -65,6 +64,7 @@ import org.apache.druid.sql.calcite.planner.DruidOperatorTable; import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.schema.DruidSchemaName; import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTestBase; @@ -170,7 +170,7 @@ public void setUp() throws Exception final PlannerConfig plannerConfig = new PlannerConfig(); final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); - final Pair> rootSchema = + final DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, CalciteTests.TEST_AUTHORIZER_MAPPER); testRequestLogger = new TestRequestLogger(); @@ -189,8 +189,8 @@ public void configure(Binder binder) binder.bind(AuthorizerMapper.class).toInstance(CalciteTests.TEST_AUTHORIZER_MAPPER); binder.bind(Escalator.class).toInstance(CalciteTests.TEST_AUTHENTICATOR_ESCALATOR); binder.bind(RequestLogger.class).toInstance(testRequestLogger); - binder.bind(SchemaPlus.class).toInstance(rootSchema.lhs); - for (NamedSchema schema : rootSchema.rhs) { + binder.bind(DruidSchemaCatalog.class).toInstance(rootSchema); + for (NamedSchema schema : rootSchema.getNamedSchemas().values()) { Multibinder.newSetBinder(binder, NamedSchema.class).addBinding().toInstance(schema); } binder.bind(QueryLifecycleFactory.class) @@ -870,13 +870,12 @@ public int getMaxRowsPerFrame() final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); final List frames = new ArrayList<>(); - Pair> rootSchema = + DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); DruidMeta smallFrameDruidMeta = new DruidMeta( CalciteTests.createSqlLifecycleFactory( new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, @@ -960,13 +959,12 @@ public int getMinRowsPerFrame() final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); final List frames = new ArrayList<>(); - Pair> rootSchema = + DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); DruidMeta smallFrameDruidMeta = new DruidMeta( CalciteTests.createSqlLifecycleFactory( new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java index 10fad022da39..fbfc2f1010c6 100644 --- a/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java +++ b/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java @@ -23,10 +23,8 @@ import com.google.common.collect.Lists; import org.apache.calcite.avatica.ColumnMetaData; import org.apache.calcite.avatica.Meta; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.common.config.NullHandling; import org.apache.druid.java.util.common.DateTimes; -import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.io.Closer; import org.apache.druid.math.expr.ExprMacroTable; import org.apache.druid.query.QueryRunnerFactoryConglomerate; @@ -37,7 +35,7 @@ import org.apache.druid.sql.calcite.planner.DruidOperatorTable; import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; -import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.QueryLogHook; @@ -54,7 +52,6 @@ import java.io.IOException; import java.util.Collections; import java.util.List; -import java.util.Set; public class DruidStatementTest extends CalciteTestBase { @@ -90,11 +87,10 @@ public void setUp() throws Exception final PlannerConfig plannerConfig = new PlannerConfig(); final DruidOperatorTable operatorTable = CalciteTests.createOperatorTable(); final ExprMacroTable macroTable = CalciteTests.createExprMacroTable(); - Pair> rootSchema = + DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(conglomerate, walker, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); final PlannerFactory plannerFactory = new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java index 8e1d755ef26a..45f0eb1fb160 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java @@ -23,13 +23,11 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.apache.calcite.plan.RelOptPlanner; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.annotations.UsedByJUnitParamsRunner; import org.apache.druid.common.config.NullHandling; import org.apache.druid.hll.VersionOneHyperLogLogCollector; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.java.util.common.Intervals; -import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.granularity.Granularity; import org.apache.druid.java.util.common.io.Closer; @@ -81,7 +79,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.planner.PlannerFactory; -import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.QueryLogHook; @@ -898,7 +896,7 @@ public SqlLifecycleFactory getSqlLifecycleFactory( { final InProcessViewManager viewManager = new InProcessViewManager(CalciteTests.TEST_AUTHENTICATOR_ESCALATOR, CalciteTests.DRUID_VIEW_MACRO_FACTORY); - Pair> rootSchema = CalciteTests.createMockRootSchema( + DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema( conglomerate, walker, plannerConfig, @@ -907,8 +905,7 @@ public SqlLifecycleFactory getSqlLifecycleFactory( ); final PlannerFactory plannerFactory = new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java index 161e18bf8a8f..337ffd24cbbf 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/SqlVectorizedExpressionSanityTest.java @@ -21,11 +21,9 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.tools.RelConversionException; import org.apache.calcite.tools.ValidationException; -import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.granularity.Granularities; import org.apache.druid.java.util.common.guava.Sequence; @@ -46,7 +44,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.planner.PlannerResult; -import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.testing.InitializedNullHandlingTest; @@ -63,7 +61,6 @@ import java.io.IOException; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; @RunWith(Parameterized.class) @@ -131,11 +128,10 @@ public static void setupClass() CLOSER.register(WALKER); final PlannerConfig plannerConfig = new PlannerConfig(); - final Pair> rootSchema = + final DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema(CONGLOMERATE, WALKER, plannerConfig, AuthTestUtils.TEST_AUTHORIZER_MAPPER); PLANNER_FACTORY = new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(WALKER, CONGLOMERATE), CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java index 17ba1fc2511e..3c049b4c3597 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestHelper.java @@ -26,6 +26,7 @@ import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.sql.SqlIntervalQualifier; import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.type.SqlTypeName; @@ -45,8 +46,14 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.rel.VirtualColumnRegistry; +import org.apache.druid.sql.calcite.schema.DruidSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; +import org.apache.druid.sql.calcite.schema.NamedDruidSchema; +import org.apache.druid.sql.calcite.schema.NamedViewSchema; +import org.apache.druid.sql.calcite.schema.ViewSchema; import org.apache.druid.sql.calcite.table.RowSignatures; import org.apache.druid.sql.calcite.util.CalciteTests; +import org.easymock.EasyMock; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Assert; @@ -67,7 +74,13 @@ class ExpressionTestHelper CalciteTests.createOperatorTable(), CalciteTests.createExprMacroTable(), new PlannerConfig(), - CalciteTests.createSchemaResourceTypes(), + new DruidSchemaCatalog( + EasyMock.createMock(SchemaPlus.class), + ImmutableMap.of( + "druid", new NamedDruidSchema(EasyMock.createMock(DruidSchema.class), "druid"), + NamedViewSchema.NAME, new NamedViewSchema(EasyMock.createMock(ViewSchema.class)) + ) + ), ImmutableMap.of() ); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java index 3ec172498296..90dfcbada486 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java @@ -26,7 +26,6 @@ import com.google.inject.Scopes; import com.google.inject.TypeLiteral; import org.apache.calcite.schema.Schema; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.guice.LazySingleton; import org.apache.druid.jackson.JacksonModule; import org.apache.druid.math.expr.ExprMacroTable; @@ -35,6 +34,7 @@ import org.apache.druid.server.security.ResourceType; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; import org.apache.druid.sql.calcite.expression.SqlOperatorConversion; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.schema.DruidSchemaName; import org.apache.druid.sql.calcite.schema.NamedSchema; import org.apache.druid.sql.calcite.util.CalciteTestBase; @@ -72,11 +72,10 @@ public class CalcitePlannerModuleTest extends CalciteTestBase @Mock private AuthorizerMapper authorizerMapper; @Mock - private SchemaPlus rootSchema; + private DruidSchemaCatalog rootSchema; private Set aggregators; private Set operatorConversions; - private Set calciteSchemas; private CalcitePlannerModule target; private Injector injector; @@ -88,10 +87,9 @@ public void setUp() EasyMock.expect(druidSchema2.getSchema()).andStubReturn(schema2); EasyMock.expect(druidSchema1.getSchemaName()).andStubReturn(SCHEMA_1); EasyMock.expect(druidSchema2.getSchemaName()).andStubReturn(SCHEMA_2); - EasyMock.expect(druidSchema1.getSchemaResourceType()).andStubReturn(ResourceType.DATASOURCE); - EasyMock.expect(druidSchema2.getSchemaResourceType()).andStubReturn("test"); + EasyMock.expect(druidSchema1.getSchemaResourceType(EasyMock.anyString())).andStubReturn(ResourceType.DATASOURCE); + EasyMock.expect(druidSchema2.getSchemaResourceType(EasyMock.anyString())).andStubReturn("test"); EasyMock.replay(druidSchema1, druidSchema2); - calciteSchemas = ImmutableSet.of(druidSchema1, druidSchema2); aggregators = ImmutableSet.of(); operatorConversions = ImmutableSet.of(); target = new CalcitePlannerModule(); @@ -100,14 +98,13 @@ public void setUp() binder -> { binder.bind(Validator.class).toInstance(Validation.buildDefaultValidatorFactory().getValidator()); binder.bindScope(LazySingleton.class, Scopes.SINGLETON); - binder.bind(Key.get(new TypeLiteral>(){})).toInstance(calciteSchemas); binder.bind(QueryLifecycleFactory.class).toInstance(queryLifecycleFactory); binder.bind(ExprMacroTable.class).toInstance(macroTable); binder.bind(AuthorizerMapper.class).toInstance(authorizerMapper); binder.bind(String.class).annotatedWith(DruidSchemaName.class).toInstance(DRUID_SCHEMA_NAME); binder.bind(Key.get(new TypeLiteral>(){})).toInstance(aggregators); binder.bind(Key.get(new TypeLiteral>(){})).toInstance(operatorConversions); - binder.bind(SchemaPlus.class).toInstance(rootSchema); + binder.bind(DruidSchemaCatalog.class).toInstance(rootSchema); }, target ); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java index f225fe626269..451e16f4c166 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java @@ -28,7 +28,6 @@ import com.google.inject.Scopes; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.client.InventoryView; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.coordinator.Coordinator; @@ -203,12 +202,12 @@ public void testLookupSchemaIsInjectedAsSingleton() @Test public void testRootSchemaAnnotatedIsInjectedAsSingleton() { - SchemaPlus rootSchema = injector.getInstance( - Key.get(SchemaPlus.class, Names.named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA)) + DruidSchemaCatalog rootSchema = injector.getInstance( + Key.get(DruidSchemaCatalog.class, Names.named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA)) ); Assert.assertNotNull(rootSchema); - SchemaPlus other = injector.getInstance( - Key.get(SchemaPlus.class, Names.named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA)) + DruidSchemaCatalog other = injector.getInstance( + Key.get(DruidSchemaCatalog.class, Names.named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA)) ); Assert.assertSame(other, rootSchema); } @@ -216,10 +215,10 @@ public void testRootSchemaAnnotatedIsInjectedAsSingleton() @Test public void testRootSchemaIsInjectedAsSingleton() { - SchemaPlus rootSchema = injector.getInstance(Key.get(SchemaPlus.class)); + DruidSchemaCatalog rootSchema = injector.getInstance(Key.get(DruidSchemaCatalog.class)); Assert.assertNotNull(rootSchema); - SchemaPlus other = injector.getInstance( - Key.get(SchemaPlus.class, Names.named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA)) + DruidSchemaCatalog other = injector.getInstance( + Key.get(DruidSchemaCatalog.class, Names.named(DruidCalciteSchemaModule.INCOMPLETE_SCHEMA)) ); Assert.assertSame(other, rootSchema); } @@ -227,7 +226,7 @@ public void testRootSchemaIsInjectedAsSingleton() @Test public void testRootSchemaIsInjectedAndHasInformationSchema() { - SchemaPlus rootSchema = injector.getInstance(Key.get(SchemaPlus.class)); + DruidSchemaCatalog rootSchema = injector.getInstance(Key.get(DruidSchemaCatalog.class)); InformationSchema expectedSchema = injector.getInstance(InformationSchema.class); Assert.assertNotNull(rootSchema); Assert.assertSame(expectedSchema, rootSchema.getSubSchema("INFORMATION_SCHEMA").unwrap(InformationSchema.class)); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/schema/RootSchemaProviderTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/schema/RootSchemaProviderTest.java index 71f116997934..6cfe3f2c81a2 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/schema/RootSchemaProviderTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/schema/RootSchemaProviderTest.java @@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableSet; import org.apache.calcite.schema.Schema; -import org.apache.calcite.schema.SchemaPlus; import org.apache.druid.java.util.common.ISE; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.easymock.EasyMock; @@ -72,9 +71,9 @@ public void setUp() @Test public void testGetShouldReturnRootSchemaWithProvidedSchemasRegistered() { - SchemaPlus rootSchema = target.get(); - Assert.assertEquals("", rootSchema.getName()); - Assert.assertFalse(rootSchema.isCacheEnabled()); + DruidSchemaCatalog rootSchema = target.get(); + Assert.assertEquals("", rootSchema.getRootSchema().getName()); + Assert.assertFalse(rootSchema.getRootSchema().isCacheEnabled()); // metadata schema should not be added Assert.assertEquals(druidSchemas.size(), rootSchema.getSubSchemaNames().size()); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java index 8667d732684d..a5e493d7f858 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java @@ -54,7 +54,6 @@ import org.apache.druid.guice.ExpressionModule; import org.apache.druid.guice.annotations.Json; import org.apache.druid.java.util.common.DateTimes; -import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.emitter.core.NoopEmitter; import org.apache.druid.java.util.emitter.service.ServiceEmitter; import org.apache.druid.java.util.http.client.HttpClient; @@ -116,6 +115,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerFactory; import org.apache.druid.sql.calcite.schema.DruidSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.schema.InformationSchema; import org.apache.druid.sql.calcite.schema.LookupSchema; import org.apache.druid.sql.calcite.schema.MetadataSegmentView; @@ -1032,14 +1032,6 @@ public static DruidOperatorTable createOperatorTable() } } - public static Map createSchemaResourceTypes() - { - return ImmutableMap.of( - "druid", ResourceType.DATASOURCE, - NamedViewSchema.NAME, ResourceType.VIEW - ); - } - public static InputRow createRow(final ImmutableMap map) { return PARSER.parseBatch((Map) map).get(0); @@ -1133,7 +1125,7 @@ public String findCurrentLeader() ); } - public static Pair> createMockRootSchema( + public static DruidSchemaCatalog createMockRootSchema( final QueryRunnerFactoryConglomerate conglomerate, final SpecificSegmentsQuerySegmentWalker walker, final PlannerConfig plannerConfig, @@ -1151,23 +1143,24 @@ public static Pair> createMockRootSchema( new NamedSystemSchema(systemSchema), new NamedLookupSchema(lookupSchema) ); + DruidSchemaCatalog catalog = new DruidSchemaCatalog( + rootSchema, + namedSchemas.stream().collect(Collectors.toMap(NamedSchema::getSchemaName, x -> x)) + ); InformationSchema informationSchema = new InformationSchema( - rootSchema, - namedSchemas, + catalog, authorizerMapper ); rootSchema.add(CalciteTests.DRUID_SCHEMA_NAME, druidSchema); rootSchema.add(CalciteTests.INFORMATION_SCHEMA_NAME, informationSchema); rootSchema.add(NamedSystemSchema.NAME, systemSchema); rootSchema.add(NamedLookupSchema.NAME, lookupSchema); - return Pair.of( - rootSchema, - namedSchemas - ); + + return catalog; } - public static Pair> createMockRootSchema( + public static DruidSchemaCatalog createMockRootSchema( final QueryRunnerFactoryConglomerate conglomerate, final SpecificSegmentsQuerySegmentWalker walker, final PlannerConfig plannerConfig, @@ -1189,10 +1182,13 @@ public static Pair> createMockRootSchema( new NamedLookupSchema(lookupSchema), new NamedViewSchema(viewSchema) ); + DruidSchemaCatalog catalog = new DruidSchemaCatalog( + rootSchema, + namedSchemas.stream().collect(Collectors.toMap(NamedSchema::getSchemaName, x -> x)) + ); InformationSchema informationSchema = new InformationSchema( - rootSchema, - namedSchemas, + catalog, authorizerMapper ); rootSchema.add(CalciteTests.DRUID_SCHEMA_NAME, druidSchema); @@ -1200,10 +1196,7 @@ public static Pair> createMockRootSchema( rootSchema.add(NamedSystemSchema.NAME, systemSchema); rootSchema.add(NamedLookupSchema.NAME, lookupSchema); rootSchema.add(NamedViewSchema.NAME, viewSchema); - return Pair.of( - rootSchema, - namedSchemas - ); + return catalog; } /** diff --git a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java index 469fd8b20d53..c7387ac6fb55 100644 --- a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java +++ b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java @@ -28,7 +28,6 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import org.apache.calcite.avatica.SqlType; -import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.tools.RelConversionException; import org.apache.druid.common.config.NullHandling; import org.apache.druid.common.guava.SettableSupplier; @@ -71,7 +70,7 @@ import org.apache.druid.sql.calcite.planner.PlannerConfig; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.planner.PlannerFactory; -import org.apache.druid.sql.calcite.schema.NamedSchema; +import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.apache.druid.sql.calcite.util.CalciteTests; import org.apache.druid.sql.calcite.util.QueryLogHook; @@ -98,7 +97,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -186,7 +184,7 @@ public boolean shouldSerializeComplexValues() return false; } }; - final Pair> rootSchema = CalciteTests.createMockRootSchema( + final DruidSchemaCatalog rootSchema = CalciteTests.createMockRootSchema( conglomerate, walker, plannerConfig, @@ -216,8 +214,7 @@ public boolean shouldSerializeComplexValues() testRequestLogger = new TestRequestLogger(); final PlannerFactory plannerFactory = new PlannerFactory( - rootSchema.lhs, - rootSchema.rhs, + rootSchema, CalciteTests.createMockQueryLifecycleFactory(walker, conglomerate), operatorTable, macroTable, From 1448046fd3ac5cf1d2298b3770d56bc38b542bcf Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Thu, 16 Sep 2021 00:31:31 -0700 Subject: [PATCH 4/5] minor stuff --- .../java/org/apache/druid/security/BasicAuthUtilsTest.java | 7 +------ .../org/apache/druid/sql/calcite/schema/NamedSchema.java | 5 +++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java index a73e94a11c67..60235fbf84bc 100644 --- a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java +++ b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java @@ -90,12 +90,7 @@ public void testPermissionSerdeIsChillAboutUnknownEnumStuffs() throws JsonProces "resourceNamePattern", "foo" ), ImmutableMap.of( - "resourceAction", - ImmutableMap.of( - "resource", - ImmutableMap.of("name", "bar", "type", "CUSTOM"), - "action", "READ" - ), + "resourceAction", customRead, "resourceNamePattern", "bar" ) ) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java index b40f589dd1fc..da951aa62733 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java @@ -34,6 +34,11 @@ public interface NamedSchema */ String getSchemaName(); + /** + * For a given name of a table, function, etc of this schema, return the value most appropriate to use for + * {@link org.apache.druid.server.security.Resource#getType()} for the resource, used during authorization. If this + * method returns null then the resource does not need any authorization. + */ @Nullable default String getSchemaResourceType(String resourceName) { From cdc17d0b23272130b21486870ee588f2745433d0 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Thu, 16 Sep 2021 10:19:42 -0700 Subject: [PATCH 5/5] Update SqlResourceCollectorShuttle.java --- .../druid/sql/calcite/planner/SqlResourceCollectorShuttle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java index 6b10c7a5f4b6..a333b0342da1 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java @@ -65,7 +65,7 @@ public SqlNode visit(SqlIdentifier id) // this should not probably be null if the namespace was not null, if (validatorTable != null) { List qualifiedNameParts = validatorTable.getQualifiedName(); - // 'schema'.'identifier' d + // 'schema'.'identifier' if (qualifiedNameParts.size() == 2) { final String schema = qualifiedNameParts.get(0); final String resourceName = qualifiedNameParts.get(1);