blob: 008730f2bc355b5ce5e32afc4d71fd183bff8ed3 [file] [log] [blame]
/*
* 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.drill.exec.store.ischema;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.apache.drill.PlanTestBase;
import org.apache.drill.exec.store.StoragePluginRegistry;
import org.apache.drill.exec.store.mock.MockBreakageStorage;
import org.apache.drill.test.ClientFixture;
import org.apache.drill.test.ClusterFixture;
import org.apache.drill.test.ClusterMockStorageFixture;
import org.junit.Test;
public class TestInfoSchemaFilterPushDown extends PlanTestBase {
@Test
public void testFilterPushdown_Equal() throws Exception {
final String query = "SELECT * FROM INFORMATION_SCHEMA.`TABLES` WHERE TABLE_SCHEMA='INFORMATION_SCHEMA'";
final String scan = "Scan.*groupscan=\\[TABLES, filter=equal\\(Field=TABLE_SCHEMA,Literal=INFORMATION_SCHEMA\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushdown_NonEqual() throws Exception {
final String query = "SELECT * FROM INFORMATION_SCHEMA.`TABLES` WHERE TABLE_SCHEMA <> 'INFORMATION_SCHEMA'";
final String scan = "Scan.*groupscan=\\[TABLES, filter=not_equal\\(Field=TABLE_SCHEMA,Literal=INFORMATION_SCHEMA\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushdown_Like() throws Exception {
final String query = "SELECT * FROM INFORMATION_SCHEMA.`TABLES` WHERE TABLE_SCHEMA LIKE '%SCH%'";
final String scan = "Scan.*groupscan=\\[TABLES, filter=like\\(Field=TABLE_SCHEMA,Literal=%SCH%\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushdown_LikeWithEscape() throws Exception {
final String query = "SELECT * FROM INFORMATION_SCHEMA.`TABLES` WHERE TABLE_SCHEMA LIKE '%\\\\SCH%' ESCAPE '\\'";
final String scan = "Scan.*groupscan=\\[TABLES, filter=like\\(Field=TABLE_SCHEMA,Literal=%\\\\\\\\SCH%,Literal=\\\\\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushdown_And() throws Exception {
final String query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE " +
"TABLE_SCHEMA = 'sys' AND " +
"TABLE_NAME <> 'version'";
final String scan = "Scan.*groupscan=\\[COLUMNS, filter=booleanand\\(equal\\(Field=TABLE_SCHEMA,Literal=sys\\)," +
"not_equal\\(Field=TABLE_NAME,Literal=version\\)\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushdown_Or() throws Exception {
final String query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE " +
"TABLE_SCHEMA = 'sys' OR " +
"TABLE_NAME <> 'version' OR " +
"TABLE_SCHEMA like '%sdfgjk%'";
final String scan = "Scan.*groupscan=\\[COLUMNS, filter=booleanor\\(equal\\(Field=TABLE_SCHEMA,Literal=sys\\)," +
"not_equal\\(Field=TABLE_NAME,Literal=version\\),like\\(Field=TABLE_SCHEMA,Literal=%sdfgjk%\\)\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushDownWithProject_Equal() throws Exception {
final String query = "SELECT COLUMN_NAME from INFORMATION_SCHEMA.`COLUMNS` WHERE TABLE_SCHEMA = 'INFORMATION_SCHEMA'";
final String scan = "Scan.*groupscan=\\[COLUMNS, filter=equal\\(Field=TABLE_SCHEMA,Literal=INFORMATION_SCHEMA\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushDownWithProject_NotEqual() throws Exception {
final String query = "SELECT COLUMN_NAME from INFORMATION_SCHEMA.`COLUMNS` WHERE TABLE_NAME <> 'TABLES'";
final String scan = "Scan.*groupscan=\\[COLUMNS, filter=not_equal\\(Field=TABLE_NAME,Literal=TABLES\\)";
testHelper(query, scan, false);
}
@Test
public void testFilterPushDownWithProject_Like() throws Exception {
final String query = "SELECT COLUMN_NAME from INFORMATION_SCHEMA.`COLUMNS` WHERE TABLE_NAME LIKE '%BL%'";
final String scan = "Scan.*groupscan=\\[COLUMNS, filter=like\\(Field=TABLE_NAME,Literal=%BL%\\)";
testHelper(query, scan, false);
}
@Test
public void testPartialFilterPushDownWithProject() throws Exception {
final String query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE " +
"TABLE_SCHEMA = 'sys' AND " +
"TABLE_NAME = 'version' AND " +
"COLUMN_NAME like 'commit%s' AND " +
"IS_NULLABLE = 'YES'"; // this is not expected to pushdown into scan
final String scan = "Scan.*groupscan=\\[COLUMNS, " +
"filter=booleanand\\(equal\\(Field=TABLE_SCHEMA,Literal=sys\\),equal\\(Field=TABLE_NAME,Literal=version\\)," +
"like\\(Field=COLUMN_NAME,Literal=commit%s\\)\\)";
testHelper(query, scan, true);
}
/**
* As reported in DRILL-8057, even queries against INFORMATION_SCHEMA that
* included a filter that could be pushed down would be penalised by eager
* schema registration executed on every enabled storage plugin instance.
* This resulted in slow or even failed INFORMATION_SCHEMA schema queries
* when some storage plugin was unresponsive, even if it was not needed for
* the query being run. This test checks that lazy schema registration is
* working by installing a mock storage plugin to act as a canary.
*/
@Test
public void testLazySchemaRegistration() throws Exception {
ClusterMockStorageFixture cluster = ClusterFixture.builder(dirTestWatcher).buildCustomMockStorage();
// This mock storage plugin throws an exception from registerSchemas which
// would have been enough to correctly make this test fail were it not that
// the exception gets swallowed by StoragePluginRegistryImpl so we need to
// inspect a counter instead.
cluster.insertMockStorage("registerSchema canary", true);
ClientFixture client = cluster.clientFixture();
final String query = "SELECT * FROM INFORMATION_SCHEMA.`TABLES` WHERE TABLE_SCHEMA='INFORMATION_SCHEMA'";
client.queryBuilder().sql(query).run();
StoragePluginRegistry spr = cluster.drillbit().getContext().getStorage();
MockBreakageStorage mbs = (MockBreakageStorage) spr.getPlugin("registerSchema canary");
// no attempt to register schemas on the canary should have been made
assertEquals(0, mbs.registerAttemptCount);
}
private void testHelper(final String query, String filterInScan, boolean filterPrelExpected) throws Exception {
String[] expectedPatterns;
String[] excludedPatterns;
if (filterPrelExpected) {
expectedPatterns = new String[] {filterInScan, "Filter"};
excludedPatterns = new String[] {};
} else {
expectedPatterns = new String[] {filterInScan};
excludedPatterns = new String[] {"Filter"};
}
// check plan
testPlanMatchingPatterns(query, expectedPatterns, excludedPatterns);
// run the query
test(query);
}
}