-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Create QueryPreparer interface #18561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| { | ||
| /** | ||
| * 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 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs API doc There was a problem hiding this comment. Choose a reason for hiding this commentThe 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", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
jainxrohit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| throws ParsingException, PrestoException, SemanticException | ||
| { | ||
| Statement statement = wrappedStatement; | ||
| Optional<String> prepareSql = Optional.empty(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)); | ||
jainxrohit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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)); | ||
jainxrohit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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) { | ||
jainxrohit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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)); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs API doc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1