Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions presto-analyzer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,25 @@
<artifactId>presto-parser</artifactId>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>

<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>

<!-- for testing -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.multibindings.MapBinder;

import static com.facebook.presto.sql.analyzer.AnalyzerType.BUILTIN;
import static com.facebook.presto.sql.analyzer.AnalyzerType.NATIVE;
import static com.google.inject.Scopes.SINGLETON;

public class AnalyzerModule
implements Module
{
@Override
public void configure(Binder binder)
{
MapBinder<AnalyzerType, QueryPreparer> queryPreparersByType = MapBinder.newMapBinder(binder, AnalyzerType.class, QueryPreparer.class);
queryPreparersByType.addBinding(BUILTIN).to(BuiltInQueryPreparer.class).in(SINGLETON);
queryPreparersByType.addBinding(NATIVE).to(NativeQueryPreparer.class).in(SINGLETON);

binder.bind(AnalyzerProvider.class).in(SINGLETON);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.presto.spi.PrestoException;

import javax.inject.Inject;

import java.util.Map;

import static com.facebook.presto.spi.StandardErrorCode.UNSUPPORTED_ANALYZER_TYPE;
import static java.util.Objects.requireNonNull;

/**
* This class provides various interfaces for various functionalities in the analyzer.
* This class can be used to get a specific analyzer implementation for a given analyzer type.
*/
public class AnalyzerProvider
{
private final Map<AnalyzerType, QueryPreparer> queryPreparersByType;

@Inject
public AnalyzerProvider(Map<AnalyzerType, QueryPreparer> queryPreparersByType)
{
this.queryPreparersByType = requireNonNull(queryPreparersByType, "queryPreparersByType is null");
}

public QueryPreparer getQueryPreparer(AnalyzerType analyzerType)
{
requireNonNull(analyzerType, "AnalyzerType is null");
if (queryPreparersByType.containsKey(analyzerType)) {
return queryPreparersByType.get(analyzerType);
}

throw new PrestoException(UNSUPPORTED_ANALYZER_TYPE, "Unsupported analyzer type: " + analyzerType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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;

/**
* Presto supports various analyzers to support various analyzer functionality.
*/
public enum AnalyzerType
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs API doc

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

{
/**
* This is for builtin analyzer. This provides default antlr based parser and inbuilt analyzer to produce Analysis object.
*/
BUILTIN,
/**
* This is for C++ based parser and analyzer. This analyzer is currently under development.
* Please avoid using it, as it may corrupt the session.
*/
NATIVE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* 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.presto.common.resourceGroups.QueryType;
import com.facebook.presto.spi.PrestoException;
import com.facebook.presto.spi.PrestoWarning;
import com.facebook.presto.spi.WarningCollector;
import com.facebook.presto.sql.analyzer.utils.StatementUtils;
import com.facebook.presto.sql.parser.ParsingException;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.tree.Execute;
import com.facebook.presto.sql.tree.Explain;
import com.facebook.presto.sql.tree.Expression;
import com.facebook.presto.sql.tree.Statement;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import javax.inject.Inject;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.facebook.presto.common.WarningHandlingLevel.AS_ERROR;
import static com.facebook.presto.spi.StandardErrorCode.NOT_FOUND;
import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED;
import static com.facebook.presto.spi.StandardErrorCode.WARNING_AS_ERROR;
import static com.facebook.presto.sql.SqlFormatter.formatSql;
import static com.facebook.presto.sql.analyzer.ConstantExpressionVerifier.verifyExpressionIsConstant;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_PARAMETER_USAGE;
import static com.facebook.presto.sql.analyzer.utils.ParameterExtractor.getParameterCount;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;

/**
* This query preparer provides builtin functionality. It leverages builtin parser and analyzer.
*/
public class BuiltInQueryPreparer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs API doc

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

implements QueryPreparer
{
private final SqlParser sqlParser;

@Inject
public BuiltInQueryPreparer(SqlParser sqlParser)
{
this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
}

@Override
public BuiltInPreparedQuery prepareQuery(AnalyzerOptions analyzerOptions, String query, Map<String, String> preparedStatements, WarningCollector warningCollector)
throws ParsingException, PrestoException, SemanticException
{
Statement wrappedStatement = sqlParser.createStatement(query, analyzerOptions.getParsingOptions());
if (warningCollector.hasWarnings() && analyzerOptions.getWarningHandlingLevel() == AS_ERROR) {
throw new PrestoException(WARNING_AS_ERROR, format("Warning handling level set to AS_ERROR. Warnings: %n %s",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete "Warning handling level set to AS_ERROR."

warningCollector.getWarnings().stream()
.map(PrestoWarning::getMessage)
.collect(joining(System.lineSeparator()))));
}
return prepareQuery(analyzerOptions, wrappedStatement, preparedStatements);
}

public BuiltInPreparedQuery prepareQuery(AnalyzerOptions analyzerOptions, Statement wrappedStatement, Map<String, String> preparedStatements)
throws ParsingException, PrestoException, SemanticException
{
Statement statement = wrappedStatement;
Optional<String> prepareSql = Optional.empty();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why all these optionals are here. Some, perhaps all, of them can be removed.

if (statement instanceof Execute) {
String preparedStatementName = ((Execute) statement).getName().getValue();
prepareSql = Optional.ofNullable(preparedStatements.get(preparedStatementName));
String query = prepareSql.orElseThrow(() -> new PrestoException(NOT_FOUND, "Prepared statement not found: " + preparedStatementName));
statement = sqlParser.createStatement(query, analyzerOptions.getParsingOptions());
}

if (statement instanceof Explain && ((Explain) statement).isAnalyze()) {
Statement innerStatement = ((Explain) statement).getStatement();
Optional<QueryType> innerQueryType = StatementUtils.getQueryType(innerStatement.getClass());
if (!innerQueryType.isPresent() || innerQueryType.get() == QueryType.DATA_DEFINITION || innerQueryType.get() == QueryType.CONTROL) {
throw new PrestoException(NOT_SUPPORTED, "EXPLAIN ANALYZE doesn't support statement type: " + innerStatement.getClass().getSimpleName());
}
}
List<Expression> parameters = ImmutableList.of();
if (wrappedStatement instanceof Execute) {
parameters = ((Execute) wrappedStatement).getParameters();
}
validateParameters(statement, parameters);
Optional<String> formattedQuery = Optional.empty();
if (analyzerOptions.isLogFormattedQueryEnabled()) {
formattedQuery = Optional.of(getFormattedQuery(statement, parameters));
}
return new BuiltInPreparedQuery(wrappedStatement, statement, parameters, formattedQuery, prepareSql);
}

private static String getFormattedQuery(Statement statement, List<Expression> parameters)
{
String formattedQuery = formatSql(
statement,
parameters.isEmpty() ? Optional.empty() : Optional.of(parameters));
return format("-- Formatted Query:%n%s", formattedQuery);
}

private static void validateParameters(Statement node, List<Expression> parameterValues)
{
int parameterCount = getParameterCount(node);
if (parameterValues.size() != parameterCount) {
throw new SemanticException(INVALID_PARAMETER_USAGE, node, "Incorrect number of parameters: expected %s but found %s", parameterCount, parameterValues.size());
}
for (Expression expression : parameterValues) {
verifyExpressionIsConstant(ImmutableSet.of(), expression);
}
}

public static class BuiltInPreparedQuery
extends PreparedQuery
{
private final Statement statement;
private final Statement wrappedStatement;
private final List<Expression> parameters;

public BuiltInPreparedQuery(Statement wrappedStatement, Statement statement, List<Expression> parameters, Optional<String> formattedQuery, Optional<String> prepareSql)
{
super(formattedQuery, prepareSql);
this.wrappedStatement = requireNonNull(wrappedStatement, "wrappedStatement is null");
this.statement = requireNonNull(statement, "statement is null");
this.parameters = ImmutableList.copyOf(requireNonNull(parameters, "parameters is null"));
}

public Statement getStatement()
{
return statement;
}

public Statement getWrappedStatement()
{
return wrappedStatement;
}

public List<Expression> getParameters()
{
return parameters;
}

public Optional<QueryType> getQueryType()
{
return StatementUtils.getQueryType(statement.getClass());
}

public boolean isTransactionControlStatement()
{
return StatementUtils.isTransactionControlStatement(getStatement());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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 java.util.Optional;

public class NativePreparedQuery
extends PreparedQuery
{
// TODO: Dummy implementation. This should be replaced with native implementation.
public NativePreparedQuery(Optional<String> formattedQuery, Optional<String> prepareSql)
{
super(formattedQuery, prepareSql);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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.presto.spi.PrestoException;
import com.facebook.presto.spi.WarningCollector;
import com.facebook.presto.sql.parser.ParsingException;

import java.util.Map;
import java.util.Optional;

public class NativeQueryPreparer
implements QueryPreparer
{
@Override
public PreparedQuery prepareQuery(AnalyzerOptions analyzerOptions, String query, Map<String, String> preparedStatements, WarningCollector warningCollector)
throws ParsingException, PrestoException, SemanticException
{
return new NativePreparedQuery(Optional.of(query), Optional.of(query));
}
}
Loading