KYLIN-6046 fix quoted lower-case table name when pushdown Co-authored-by: Xuecheng Shan <xuecheng.shan@kyligence.io>
diff --git a/src/query-common/src/main/java/org/apache/kylin/query/security/HackSelectStarWithColumnACL.java b/src/query-common/src/main/java/org/apache/kylin/query/security/HackSelectStarWithColumnACL.java index da18eb2..64de05e 100644 --- a/src/query-common/src/main/java/org/apache/kylin/query/security/HackSelectStarWithColumnACL.java +++ b/src/query-common/src/main/java/org/apache/kylin/query/security/HackSelectStarWithColumnACL.java
@@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -118,12 +119,14 @@ private final String defaultSchema; private final List<AclTCR> aclTCRList; private final NTableMetadataManager tableMgr; + private final boolean sourceNameCaseSensitiveEnabled; private final boolean isPushdownSelectStarCaseSensitiveEnable; private final boolean isPushdownSelectStarLowerCaseEnable; SelectStarAuthVisitor(String project, String defaultSchema, QueryContext.AclInfo aclInfo) { this.defaultSchema = defaultSchema; KylinConfig config = NProjectManager.getProjectConfig(project); + this.sourceNameCaseSensitiveEnabled = config.getSourceNameCaseSensitiveEnabled(); this.isPushdownSelectStarCaseSensitiveEnable = config.getPushdownSelectStarCaseSensitiveEnable(); this.isPushdownSelectStarLowerCaseEnable = config.getPushdownSelectStarLowercaseEnable(); this.tableMgr = NTableMetadataManager.getInstance(config, project); @@ -210,7 +213,11 @@ List<String> names = operand.names; String schema = names.size() == 1 ? defaultSchema : names.get(0); String table = names.size() == 1 ? names.get(0) : names.get(1); - TableDesc tableDesc = tableMgr.getTableDesc(schema + '.' + table); + String tableMetadataKey = schema + '.' + table; + if (!sourceNameCaseSensitiveEnabled) { + tableMetadataKey = tableMetadataKey.toUpperCase(Locale.ROOT); + } + TableDesc tableDesc = tableMgr.getTableDesc(tableMetadataKey); if (tableDesc == null) { throw new KylinRuntimeException("Failed to parse table: " + operand); }
diff --git a/src/query/src/test/java/org/apache/kylin/query/security/HackSelectStarWithColumnACLTest.java b/src/query/src/test/java/org/apache/kylin/query/security/HackSelectStarWithColumnACLTest.java index ac614bf..fb95f0f 100644 --- a/src/query/src/test/java/org/apache/kylin/query/security/HackSelectStarWithColumnACLTest.java +++ b/src/query/src/test/java/org/apache/kylin/query/security/HackSelectStarWithColumnACLTest.java
@@ -512,6 +512,16 @@ String converted = TRANSFORMER.convert(sql, PROJECT, SCHEMA); Assertions.assertEquals(expected, converted); } + // quoted lower case table name + { + String sql = "select * from \"default\".\"test_kylin_fact\""; + String expected = "select * from ( " + + "select \"TEST_KYLIN_FACT\".\"ORDER_ID\", \"TEST_KYLIN_FACT\".\"PRICE\", " + + "\"TEST_KYLIN_FACT\".\"ITEM_COUNT\" " + + "from \"DEFAULT\".\"TEST_KYLIN_FACT\") as \"test_kylin_fact\""; + String converted = TRANSFORMER.convert(sql, PROJECT, SCHEMA); + Assertions.assertEquals(expected, converted); + } } @Test
diff --git a/src/query/src/test/java/org/apache/kylin/query/security/HackSelectStarWithColumnACLWithTableNameCaseSensitiveTest.java b/src/query/src/test/java/org/apache/kylin/query/security/HackSelectStarWithColumnACLWithTableNameCaseSensitiveTest.java new file mode 100644 index 0000000..2509b3e --- /dev/null +++ b/src/query/src/test/java/org/apache/kylin/query/security/HackSelectStarWithColumnACLWithTableNameCaseSensitiveTest.java
@@ -0,0 +1,85 @@ +/* + * 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.kylin.query.security; + +import static org.apache.kylin.common.util.TestUtils.getTestConfig; + +import org.apache.kylin.common.QueryContext; +import org.apache.kylin.common.exception.KylinRuntimeException; +import org.apache.kylin.guava30.shaded.common.collect.Sets; +import org.apache.kylin.junit.annotation.MetadataInfo; +import org.apache.kylin.metadata.acl.AclTCR; +import org.apache.kylin.metadata.acl.AclTCRManager; +import org.junit.Assert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@MetadataInfo +class HackSelectStarWithColumnACLWithTableNameCaseSensitiveTest { + private static final String PROJECT = "default"; + private static final String SCHEMA = "DEFAULT"; + private static final HackSelectStarWithColumnACL TRANSFORMER = new HackSelectStarWithColumnACL(); + QueryContext current = QueryContext.current(); + + @BeforeEach + void setup() { + getTestConfig().setProperty("kylin.query.security.acl-tcr-enabled", "true"); + getTestConfig().setProperty("kylin.source.name-case-sensitive-enabled", "true"); + prepareBasic(); + current.setAclInfo(new QueryContext.AclInfo("u1", Sets.newHashSet("g1"), false)); + } + + @AfterAll + static void afterAll() { + QueryContext.current().close(); + } + + @Test + void testQuotedLowerCaseTableName() { + //with kylin.source.name-case-sensitive-enabled = true + // table identity is upper-case in metadata, quoted lower-case will throw exception + { + String sql = "select * from \"default\".TEST_KYLIN_FACT"; + Assert.assertThrows(KylinRuntimeException.class, () -> TRANSFORMER.convert(sql, PROJECT, SCHEMA)); + } + // matched metadata + { + String sql = "select * from \"DEFAULT\".TEST_KYLIN_FACT"; + String convertedSql = TRANSFORMER.convert(sql, PROJECT, SCHEMA); + String expected = "select * from ( select \"TEST_KYLIN_FACT\".\"order_id\" from" + + " \"DEFAULT\".\"TEST_KYLIN_FACT\") as \"TEST_KYLIN_FACT\""; + Assert.assertNotNull(expected, convertedSql); + } + } + + private void prepareBasic() { + AclTCRManager manager = AclTCRManager.getInstance(getTestConfig(), PROJECT); + + AclTCR g1a1 = new AclTCR(); + AclTCR.Table g1t1 = new AclTCR.Table(); + AclTCR.ColumnRow g1cr1 = new AclTCR.ColumnRow(); + AclTCR.Column g1c1 = new AclTCR.Column(); + g1c1.add("ORDER_ID"); + g1cr1.setColumn(g1c1); + g1t1.put("DEFAULT.TEST_KYLIN_FACT", g1cr1); + g1a1.setTable(g1t1); + manager.updateAclTCR(g1a1, "g1", false); + } +}