vvysotskyi commented on a change in pull request #1940: DRILL-7406: Update Calcite to 1.21.0 URL: https://github.com/apache/drill/pull/1940#discussion_r361674822
########## File path: exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/conversion/SqlConverter.java ########## @@ -0,0 +1,297 @@ +/* + * 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.planner.sql.conversion; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.calcite.adapter.java.JavaTypeFactory; +import org.apache.calcite.jdbc.DynamicSchema; +import org.apache.calcite.jdbc.JavaTypeFactoryImpl; +import org.apache.calcite.plan.ConventionTraitDef; +import org.apache.calcite.plan.RelOptCluster; +import org.apache.calcite.plan.RelOptCostFactory; +import org.apache.calcite.plan.RelOptPlanner; +import org.apache.calcite.plan.volcano.VolcanoPlanner; +import org.apache.calcite.rel.RelCollationTraitDef; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.RelRoot; +import org.apache.calcite.rel.logical.LogicalProject; +import org.apache.calcite.rel.metadata.JaninoRelMetadataProvider; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.rex.RexBuilder; +import org.apache.calcite.rex.RexNode; +import org.apache.calcite.runtime.Hook; +import org.apache.calcite.schema.SchemaPlus; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlOperatorTable; +import org.apache.calcite.sql.parser.SqlParseException; +import org.apache.calcite.sql.parser.SqlParser; +import org.apache.calcite.sql.util.ChainedSqlOperatorTable; +import org.apache.calcite.sql2rel.SqlToRelConverter; +import org.apache.drill.common.config.DrillConfig; +import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.exec.ExecConstants; +import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry; +import org.apache.drill.exec.ops.QueryContext; +import org.apache.drill.exec.ops.UdfUtilities; +import org.apache.drill.exec.planner.cost.DrillCostBase; +import org.apache.drill.exec.planner.logical.DrillConstExecutor; +import org.apache.drill.exec.planner.logical.DrillRelFactories; +import org.apache.drill.exec.planner.physical.DrillDistributionTraitDef; +import org.apache.drill.exec.planner.physical.PlannerSettings; +import org.apache.drill.exec.planner.sql.DrillConvertletTable; +import org.apache.drill.exec.planner.sql.DrillParserConfig; +import org.apache.drill.exec.planner.sql.SchemaUtilites; +import org.apache.drill.exec.planner.sql.parser.impl.DrillSqlParseException; +import org.apache.drill.exec.planner.types.DrillRelDataTypeSystem; +import org.apache.drill.exec.rpc.user.UserSession; +import org.apache.drill.exec.util.Utilities; + +/** + * Class responsible for managing: + * <ul> + * <li>parsing - {@link #parse(String)}<li/> + * <li>validation - {@link #validate(SqlNode)}<li/> + * <li>conversion to rel - {@link #toRel(SqlNode)} (String)}<li/> + * <ul/> + */ +public class SqlConverter { + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SqlConverter.class); + + private final JavaTypeFactory typeFactory; + private final SqlParser.Config parserConfig; + private final DrillCalciteCatalogReader catalog; + private final PlannerSettings settings; + private final SchemaPlus rootSchema; + private final SchemaPlus defaultSchema; + private final SqlOperatorTable opTab; + private final RelOptCostFactory costFactory; + private final DrillValidator validator; + private final boolean isInnerQuery; + private final boolean isExpandedView; + private final UdfUtilities util; + private final FunctionImplementationRegistry functions; + private final String temporarySchema; + private final UserSession session; + private final DrillConfig drillConfig; + // Allow the default config to be modified using immutable configs + private SqlToRelConverter.Config sqlToRelConverterConfig; + private RelOptCluster cluster; + private VolcanoPlanner planner; + private boolean useRootSchema = false; + + static { + /* + * Sets value to false to avoid simplifying project expressions + * during creating new projects since it may cause changing data mode + * which causes to assertion errors during type validation + */ + Hook.REL_BUILDER_SIMPLIFY.add(Hook.propertyJ(false)); + } + + public SqlConverter(QueryContext context) { + this.settings = context.getPlannerSettings(); + this.util = context; + this.functions = context.getFunctionRegistry(); + this.parserConfig = new DrillParserConfig(settings); + this.sqlToRelConverterConfig = SqlToRelConverter.configBuilder() + .withInSubQueryThreshold((int) settings.getInSubqueryThreshold()) + .withConvertTableAccess(false) + .withExpand(false) + .withRelBuilderFactory(DrillRelFactories.LOGICAL_BUILDER) + .build(); + this.isInnerQuery = false; + this.isExpandedView = false; + this.typeFactory = new JavaTypeFactoryImpl(DrillRelDataTypeSystem.DRILL_REL_DATATYPE_SYSTEM); + this.defaultSchema = context.getNewDefaultSchema(); + this.rootSchema = SchemaUtilites.rootSchema(defaultSchema); + this.temporarySchema = context.getConfig().getString(ExecConstants.DEFAULT_TEMPORARY_WORKSPACE); + this.session = context.getSession(); + this.drillConfig = context.getConfig(); + this.catalog = new DrillCalciteCatalogReader( + rootSchema, + parserConfig.caseSensitive(), + DynamicSchema.from(defaultSchema).path(null), + typeFactory, + drillConfig, + session, + temporarySchema, + this::isUseRootSchema, + this::getDefaultSchema); + this.opTab = new ChainedSqlOperatorTable(Arrays.asList(context.getDrillOperatorTable(), catalog)); + this.costFactory = (settings.useDefaultCosting()) ? null : new DrillCostBase.DrillCostFactory(); + this.validator = new DrillValidator(opTab, catalog, typeFactory, parserConfig.conformance(), session); + validator.setIdentifierExpansion(true); + cluster = null; + } + + SqlConverter(SqlConverter parent, SchemaPlus defaultSchema, SchemaPlus rootSchema, + DrillCalciteCatalogReader catalog) { + this.parserConfig = parent.parserConfig; + this.sqlToRelConverterConfig = parent.sqlToRelConverterConfig; + this.defaultSchema = defaultSchema; + this.functions = parent.functions; + this.util = parent.util; + this.isInnerQuery = true; + this.isExpandedView = true; + this.typeFactory = parent.typeFactory; + this.costFactory = parent.costFactory; + this.settings = parent.settings; + this.rootSchema = rootSchema; + this.catalog = catalog; + this.opTab = parent.opTab; + this.planner = parent.planner; + this.validator = new DrillValidator(opTab, catalog, typeFactory, parserConfig.conformance(), parent.session); + this.temporarySchema = parent.temporarySchema; + this.session = parent.session; + this.drillConfig = parent.drillConfig; + validator.setIdentifierExpansion(true); + this.cluster = parent.cluster; + } + + public SqlNode parse(String sql) { + try { + SqlParser parser = SqlParser.create(sql, parserConfig); + return parser.parseStmt(); + } catch (SqlParseException parseError) { + DrillSqlParseException dex = new DrillSqlParseException(sql, parseError); + UserException.Builder builder = UserException + .parseError(dex) + .addContext(dex.getSqlWithErrorPointer()); + if (isInnerQuery) { + builder.message("Failure parsing a view your query is dependent upon."); + } + throw builder.build(logger); + } + } + + public SqlNode validate(final SqlNode parsedNode) { + try { + return validator.validate(parsedNode); + } catch (RuntimeException e) { + UserException.Builder builder = UserException + .validationError(e); + if (isInnerQuery) { + builder.message("Failure validating a view your query is dependent upon."); + } + throw builder.build(logger); + } + } + + public RelRoot toRel(final SqlNode validatedNode) { + initCluster(initPlanner()); + DrillViewExpander viewExpander = new DrillViewExpander(this); + final SqlToRelConverter sqlToRelConverter = new SqlToRelConverter( + viewExpander, validator, catalog, cluster, + DrillConvertletTable.INSTANCE, sqlToRelConverterConfig); + + boolean topLevelQuery = !isInnerQuery || isExpandedView; + RelRoot rel = sqlToRelConverter.convertQuery(validatedNode, false, topLevelQuery); + + // If extra expressions used in ORDER BY were added to the project list, + // add another project to remove them. + if (topLevelQuery && rel.rel.getRowType().getFieldCount() - rel.fields.size() > 0) { + RexBuilder builder = rel.rel.getCluster().getRexBuilder(); + + RelNode relNode = rel.rel; + List<RexNode> expressions = rel.fields.stream() + .map(f -> builder.makeInputRef(relNode, f.left)) + .collect(Collectors.toList()); + + RelNode project = LogicalProject.create(rel.rel, expressions, rel.validatedRowType); + rel = RelRoot.of(project, rel.validatedRowType, rel.kind); + } + return rel.withRel(sqlToRelConverter.flattenTypes(rel.rel, true)); + } + + public RelDataType getOutputType(SqlNode validatedNode) { + return validator.getValidatedNodeType(validatedNode); + } + + public JavaTypeFactory getTypeFactory() { + return typeFactory; + } + + public DrillConfig getDrillConfig() { + return drillConfig; + } + + public UserSession getSession() { + return session; + } + + public RelOptCostFactory getCostFactory() { + return costFactory; + } + + public SchemaPlus getRootSchema() { + return rootSchema; + } + + public SchemaPlus getDefaultSchema() { + return defaultSchema; + } + + public boolean isCaseSensitive() { + return parserConfig.caseSensitive(); + } + + /** Disallow temporary tables presence in sql statement (ex: in view definitions) */ + public void disallowTemporaryTables() { + catalog.disallowTemporaryTables(); + } + + String getTemporarySchema() { + return temporarySchema; + } + + boolean isUseRootSchema() { Review comment: Please rename it to `useRootSchema` ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services