AbstractAnalyzerTest.java
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.sql.analyzer;
import com.facebook.airlift.json.JsonCodec;
import com.facebook.presto.Session;
import com.facebook.presto.common.QualifiedObjectName;
import com.facebook.presto.common.type.ArrayType;
import com.facebook.presto.common.type.RealType;
import com.facebook.presto.common.type.RowType;
import com.facebook.presto.common.type.StandardTypes;
import com.facebook.presto.connector.informationSchema.InformationSchemaConnector;
import com.facebook.presto.connector.system.SystemConnector;
import com.facebook.presto.execution.warnings.WarningCollectorConfig;
import com.facebook.presto.functionNamespace.SqlInvokedFunctionNamespaceManagerConfig;
import com.facebook.presto.functionNamespace.execution.NoopSqlFunctionExecutor;
import com.facebook.presto.functionNamespace.execution.SqlFunctionExecutors;
import com.facebook.presto.functionNamespace.testing.InMemoryFunctionNamespaceManager;
import com.facebook.presto.metadata.Catalog;
import com.facebook.presto.metadata.CatalogManager;
import com.facebook.presto.metadata.InMemoryNodeManager;
import com.facebook.presto.metadata.InternalNodeManager;
import com.facebook.presto.metadata.Metadata;
import com.facebook.presto.spi.ColumnMetadata;
import com.facebook.presto.spi.ConnectorId;
import com.facebook.presto.spi.ConnectorTableMetadata;
import com.facebook.presto.spi.SchemaTableName;
import com.facebook.presto.spi.WarningCollector;
import com.facebook.presto.spi.analyzer.ViewDefinition;
import com.facebook.presto.spi.connector.Connector;
import com.facebook.presto.spi.connector.ConnectorMetadata;
import com.facebook.presto.spi.connector.ConnectorSplitManager;
import com.facebook.presto.spi.connector.ConnectorTransactionHandle;
import com.facebook.presto.spi.function.FunctionImplementationType;
import com.facebook.presto.spi.function.Parameter;
import com.facebook.presto.spi.function.RoutineCharacteristics;
import com.facebook.presto.spi.function.SqlInvokedFunction;
import com.facebook.presto.spi.security.AccessControl;
import com.facebook.presto.spi.security.AllowAllAccessControl;
import com.facebook.presto.spi.session.PropertyMetadata;
import com.facebook.presto.spi.transaction.IsolationLevel;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.tree.NodeLocation;
import com.facebook.presto.sql.tree.Statement;
import com.facebook.presto.testing.TestingAccessControlManager;
import com.facebook.presto.testing.TestingMetadata;
import com.facebook.presto.testing.TestingWarningCollector;
import com.facebook.presto.testing.TestingWarningCollectorConfig;
import com.facebook.presto.transaction.TransactionManager;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.intellij.lang.annotations.Language;
import org.testng.annotations.BeforeClass;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import static com.facebook.presto.SystemSessionProperties.CHECK_ACCESS_CONTROL_ON_UTILIZED_COLUMNS_ONLY;
import static com.facebook.presto.SystemSessionProperties.CHECK_ACCESS_CONTROL_WITH_SUBFIELDS;
import static com.facebook.presto.common.type.BigintType.BIGINT;
import static com.facebook.presto.common.type.DoubleType.DOUBLE;
import static com.facebook.presto.common.type.TypeSignature.parseTypeSignature;
import static com.facebook.presto.common.type.VarcharType.VARCHAR;
import static com.facebook.presto.metadata.MetadataManager.createTestMetadataManager;
import static com.facebook.presto.operator.scalar.ApplyFunction.APPLY_FUNCTION;
import static com.facebook.presto.spi.ConnectorId.createInformationSchemaConnectorId;
import static com.facebook.presto.spi.ConnectorId.createSystemTablesConnectorId;
import static com.facebook.presto.spi.function.FunctionVersion.notVersioned;
import static com.facebook.presto.spi.function.RoutineCharacteristics.Determinism.DETERMINISTIC;
import static com.facebook.presto.spi.function.RoutineCharacteristics.Language.SQL;
import static com.facebook.presto.spi.function.RoutineCharacteristics.NullCallClause.RETURNS_NULL_ON_NULL_INPUT;
import static com.facebook.presto.spi.session.PropertyMetadata.integerProperty;
import static com.facebook.presto.spi.session.PropertyMetadata.stringProperty;
import static com.facebook.presto.testing.TestingSession.testSessionBuilder;
import static com.facebook.presto.transaction.InMemoryTransactionManager.createTestTransactionManager;
import static com.facebook.presto.transaction.TransactionBuilder.transaction;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static org.testng.Assert.fail;
public class AbstractAnalyzerTest
{
protected static final SqlParser SQL_PARSER = new SqlParser();
protected static final String TPCH_CATALOG = "tpch";
protected static final ConnectorId TPCH_CONNECTOR_ID = new ConnectorId(TPCH_CATALOG);
protected static final String SECOND_CATALOG = "c2";
protected static final ConnectorId SECOND_CONNECTOR_ID = new ConnectorId(SECOND_CATALOG);
protected static final String THIRD_CATALOG = "c3";
protected static final ConnectorId THIRD_CONNECTOR_ID = new ConnectorId(THIRD_CATALOG);
protected static final Session SETUP_SESSION = testSessionBuilder()
.setCatalog("c1")
.setSchema("s1")
.build();
protected static final Session CLIENT_SESSION = testSessionBuilder()
.setCatalog(TPCH_CATALOG)
.setSchema("s1")
.setSystemProperty(CHECK_ACCESS_CONTROL_ON_UTILIZED_COLUMNS_ONLY, "true")
.setSystemProperty(CHECK_ACCESS_CONTROL_WITH_SUBFIELDS, "true")
.build();
protected static final SqlInvokedFunction SQL_FUNCTION_SQUARE = new SqlInvokedFunction(
QualifiedObjectName.valueOf("unittest", "memory", "square"),
ImmutableList.of(new Parameter("x", parseTypeSignature(StandardTypes.BIGINT))),
parseTypeSignature(StandardTypes.BIGINT),
"square",
RoutineCharacteristics.builder()
.setDeterminism(DETERMINISTIC)
.setNullCallClause(RETURNS_NULL_ON_NULL_INPUT)
.build(),
"RETURN x * x",
notVersioned());
protected TransactionManager transactionManager;
protected AccessControl accessControl;
protected Metadata metadata;
@BeforeClass
public void setup()
{
CatalogManager catalogManager = new CatalogManager();
transactionManager = createTestTransactionManager(catalogManager);
accessControl = new TestingAccessControlManager(transactionManager);
metadata = createTestMetadataManager(transactionManager);
metadata.getFunctionAndTypeManager().registerBuiltInFunctions(ImmutableList.of(APPLY_FUNCTION));
metadata.getFunctionAndTypeManager().addFunctionNamespace(
"unittest",
new InMemoryFunctionNamespaceManager(
"unittest",
new SqlFunctionExecutors(
ImmutableMap.of(SQL, FunctionImplementationType.SQL),
new NoopSqlFunctionExecutor()),
new SqlInvokedFunctionNamespaceManagerConfig().setSupportedFunctionLanguages("sql")));
metadata.getFunctionAndTypeManager().createFunction(SQL_FUNCTION_SQUARE, true);
Catalog tpchTestCatalog = createTestingCatalog(TPCH_CATALOG, TPCH_CONNECTOR_ID);
catalogManager.registerCatalog(tpchTestCatalog);
metadata.getAnalyzePropertyManager().addProperties(TPCH_CONNECTOR_ID, tpchTestCatalog.getConnector(TPCH_CONNECTOR_ID).getAnalyzeProperties());
catalogManager.registerCatalog(createTestingCatalog(SECOND_CATALOG, SECOND_CONNECTOR_ID));
catalogManager.registerCatalog(createTestingCatalog(THIRD_CATALOG, THIRD_CONNECTOR_ID));
SchemaTableName table1 = new SchemaTableName("s1", "t1");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table1, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(BIGINT).build(),
ColumnMetadata.builder().setName("c").setType(BIGINT).build(),
ColumnMetadata.builder().setName("d").setType(BIGINT).build())),
false));
SchemaTableName table2 = new SchemaTableName("s1", "t2");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table2, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(BIGINT).build())),
false));
SchemaTableName table3 = new SchemaTableName("s1", "t3");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table3, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(BIGINT).build(),
ColumnMetadata.builder().setName("x").setType(BIGINT).setHidden(true).build())),
false));
// table in different catalog
SchemaTableName table4 = new SchemaTableName("s2", "t4");
inSetupTransaction(session -> metadata.createTable(session, SECOND_CATALOG,
new ConnectorTableMetadata(table4, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build())),
false));
// table with a hidden column
SchemaTableName table5 = new SchemaTableName("s1", "t5");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table5, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(BIGINT).setHidden(true).build())),
false));
// table with a varchar column
SchemaTableName table6 = new SchemaTableName("s1", "t6");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table6, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(VARCHAR).build(),
ColumnMetadata.builder().setName("c").setType(BIGINT).build(),
ColumnMetadata.builder().setName("d").setType(BIGINT).build())),
false));
// table with bigint, double, array of bigints and array of doubles column
SchemaTableName table7 = new SchemaTableName("s1", "t7");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table7, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(DOUBLE).build(),
ColumnMetadata.builder().setName("c").setType(new ArrayType(BIGINT)).build(),
ColumnMetadata.builder().setName("d").setType(new ArrayType(DOUBLE)).build())),
false));
// table with double, array of bigints, real, and bigint
SchemaTableName table8 = new SchemaTableName("s1", "t8");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table8, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(DOUBLE).build(),
ColumnMetadata.builder().setName("b").setType(new ArrayType(BIGINT)).build(),
ColumnMetadata.builder().setName("c").setType(RealType.REAL).build(),
ColumnMetadata.builder().setName("d").setType(BIGINT).build())),
false));
// table with double, array of bigints, real, and bigint
SchemaTableName table9 = new SchemaTableName("s1", "t9");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table9, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(DOUBLE).build(),
ColumnMetadata.builder().setName("b").setType(new ArrayType(BIGINT)).build(),
ColumnMetadata.builder().setName("c").setType(RealType.REAL).build(),
ColumnMetadata.builder().setName("d").setType(BIGINT).build())),
false));
// table with nested struct
SchemaTableName table10 = new SchemaTableName("s1", "t10");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table10, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(RowType.from(ImmutableList.of(
new RowType.Field(Optional.of("w"), BIGINT),
new RowType.Field(Optional.of("x"),
RowType.from(ImmutableList.of(
new RowType.Field(Optional.of("y"), BIGINT),
new RowType.Field(Optional.of("z"), DOUBLE))))))).build(),
ColumnMetadata.builder().setName("c").setType(RowType.from(ImmutableList.of(
new RowType.Field(Optional.of("d"), BIGINT)))).build())),
false));
// table with nested arrays, structs
SchemaTableName table11 = new SchemaTableName("s1", "t11");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table11, ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(new ArrayType(RowType.from(ImmutableList.of(
new RowType.Field(Optional.of("x"), BIGINT),
new RowType.Field(Optional.of("y"), BIGINT))))).build(),
ColumnMetadata.builder().setName("b").setType(RowType.from(ImmutableList.of(
new RowType.Field(Optional.of("w"), BIGINT),
new RowType.Field(Optional.of("x"),
new ArrayType(new ArrayType(RowType.from(ImmutableList.of(new RowType.Field(Optional.of("y"), BIGINT))))))))).build(),
ColumnMetadata.builder().setName("c").setType(RowType.from(ImmutableList.of(
new RowType.Field(
Optional.of("x"),
new ArrayType(RowType.from(ImmutableList.of(
new RowType.Field(Optional.of("x"), BIGINT),
new RowType.Field(Optional.of("y"), BIGINT)))))))).build())),
false));
// table with columns containing special characters
SchemaTableName table12 = new SchemaTableName("s1", "t12");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table12, ImmutableList.of(
ColumnMetadata.builder().setName("a.x").setType(BIGINT).build(),
ColumnMetadata.builder().setName("a&^[x").setType(BIGINT).build())),
false));
// table with bigint, double, array of bigints and array of doubles column
SchemaTableName table13 = new SchemaTableName("s1", "t13");
inSetupTransaction(session -> metadata.createTable(session, TPCH_CATALOG,
new ConnectorTableMetadata(table13, ImmutableList.of(
ColumnMetadata.builder().setName("w").setType(BIGINT).build(),
ColumnMetadata.builder().setName("x").setType(BIGINT).build(),
ColumnMetadata.builder().setName("y").setType(BIGINT).build(),
ColumnMetadata.builder().setName("z").setType(BIGINT).build())),
false));
// valid view referencing table in same schema
String viewData1 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select a from t1",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(new ViewDefinition.ViewColumn("a", BIGINT)),
Optional.of("user"),
false));
ConnectorTableMetadata viewMetadata1 = new ConnectorTableMetadata(
new SchemaTableName("s1", "v1"),
ImmutableList.of(ColumnMetadata.builder().setName("a").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadata1, viewData1, false));
// stale view (different column type)
String viewData2 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select a from t1",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(new ViewDefinition.ViewColumn("a", VARCHAR)),
Optional.of("user"),
false));
ConnectorTableMetadata viewMetadata2 = new ConnectorTableMetadata(
new SchemaTableName("s1", "v2"),
ImmutableList.of(ColumnMetadata.builder().setName("a").setType(VARCHAR).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadata2, viewData2, false));
// view referencing table in different schema from itself and session
String viewData3 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select a from t4",
Optional.of(SECOND_CATALOG),
Optional.of("s2"),
ImmutableList.of(new ViewDefinition.ViewColumn("a", BIGINT)),
Optional.of("owner"),
false));
ConnectorTableMetadata viewMetadata3 = new ConnectorTableMetadata(
new SchemaTableName("s3", "v3"),
ImmutableList.of(ColumnMetadata.builder().setName("a").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, THIRD_CATALOG, viewMetadata3, viewData3, false));
// valid view with uppercase column name
String viewData4 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select A from t1",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(new ViewDefinition.ViewColumn("a", BIGINT)),
Optional.of("user"),
false));
ConnectorTableMetadata viewMetadata4 = new ConnectorTableMetadata(
new SchemaTableName("s1", "v4"),
ImmutableList.of(ColumnMetadata.builder().setName("a").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadata4, viewData4, false));
// recursive view referencing to itself
String viewData5 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select * from v5",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(new ViewDefinition.ViewColumn("a", BIGINT)),
Optional.of("user"),
false));
ConnectorTableMetadata viewMetadata5 = new ConnectorTableMetadata(
new SchemaTableName("s1", "v5"),
ImmutableList.of(ColumnMetadata.builder().setName("a").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadata5, viewData5, false));
String viewDataInvoker1 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select a,b,c from t1",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(
new ViewDefinition.ViewColumn("a", BIGINT),
new ViewDefinition.ViewColumn("b", BIGINT),
new ViewDefinition.ViewColumn("c", BIGINT)),
Optional.empty(),
true));
ConnectorTableMetadata viewMetadataInvoker1 = new ConnectorTableMetadata(
new SchemaTableName("s1", "view_invoker1"),
ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(BIGINT).build(),
ColumnMetadata.builder().setName("c").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadataInvoker1, viewDataInvoker1, false));
String viewDataInvoker2 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select x, y, z from t13",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(
new ViewDefinition.ViewColumn("x", BIGINT),
new ViewDefinition.ViewColumn("y", BIGINT),
new ViewDefinition.ViewColumn("z", BIGINT)),
Optional.empty(),
true));
ConnectorTableMetadata viewMetadataInvoker2 = new ConnectorTableMetadata(
new SchemaTableName("s1", "view_invoker2"),
ImmutableList.of(
ColumnMetadata.builder().setName("x").setType(BIGINT).build(),
ColumnMetadata.builder().setName("y").setType(BIGINT).build(),
ColumnMetadata.builder().setName("z").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadataInvoker2, viewDataInvoker2, false));
String viewDataDefiner1 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select a,b,c from t1",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(
new ViewDefinition.ViewColumn("a", BIGINT),
new ViewDefinition.ViewColumn("b", BIGINT),
new ViewDefinition.ViewColumn("c", BIGINT)),
Optional.of("different_user"),
false));
ConnectorTableMetadata viewMetadataDefiner1 = new ConnectorTableMetadata(
new SchemaTableName("s1", "view_definer1"),
ImmutableList.of(
ColumnMetadata.builder().setName("a").setType(BIGINT).build(),
ColumnMetadata.builder().setName("b").setType(BIGINT).build(),
ColumnMetadata.builder().setName("c").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadataDefiner1, viewDataDefiner1, false));
String viewDataDefiner2 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"select x, y, z from t13",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(
new ViewDefinition.ViewColumn("x", BIGINT),
new ViewDefinition.ViewColumn("y", BIGINT),
new ViewDefinition.ViewColumn("z", BIGINT)),
Optional.of("different_user"),
false));
ConnectorTableMetadata viewMetadataDefiner2 = new ConnectorTableMetadata(
new SchemaTableName("s1", "view_definer2"),
ImmutableList.of(
ColumnMetadata.builder().setName("x").setType(BIGINT).build(),
ColumnMetadata.builder().setName("y").setType(BIGINT).build(),
ColumnMetadata.builder().setName("z").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadataDefiner2, viewDataDefiner2, false));
String viewDataInvokerWithCte1 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
new ViewDefinition(
"WITH cte as (SELECT a + 1 as c1, b +1 as c2, c +1 as c3 FROM t1) SELECT c1, c2, c3 from cte where c1 > 5",
Optional.of(TPCH_CATALOG),
Optional.of("s1"),
ImmutableList.of(
new ViewDefinition.ViewColumn("c1", BIGINT),
new ViewDefinition.ViewColumn("c2", BIGINT),
new ViewDefinition.ViewColumn("c3", BIGINT)),
Optional.empty(),
true));
ConnectorTableMetadata viewMetadataInvokerWithCte1 = new ConnectorTableMetadata(
new SchemaTableName("s1", "view_invoker_with_cte1"),
ImmutableList.of(
ColumnMetadata.builder().setName("c1").setType(BIGINT).build(),
ColumnMetadata.builder().setName("c2").setType(BIGINT).build(),
ColumnMetadata.builder().setName("c3").setType(BIGINT).build()));
inSetupTransaction(session -> metadata.createView(session, TPCH_CATALOG, viewMetadataInvokerWithCte1, viewDataInvokerWithCte1, false));
}
private void inSetupTransaction(Consumer<Session> consumer)
{
transaction(transactionManager, accessControl)
.singleStatement()
.readUncommitted()
.execute(SETUP_SESSION, consumer);
}
protected void analyze(@Language("SQL") String query)
{
analyze(CLIENT_SESSION, query);
}
protected WarningCollector analyzeWithWarnings(@Language("SQL") String query)
{
WarningCollector warningCollector = new TestingWarningCollector(new WarningCollectorConfig(), new TestingWarningCollectorConfig());
analyze(CLIENT_SESSION, warningCollector, query);
return warningCollector;
}
protected void analyze(Session clientSession, @Language("SQL") String query)
{
analyze(clientSession, WarningCollector.NOOP, query);
}
private void analyze(Session clientSession, WarningCollector warningCollector, @Language("SQL") String query)
{
transaction(transactionManager, accessControl)
.singleStatement()
.readUncommitted()
.readOnly()
.execute(clientSession, session -> {
Analyzer analyzer = AbstractAnalyzerTest.createAnalyzer(session, metadata, warningCollector, query);
Statement statement = SQL_PARSER.createStatement(query);
analyzer.analyze(statement);
});
}
protected void assertFails(SemanticErrorCode error, @Language("SQL") String query)
{
assertFails(CLIENT_SESSION, error, query);
}
protected void assertFails(SemanticErrorCode error, int line, int column, @Language("SQL") String query)
{
assertFails(CLIENT_SESSION, error, Optional.of(new NodeLocation(line, column - 1)), query);
}
protected void assertFails(SemanticErrorCode error, String message, @Language("SQL") String query)
{
assertFails(CLIENT_SESSION, error, message, query);
}
protected void assertFails(Session session, SemanticErrorCode error, @Language("SQL") String query)
{
assertFails(session, error, Optional.empty(), query);
}
private void assertFails(Session session, SemanticErrorCode error, Optional<NodeLocation> location, @Language("SQL") String query)
{
try {
analyze(session, query);
fail(format("Expected error %s, but analysis succeeded", error));
}
catch (SemanticException e) {
if (e.getCode() != error) {
fail(format("Expected error %s, but found %s: %s", error, e.getCode(), e.getMessage()), e);
}
if (location.isPresent()) {
NodeLocation expected = location.get();
NodeLocation actual = e.getLocation().get();
if (expected.getLineNumber() != actual.getLineNumber() || expected.getColumnNumber() != actual.getColumnNumber()) {
fail(format(
"Expected error '%s' to occur at line %s, offset %s, but was: line %s, offset %s",
e.getCode(),
expected.getLineNumber(),
expected.getColumnNumber(),
actual.getLineNumber(),
actual.getColumnNumber()));
}
}
}
}
protected void assertFails(Session session, SemanticErrorCode error, String message, @Language("SQL") String query)
{
try {
analyze(session, query);
fail(format("Expected error %s, but analysis succeeded", error));
}
catch (SemanticException e) {
if (e.getCode() != error) {
fail(format("Expected error %s, but found %s: %s", error, e.getCode(), e.getMessage()), e);
}
if (!e.getMessage().matches(message)) {
fail(format("Expected error '%s', but got '%s'", message, e.getMessage()), e);
}
}
}
protected static Analyzer createAnalyzer(Session session, Metadata metadata, WarningCollector warningCollector, String query)
{
return new Analyzer(
session,
metadata,
SQL_PARSER,
new AllowAllAccessControl(),
Optional.empty(),
emptyList(),
emptyMap(),
warningCollector,
query);
}
private Catalog createTestingCatalog(String catalogName, ConnectorId connectorId)
{
ConnectorId systemId = createSystemTablesConnectorId(connectorId);
Connector connector = AbstractAnalyzerTest.createTestingConnector();
InternalNodeManager nodeManager = new InMemoryNodeManager();
return new Catalog(
catalogName,
connectorId,
connector,
createInformationSchemaConnectorId(connectorId),
new InformationSchemaConnector(catalogName, nodeManager, metadata, accessControl, ImmutableList.of()),
systemId,
new SystemConnector(
systemId,
nodeManager,
connector.getSystemTables(),
transactionId -> transactionManager.getConnectorTransaction(transactionId, connectorId)));
}
private static Connector createTestingConnector()
{
return new Connector()
{
private final ConnectorMetadata metadata = new TestingMetadata();
@Override
public ConnectorTransactionHandle beginTransaction(IsolationLevel isolationLevel, boolean readOnly)
{
return new ConnectorTransactionHandle() {};
}
@Override
public ConnectorMetadata getMetadata(ConnectorTransactionHandle transaction)
{
return metadata;
}
@Override
public ConnectorSplitManager getSplitManager()
{
throw new UnsupportedOperationException();
}
@Override
public List<PropertyMetadata<?>> getAnalyzeProperties()
{
return ImmutableList.of(
stringProperty("p1", "test string property", "", false),
integerProperty("p2", "test integer property", 0, false));
}
};
}
}