OmniSciDB  ab4938a6a3
SqlToRelConverter.java
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to you under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.calcite.sql2rel;
18 
19 import static org.apache.calcite.sql.SqlUtil.stripAs;
20 
21 import com.google.common.base.Preconditions;
22 import com.google.common.collect.ImmutableList;
23 import com.google.common.collect.ImmutableList.Builder;
24 import com.google.common.collect.ImmutableMap;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.collect.Iterables;
27 import com.google.common.collect.Sets;
28 
29 import org.apache.calcite.avatica.util.Spaces;
30 import org.apache.calcite.linq4j.Ord;
31 import org.apache.calcite.plan.Convention;
32 import org.apache.calcite.plan.RelOptCluster;
33 import org.apache.calcite.plan.RelOptPlanner;
34 import org.apache.calcite.plan.RelOptSamplingParameters;
35 import org.apache.calcite.plan.RelOptTable;
36 import org.apache.calcite.plan.RelOptUtil;
37 import org.apache.calcite.plan.RelTraitSet;
38 import org.apache.calcite.plan.ViewExpanders;
39 import org.apache.calcite.prepare.Prepare;
40 import org.apache.calcite.prepare.RelOptTableImpl;
41 import org.apache.calcite.rel.RelCollation;
42 import org.apache.calcite.rel.RelCollationTraitDef;
43 import org.apache.calcite.rel.RelCollations;
44 import org.apache.calcite.rel.RelFieldCollation;
45 import org.apache.calcite.rel.RelNode;
46 import org.apache.calcite.rel.RelRoot;
47 import org.apache.calcite.rel.RelShuttleImpl;
48 import org.apache.calcite.rel.SingleRel;
49 import org.apache.calcite.rel.core.AggregateCall;
50 import org.apache.calcite.rel.core.Collect;
51 import org.apache.calcite.rel.core.CorrelationId;
52 import org.apache.calcite.rel.core.Filter;
53 import org.apache.calcite.rel.core.Join;
54 import org.apache.calcite.rel.core.JoinInfo;
55 import org.apache.calcite.rel.core.JoinRelType;
56 import org.apache.calcite.rel.core.Project;
57 import org.apache.calcite.rel.core.RelFactories;
58 import org.apache.calcite.rel.core.Sample;
59 import org.apache.calcite.rel.core.Sort;
60 import org.apache.calcite.rel.core.TableScan;
61 import org.apache.calcite.rel.core.Uncollect;
62 import org.apache.calcite.rel.core.Values;
63 import org.apache.calcite.rel.hint.HintStrategyTable;
64 import org.apache.calcite.rel.hint.Hintable;
65 import org.apache.calcite.rel.hint.RelHint;
66 import org.apache.calcite.rel.logical.LogicalAggregate;
67 import org.apache.calcite.rel.logical.LogicalCorrelate;
68 import org.apache.calcite.rel.logical.LogicalFilter;
69 import org.apache.calcite.rel.logical.LogicalIntersect;
70 import org.apache.calcite.rel.logical.LogicalJoin;
71 import org.apache.calcite.rel.logical.LogicalMatch;
72 import org.apache.calcite.rel.logical.LogicalMinus;
73 import org.apache.calcite.rel.logical.LogicalProject;
74 import org.apache.calcite.rel.logical.LogicalSort;
75 import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
76 import org.apache.calcite.rel.logical.LogicalTableModify;
77 import org.apache.calcite.rel.logical.LogicalTableScan;
78 import org.apache.calcite.rel.logical.LogicalUnion;
79 import org.apache.calcite.rel.logical.LogicalValues;
80 import org.apache.calcite.rel.metadata.RelColumnMapping;
81 import org.apache.calcite.rel.metadata.RelMetadataQuery;
82 import org.apache.calcite.rel.stream.Delta;
83 import org.apache.calcite.rel.stream.LogicalDelta;
84 import org.apache.calcite.rel.type.RelDataType;
85 import org.apache.calcite.rel.type.RelDataTypeFactory;
86 import org.apache.calcite.rel.type.RelDataTypeField;
87 import org.apache.calcite.rex.RexBuilder;
88 import org.apache.calcite.rex.RexCall;
89 import org.apache.calcite.rex.RexCallBinding;
90 import org.apache.calcite.rex.RexCorrelVariable;
91 import org.apache.calcite.rex.RexDynamicParam;
92 import org.apache.calcite.rex.RexFieldAccess;
93 import org.apache.calcite.rex.RexFieldCollation;
94 import org.apache.calcite.rex.RexInputRef;
95 import org.apache.calcite.rex.RexLiteral;
96 import org.apache.calcite.rex.RexNode;
97 import org.apache.calcite.rex.RexPatternFieldRef;
98 import org.apache.calcite.rex.RexRangeRef;
99 import org.apache.calcite.rex.RexShuttle;
100 import org.apache.calcite.rex.RexSubQuery;
101 import org.apache.calcite.rex.RexUtil;
102 import org.apache.calcite.rex.RexWindowBound;
103 import org.apache.calcite.schema.ColumnStrategy;
104 import org.apache.calcite.schema.ModifiableTable;
105 import org.apache.calcite.schema.ModifiableView;
106 import org.apache.calcite.schema.Table;
107 import org.apache.calcite.schema.TranslatableTable;
108 import org.apache.calcite.schema.Wrapper;
109 import org.apache.calcite.sql.JoinConditionType;
110 import org.apache.calcite.sql.JoinType;
111 import org.apache.calcite.sql.SqlAggFunction;
112 import org.apache.calcite.sql.SqlBasicCall;
113 import org.apache.calcite.sql.SqlCall;
114 import org.apache.calcite.sql.SqlCallBinding;
115 import org.apache.calcite.sql.SqlDataTypeSpec;
116 import org.apache.calcite.sql.SqlDelete;
117 import org.apache.calcite.sql.SqlDynamicParam;
118 import org.apache.calcite.sql.SqlExplainFormat;
119 import org.apache.calcite.sql.SqlExplainLevel;
120 import org.apache.calcite.sql.SqlFunction;
121 import org.apache.calcite.sql.SqlIdentifier;
122 import org.apache.calcite.sql.SqlInsert;
123 import org.apache.calcite.sql.SqlIntervalQualifier;
124 import org.apache.calcite.sql.SqlJoin;
125 import org.apache.calcite.sql.SqlKind;
126 import org.apache.calcite.sql.SqlLiteral;
127 import org.apache.calcite.sql.SqlMatchRecognize;
128 import org.apache.calcite.sql.SqlMerge;
129 import org.apache.calcite.sql.SqlNode;
130 import org.apache.calcite.sql.SqlNodeList;
131 import org.apache.calcite.sql.SqlNumericLiteral;
132 import org.apache.calcite.sql.SqlOperator;
133 import org.apache.calcite.sql.SqlOperatorTable;
134 import org.apache.calcite.sql.SqlOrderBy;
135 import org.apache.calcite.sql.SqlSampleSpec;
136 import org.apache.calcite.sql.SqlSelect;
137 import org.apache.calcite.sql.SqlSelectKeyword;
138 import org.apache.calcite.sql.SqlSetOperator;
139 import org.apache.calcite.sql.SqlSnapshot;
140 import org.apache.calcite.sql.SqlUnnestOperator;
141 import org.apache.calcite.sql.SqlUpdate;
142 import org.apache.calcite.sql.SqlUtil;
143 import org.apache.calcite.sql.SqlValuesOperator;
144 import org.apache.calcite.sql.SqlWindow;
145 import org.apache.calcite.sql.SqlWith;
146 import org.apache.calcite.sql.SqlWithItem;
147 import org.apache.calcite.sql.fun.SqlCase;
148 import org.apache.calcite.sql.fun.SqlCountAggFunction;
149 import org.apache.calcite.sql.fun.SqlInOperator;
150 import org.apache.calcite.sql.fun.SqlQuantifyOperator;
151 import org.apache.calcite.sql.fun.SqlRowOperator;
152 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
153 import org.apache.calcite.sql.parser.SqlParserPos;
154 import org.apache.calcite.sql.type.SqlReturnTypeInference;
155 import org.apache.calcite.sql.type.SqlTypeName;
156 import org.apache.calcite.sql.type.SqlTypeUtil;
157 import org.apache.calcite.sql.type.TableFunctionReturnTypeInference;
158 import org.apache.calcite.sql.util.SqlBasicVisitor;
159 import org.apache.calcite.sql.util.SqlVisitor;
160 import org.apache.calcite.sql.validate.AggregatingSelectScope;
161 import org.apache.calcite.sql.validate.CollectNamespace;
162 import org.apache.calcite.sql.validate.DelegatingScope;
163 import org.apache.calcite.sql.validate.ListScope;
164 import org.apache.calcite.sql.validate.MatchRecognizeScope;
165 import org.apache.calcite.sql.validate.ParameterScope;
166 import org.apache.calcite.sql.validate.SelectScope;
167 import org.apache.calcite.sql.validate.SqlMonotonicity;
168 import org.apache.calcite.sql.validate.SqlNameMatcher;
169 import org.apache.calcite.sql.validate.SqlQualified;
170 import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction;
171 import org.apache.calcite.sql.validate.SqlUserDefinedTableMacro;
172 import org.apache.calcite.sql.validate.SqlValidator;
173 import org.apache.calcite.sql.validate.SqlValidatorImpl;
174 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
175 import org.apache.calcite.sql.validate.SqlValidatorScope;
176 import org.apache.calcite.sql.validate.SqlValidatorTable;
177 import org.apache.calcite.sql.validate.SqlValidatorUtil;
178 import org.apache.calcite.tools.RelBuilder;
179 import org.apache.calcite.tools.RelBuilderFactory;
180 import org.apache.calcite.util.ImmutableBitSet;
181 import org.apache.calcite.util.ImmutableIntList;
182 import org.apache.calcite.util.Litmus;
183 import org.apache.calcite.util.NlsString;
184 import org.apache.calcite.util.NumberUtil;
185 import org.apache.calcite.util.Pair;
186 import org.apache.calcite.util.Util;
187 import org.apache.calcite.util.trace.CalciteTrace;
188 import org.slf4j.Logger;
189 
190 import java.lang.reflect.Type;
191 import java.math.BigDecimal;
192 import java.util.AbstractList;
193 import java.util.ArrayDeque;
194 import java.util.ArrayList;
195 import java.util.BitSet;
196 import java.util.Collection;
197 import java.util.Collections;
198 import java.util.Deque;
199 import java.util.EnumSet;
200 import java.util.HashMap;
201 import java.util.HashSet;
202 import java.util.List;
203 import java.util.Map;
204 import java.util.Objects;
205 import java.util.Set;
206 import java.util.TreeSet;
207 import java.util.function.BiPredicate;
208 import java.util.function.Supplier;
209 import java.util.stream.Collectors;
210 
220 public class SqlToRelConverter {
221  // ~ Static fields/initializers ---------------------------------------------
222 
223  protected static final Logger SQL2REL_LOGGER = CalciteTrace.getSqlToRelTracer();
224 
225  private static final BigDecimal TWO = BigDecimal.valueOf(2L);
226 
231  public static final int DEFAULT_IN_SUB_QUERY_THRESHOLD = 20;
232 
233  @Deprecated // to be removed before 2.0
235 
236  // ~ Instance fields --------------------------------------------------------
237 
238  protected final SqlValidator validator;
239  protected final RexBuilder rexBuilder;
240  protected final Prepare.CatalogReader catalogReader;
241  protected final RelOptCluster cluster;
242  private SubQueryConverter subQueryConverter;
243  protected final Map<RelNode, Integer> leaves = new HashMap<>();
244  private final List<SqlDynamicParam> dynamicParamSqlNodes = new ArrayList<>();
245  private final SqlOperatorTable opTab;
246  protected final RelDataTypeFactory typeFactory;
247  private final SqlNodeToRexConverter exprConverter;
248  private final HintStrategyTable hintStrategies;
249  private int explainParamCount;
250  public final SqlToRelConverter.Config config;
251  private final RelBuilder relBuilder;
252 
256  private final Map<CorrelationId, DeferredLookup> mapCorrelToDeferred = new HashMap<>();
257 
262  private final Deque<String> datasetStack = new ArrayDeque<>();
263 
269  private final Map<SqlNode, RexNode> mapConvertedNonCorrSubqs = new HashMap<>();
270 
271  public final RelOptTable.ViewExpander viewExpander;
272 
273  // ~ Constructors -----------------------------------------------------------
284  @Deprecated // to be removed before 2.0
285  public SqlToRelConverter(RelOptTable.ViewExpander viewExpander,
286  SqlValidator validator,
287  Prepare.CatalogReader catalogReader,
288  RelOptPlanner planner,
289  RexBuilder rexBuilder,
290  SqlRexConvertletTable convertletTable) {
291  this(viewExpander,
292  validator,
294  RelOptCluster.create(planner, rexBuilder),
295  convertletTable,
296  Config.DEFAULT);
297  }
298 
299  @Deprecated // to be removed before 2.0
300  public SqlToRelConverter(RelOptTable.ViewExpander viewExpander,
301  SqlValidator validator,
302  Prepare.CatalogReader catalogReader,
303  RelOptCluster cluster,
304  SqlRexConvertletTable convertletTable) {
305  this(viewExpander,
306  validator,
308  cluster,
309  convertletTable,
310  Config.DEFAULT);
311  }
312 
313  /* Creates a converter. */
314  public SqlToRelConverter(RelOptTable.ViewExpander viewExpander,
315  SqlValidator validator,
316  Prepare.CatalogReader catalogReader,
317  RelOptCluster cluster,
318  SqlRexConvertletTable convertletTable,
319  Config config) {
320  this.viewExpander = viewExpander;
321  this.opTab = (validator == null) ? SqlStdOperatorTable.instance()
322  : validator.getOperatorTable();
323  this.validator = validator;
325  this.subQueryConverter = new NoOpSubQueryConverter();
326  this.rexBuilder = cluster.getRexBuilder();
327  this.typeFactory = rexBuilder.getTypeFactory();
328  this.exprConverter = new SqlNodeToRexConverterImpl(convertletTable);
329  this.explainParamCount = 0;
330  this.config = new ConfigBuilder().withConfig(config).build();
331  this.relBuilder = config.getRelBuilderFactory().create(cluster, null);
332  this.hintStrategies = config.getHintStrategyTable();
333 
334  cluster.setHintStrategies(this.hintStrategies);
335  this.cluster = Objects.requireNonNull(cluster);
336  }
337 
338  // ~ Methods ----------------------------------------------------------------
339 
343  public RelOptCluster getCluster() {
344  return cluster;
345  }
346 
350  public RexBuilder getRexBuilder() {
351  return rexBuilder;
352  }
353 
360  public int getDynamicParamCount() {
361  return dynamicParamSqlNodes.size();
362  }
363 
370  public RelDataType getDynamicParamType(int index) {
371  SqlNode sqlNode = dynamicParamSqlNodes.get(index);
372  if (sqlNode == null) {
373  throw Util.needToImplement("dynamic param type inference");
374  }
375  return validator.getValidatedNodeType(sqlNode);
376  }
377 
385  public int getDynamicParamCountInExplain(boolean increment) {
386  int retVal = explainParamCount;
387  if (increment) {
389  }
390  return retVal;
391  }
392 
397  public Map<SqlNode, RexNode> getMapConvertedNonCorrSubqs() {
399  }
400 
409  Map<SqlNode, RexNode> alreadyConvertedNonCorrSubqs) {
410  mapConvertedNonCorrSubqs.putAll(alreadyConvertedNonCorrSubqs);
411  }
412 
419  public void setSubQueryConverter(SubQueryConverter converter) {
420  subQueryConverter = converter;
421  }
422 
428  public void setDynamicParamCountInExplain(int explainParamCount) {
429  assert config.isExplain();
430  this.explainParamCount = explainParamCount;
431  }
432 
433  private void checkConvertedType(SqlNode query, RelNode result) {
434  if (query.isA(SqlKind.DML)) {
435  return;
436  }
437  // Verify that conversion from SQL to relational algebra did
438  // not perturb any type information. (We can't do this if the
439  // SQL statement is something like an INSERT which has no
440  // validator type information associated with its result,
441  // hence the namespace check above.)
442  final List<RelDataTypeField> validatedFields =
443  validator.getValidatedNodeType(query).getFieldList();
444  final RelDataType validatedRowType =
445  validator.getTypeFactory().createStructType(Pair.right(validatedFields),
446  SqlValidatorUtil.uniquify(Pair.left(validatedFields),
447  catalogReader.nameMatcher().isCaseSensitive()));
448 
449  final List<RelDataTypeField> convertedFields =
450  result.getRowType().getFieldList().subList(0, validatedFields.size());
451  final RelDataType convertedRowType =
452  validator.getTypeFactory().createStructType(convertedFields);
453 
454  if (!RelOptUtil.equal("validated row type",
455  validatedRowType,
456  "converted row type",
457  convertedRowType,
458  Litmus.IGNORE)) {
459  throw new AssertionError("Conversion to relational algebra failed to "
460  + "preserve datatypes:\n"
461  + "validated type:\n" + validatedRowType.getFullTypeString()
462  + "\nconverted type:\n" + convertedRowType.getFullTypeString() + "\nrel:\n"
463  + RelOptUtil.toString(result));
464  }
465  }
466 
467  public RelNode flattenTypes(RelNode rootRel, boolean restructure) {
468  RelStructuredTypeFlattener typeFlattener = new RelStructuredTypeFlattener(
469  relBuilder, rexBuilder, createToRelContext(ImmutableList.of()), restructure);
470  return typeFlattener.rewrite(rootRel);
471  }
472 
481  public RelNode decorrelate(SqlNode query, RelNode rootRel) {
482  if (!enableDecorrelation()) {
483  return rootRel;
484  }
485  final RelNode result = decorrelateQuery(rootRel);
486  if (result != rootRel) {
487  checkConvertedType(query, result);
488  }
489  return result;
490  }
491 
514  public RelNode trimUnusedFields(boolean ordered, RelNode rootRel) {
515  // Trim fields that are not used by their consumer.
516  if (isTrimUnusedFields()) {
517  final RelFieldTrimmer trimmer = newFieldTrimmer();
518  final List<RelCollation> collations =
519  rootRel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
520  rootRel = trimmer.trim(rootRel);
521  if (!ordered && collations != null && !collations.isEmpty()
522  && !collations.equals(ImmutableList.of(RelCollations.EMPTY))) {
523  final RelTraitSet traitSet =
524  rootRel.getTraitSet().replace(RelCollationTraitDef.INSTANCE, collations);
525  rootRel = rootRel.copy(traitSet, rootRel.getInputs());
526  }
527  if (SQL2REL_LOGGER.isDebugEnabled()) {
528  SQL2REL_LOGGER.debug(RelOptUtil.dumpPlan("Plan after trimming unused fields",
529  rootRel,
530  SqlExplainFormat.TEXT,
531  SqlExplainLevel.EXPPLAN_ATTRIBUTES));
532  }
533  }
534  return rootRel;
535  }
536 
542  protected RelFieldTrimmer newFieldTrimmer() {
543  return new RelFieldTrimmer(validator, relBuilder);
544  }
545 
557  public RelRoot convertQuery(
558  SqlNode query, final boolean needsValidation, final boolean top) {
559  if (needsValidation) {
560  query = validator.validate(query);
561  }
562 
563  RelNode result = convertQueryRecursive(query, top, null).rel;
564  if (top) {
565  if (isStream(query)) {
566  result = new LogicalDelta(cluster, result.getTraitSet(), result);
567  }
568  }
569  RelCollation collation = RelCollations.EMPTY;
570  if (!query.isA(SqlKind.DML)) {
571  if (isOrdered(query)) {
572  collation = requiredCollation(result);
573  }
574  }
575  checkConvertedType(query, result);
576 
577  if (SQL2REL_LOGGER.isDebugEnabled()) {
578  SQL2REL_LOGGER.debug(RelOptUtil.dumpPlan("Plan after converting SqlNode to RelNode",
579  result,
580  SqlExplainFormat.TEXT,
581  SqlExplainLevel.EXPPLAN_ATTRIBUTES));
582  }
583 
584  final RelDataType validatedRowType = validator.getValidatedNodeType(query);
585  List<RelHint> hints = new ArrayList<>();
586  if (query.getKind() == SqlKind.SELECT) {
587  final SqlSelect select = (SqlSelect) query;
588  if (select.hasHints()) {
589  hints = SqlUtil.getRelHint(hintStrategies, select.getHints());
590  }
591  }
592  // propagate the hints.
593  result = RelOptUtil.propagateRelHints(result, false);
594  return RelRoot.of(result, validatedRowType, query.getKind())
595  .withCollation(collation)
596  .withHints(hints);
597  }
598 
599  private static boolean isStream(SqlNode query) {
600  return query instanceof SqlSelect
601  && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
602  }
603 
604  public static boolean isOrdered(SqlNode query) {
605  switch (query.getKind()) {
606  case SELECT:
607  return ((SqlSelect) query).getOrderList() != null
608  && ((SqlSelect) query).getOrderList().size() > 0;
609  case WITH:
610  return isOrdered(((SqlWith) query).body);
611  case ORDER_BY:
612  return ((SqlOrderBy) query).orderList.size() > 0;
613  default:
614  return false;
615  }
616  }
617 
618  private RelCollation requiredCollation(RelNode r) {
619  if (r instanceof Sort) {
620  return ((Sort) r).collation;
621  }
622  if (r instanceof Project) {
623  return requiredCollation(((Project) r).getInput());
624  }
625  if (r instanceof Delta) {
626  return requiredCollation(((Delta) r).getInput());
627  }
628  throw new AssertionError();
629  }
630 
634  public RelNode convertSelect(SqlSelect select, boolean top) {
635  final SqlValidatorScope selectScope = validator.getWhereScope(select);
636  final Blackboard bb = createBlackboard(selectScope, null, top);
637  convertSelectImpl(bb, select);
638  return bb.root;
639  }
640 
645  SqlValidatorScope scope, Map<String, RexNode> nameToNodeMap, boolean top) {
646  return new Blackboard(scope, nameToNodeMap, top);
647  }
648 
653  protected void convertSelectImpl(final Blackboard bb, SqlSelect select) {
654  convertFrom(bb, select.getFrom());
655  convertWhere(bb, select.getWhere());
656 
657  final List<SqlNode> orderExprList = new ArrayList<>();
658  final List<RelFieldCollation> collationList = new ArrayList<>();
659  gatherOrderExprs(bb, select, select.getOrderList(), orderExprList, collationList);
660  final RelCollation collation =
661  cluster.traitSet().canonize(RelCollations.of(collationList));
662 
663  if (validator.isAggregate(select)) {
664  convertAgg(bb, select, orderExprList);
665  } else {
666  convertSelectList(bb, select, orderExprList);
667  }
668 
669  if (select.isDistinct()) {
670  distinctify(bb, true);
671  }
672 
673  convertOrder(
674  select, bb, collation, orderExprList, select.getOffset(), select.getFetch());
675 
676  if (select.hasHints()) {
677  final List<RelHint> hints = SqlUtil.getRelHint(hintStrategies, select.getHints());
678  // Attach the hints to the first Hintable node we found from the root node.
679  bb.setRoot(bb.root.accept(new RelShuttleImpl() {
680  boolean attached = false;
681 
682  @Override
683  public RelNode visitChild(RelNode parent, int i, RelNode child) {
684  if (parent instanceof Hintable && !attached) {
685  attached = true;
686  return ((Hintable) parent).attachHints(hints);
687  } else {
688  return super.visitChild(parent, i, child);
689  }
690  }
691  }),
692  true);
693  } else {
694  bb.setRoot(bb.root, true);
695  }
696  }
697 
711  private void distinctify(Blackboard bb, boolean checkForDupExprs) {
712  // Look for duplicate expressions in the project.
713  // Say we have 'select x, y, x, z'.
714  // Then dups will be {[2, 0]}
715  // and oldToNew will be {[0, 0], [1, 1], [2, 0], [3, 2]}
716  RelNode rel = bb.root;
717  if (checkForDupExprs && (rel instanceof LogicalProject)) {
718  LogicalProject project = (LogicalProject) rel;
719  final List<RexNode> projectExprs = project.getProjects();
720  final List<Integer> origins = new ArrayList<>();
721  int dupCount = 0;
722  for (int i = 0; i < projectExprs.size(); i++) {
723  int x = projectExprs.indexOf(projectExprs.get(i));
724  if (x >= 0 && x < i) {
725  origins.add(x);
726  ++dupCount;
727  } else {
728  origins.add(i);
729  }
730  }
731  if (dupCount == 0) {
732  distinctify(bb, false);
733  return;
734  }
735 
736  final Map<Integer, Integer> squished = new HashMap<>();
737  final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
738  final List<Pair<RexNode, String>> newProjects = new ArrayList<>();
739  for (int i = 0; i < fields.size(); i++) {
740  if (origins.get(i) == i) {
741  squished.put(i, newProjects.size());
742  newProjects.add(RexInputRef.of2(i, fields));
743  }
744  }
745  rel = LogicalProject.create(
746  rel, ImmutableList.of(), Pair.left(newProjects), Pair.right(newProjects));
747  bb.root = rel;
748  distinctify(bb, false);
749  rel = bb.root;
750 
751  // Create the expressions to reverse the mapping.
752  // Project($0, $1, $0, $2).
753  final List<Pair<RexNode, String>> undoProjects = new ArrayList<>();
754  for (int i = 0; i < fields.size(); i++) {
755  final int origin = origins.get(i);
756  RelDataTypeField field = fields.get(i);
757  undoProjects.add(
758  Pair.of((RexNode) new RexInputRef(squished.get(origin), field.getType()),
759  field.getName()));
760  }
761 
762  rel = LogicalProject.create(
763  rel, ImmutableList.of(), Pair.left(undoProjects), Pair.right(undoProjects));
764  bb.setRoot(rel, false);
765 
766  return;
767  }
768 
769  // Usual case: all of the expressions in the SELECT clause are
770  // different.
771  final ImmutableBitSet groupSet =
772  ImmutableBitSet.range(rel.getRowType().getFieldCount());
773  rel = createAggregate(bb, groupSet, ImmutableList.of(groupSet), ImmutableList.of());
774 
775  bb.setRoot(rel, false);
776  }
777 
794  protected void convertOrder(SqlSelect select,
795  Blackboard bb,
796  RelCollation collation,
797  List<SqlNode> orderExprList,
798  SqlNode offset,
799  SqlNode fetch) {
800  if (!bb.top || select.getOrderList() == null
801  || select.getOrderList().getList().isEmpty()) {
802  assert !bb.top || collation.getFieldCollations().isEmpty();
803  if ((offset == null
804  || (offset instanceof SqlLiteral
805  && ((SqlLiteral) offset)
806  .bigDecimalValue()
807  .equals(BigDecimal.ZERO)))
808  && fetch == null) {
809  return;
810  }
811  }
812 
813  // Create a sorter using the previously constructed collations.
814  bb.setRoot(LogicalSort.create(bb.root,
815  collation,
816  offset == null ? null : convertExpression(offset),
817  fetch == null ? null : convertExpression(fetch)),
818  false);
819 
820  // If extra expressions were added to the project list for sorting,
821  // add another project to remove them. But make the collation empty, because
822  // we can't represent the real collation.
823  //
824  // If it is the top node, use the real collation, but don't trim fields.
825  if (orderExprList.size() > 0 && !bb.top) {
826  final List<RexNode> exprs = new ArrayList<>();
827  final RelDataType rowType = bb.root.getRowType();
828  final int fieldCount = rowType.getFieldCount() - orderExprList.size();
829  for (int i = 0; i < fieldCount; i++) {
830  exprs.add(rexBuilder.makeInputRef(bb.root, i));
831  }
832  bb.setRoot(LogicalProject.create(bb.root,
833  ImmutableList.of(),
834  exprs,
835  rowType.getFieldNames().subList(0, fieldCount)),
836  false);
837  }
838  }
839 
845  private static boolean containsInOperator(SqlNode node) {
846  try {
847  SqlVisitor<Void> visitor = new SqlBasicVisitor<Void>() {
848  public Void visit(SqlCall call) {
849  if (call.getOperator() instanceof SqlInOperator) {
850  throw new Util.FoundOne(call);
851  }
852  return super.visit(call);
853  }
854  };
855  node.accept(visitor);
856  return false;
857  } catch (Util.FoundOne e) {
858  Util.swallow(e, null);
859  return true;
860  }
861  }
862 
870  private static SqlNode pushDownNotForIn(SqlValidatorScope scope, SqlNode sqlNode) {
871  if (!(sqlNode instanceof SqlCall) || !containsInOperator(sqlNode)) {
872  return sqlNode;
873  }
874  final SqlCall sqlCall = (SqlCall) sqlNode;
875  switch (sqlCall.getKind()) {
876  case AND:
877  case OR:
878  final List<SqlNode> operands = new ArrayList<>();
879  for (SqlNode operand : sqlCall.getOperandList()) {
880  operands.add(pushDownNotForIn(scope, operand));
881  }
882  final SqlCall newCall =
883  sqlCall.getOperator().createCall(sqlCall.getParserPosition(), operands);
884  return reg(scope, newCall);
885 
886  case NOT:
887  assert sqlCall.operand(0) instanceof SqlCall;
888  final SqlCall call = sqlCall.operand(0);
889  switch (sqlCall.operand(0).getKind()) {
890  case CASE:
891  final SqlCase caseNode = (SqlCase) call;
892  final SqlNodeList thenOperands = new SqlNodeList(SqlParserPos.ZERO);
893 
894  for (SqlNode thenOperand : caseNode.getThenOperands()) {
895  final SqlCall not =
896  SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO, thenOperand);
897  thenOperands.add(pushDownNotForIn(scope, reg(scope, not)));
898  }
899  SqlNode elseOperand = caseNode.getElseOperand();
900  if (!SqlUtil.isNull(elseOperand)) {
901  // "not(unknown)" is "unknown", so no need to simplify
902  final SqlCall not =
903  SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO, elseOperand);
904  elseOperand = pushDownNotForIn(scope, reg(scope, not));
905  }
906 
907  return reg(scope,
908  SqlStdOperatorTable.CASE.createCall(SqlParserPos.ZERO,
909  caseNode.getValueOperand(),
910  caseNode.getWhenOperands(),
911  thenOperands,
912  elseOperand));
913 
914  case AND:
915  final List<SqlNode> orOperands = new ArrayList<>();
916  for (SqlNode operand : call.getOperandList()) {
917  orOperands.add(pushDownNotForIn(scope,
918  reg(scope,
919  SqlStdOperatorTable.NOT.createCall(
920  SqlParserPos.ZERO, operand))));
921  }
922  return reg(scope,
923  SqlStdOperatorTable.OR.createCall(SqlParserPos.ZERO, orOperands));
924 
925  case OR:
926  final List<SqlNode> andOperands = new ArrayList<>();
927  for (SqlNode operand : call.getOperandList()) {
928  andOperands.add(pushDownNotForIn(scope,
929  reg(scope,
930  SqlStdOperatorTable.NOT.createCall(
931  SqlParserPos.ZERO, operand))));
932  }
933  return reg(scope,
934  SqlStdOperatorTable.AND.createCall(SqlParserPos.ZERO, andOperands));
935 
936  case NOT:
937  assert call.operandCount() == 1;
938  return pushDownNotForIn(scope, call.operand(0));
939 
940  case NOT_IN:
941  return reg(scope,
942  SqlStdOperatorTable.IN.createCall(
943  SqlParserPos.ZERO, call.getOperandList()));
944 
945  case IN:
946  return reg(scope,
947  SqlStdOperatorTable.NOT_IN.createCall(
948  SqlParserPos.ZERO, call.getOperandList()));
949  }
950  }
951  return sqlNode;
952  }
953 
958  private static SqlNode reg(SqlValidatorScope scope, SqlNode e) {
959  scope.getValidator().deriveType(scope, e);
960  return e;
961  }
962 
969  private void convertWhere(final Blackboard bb, final SqlNode where) {
970  if (where == null) {
971  return;
972  }
973  SqlNode newWhere = pushDownNotForIn(bb.scope, where);
974  replaceSubQueries(bb, newWhere, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
975  final RexNode convertedWhere = bb.convertExpression(newWhere);
976  final RexNode convertedWhere2 =
977  RexUtil.removeNullabilityCast(typeFactory, convertedWhere);
978 
979  // only allocate filter if the condition is not TRUE
980  if (convertedWhere2.isAlwaysTrue()) {
981  return;
982  }
983 
984  final RelFactories.FilterFactory filterFactory = RelFactories.DEFAULT_FILTER_FACTORY;
985  final RelNode filter =
986  filterFactory.createFilter(bb.root, convertedWhere2, ImmutableSet.of());
987  final RelNode r;
988  final CorrelationUse p = getCorrelationUse(bb, filter);
989  if (p != null) {
990  assert p.r instanceof Filter;
991  Filter f = (Filter) p.r;
992  r = LogicalFilter.create(f.getInput(), f.getCondition(), ImmutableSet.of(p.id));
993  } else {
994  r = filter;
995  }
996 
997  bb.setRoot(r, false);
998  }
999 
1000  private void replaceSubQueries(
1001  final Blackboard bb, final SqlNode expr, RelOptUtil.Logic logic) {
1002  findSubQueries(bb, expr, logic, false);
1003  for (SubQuery node : bb.subQueryList) {
1004  substituteSubQuery(bb, node);
1005  }
1006  }
1007 
1008  private void substituteSubQuery(Blackboard bb, SubQuery subQuery) {
1009  final RexNode expr = subQuery.expr;
1010  if (expr != null) {
1011  // Already done.
1012  return;
1013  }
1014 
1015  final SqlBasicCall call;
1016  final RelNode rel;
1017  final SqlNode query;
1018  final RelOptUtil.Exists converted;
1019 
1020  boolean isExpand = config.getExpandPredicate().test(bb.getTopNode(), subQuery.node);
1021 
1022  switch (subQuery.node.getKind()) {
1023  case CURSOR:
1024  convertCursor(bb, subQuery);
1025  return;
1026 
1027  case MULTISET_QUERY_CONSTRUCTOR:
1028  case MULTISET_VALUE_CONSTRUCTOR:
1029  case ARRAY_QUERY_CONSTRUCTOR:
1030  rel = convertMultisets(ImmutableList.of(subQuery.node), bb);
1031  subQuery.expr = bb.register(rel, JoinRelType.INNER);
1032  return;
1033 
1034  case IN:
1035  case NOT_IN:
1036  case SOME:
1037  case ALL:
1038  call = (SqlBasicCall) subQuery.node;
1039  query = call.operand(1);
1040  if (!isExpand && !(query instanceof SqlNodeList)) {
1041  return;
1042  }
1043  final SqlNode leftKeyNode = call.operand(0);
1044 
1045  final List<RexNode> leftKeys;
1046  switch (leftKeyNode.getKind()) {
1047  case ROW:
1048  leftKeys = new ArrayList<>();
1049  for (SqlNode sqlExpr : ((SqlBasicCall) leftKeyNode).getOperandList()) {
1050  leftKeys.add(bb.convertExpression(sqlExpr));
1051  }
1052  break;
1053  default:
1054  leftKeys = ImmutableList.of(bb.convertExpression(leftKeyNode));
1055  }
1056 
1057  if (query instanceof SqlNodeList) {
1058  SqlNodeList valueList = (SqlNodeList) query;
1059  if (!containsNullLiteral(valueList)
1060  && valueList.size() < config.getInSubQueryThreshold()) {
1061  // We're under the threshold, so convert to OR.
1062  subQuery.expr = convertInToOr(
1063  bb, leftKeys, valueList, (SqlInOperator) call.getOperator());
1064  return;
1065  }
1066 
1067  // Otherwise, let convertExists translate
1068  // values list into an inline table for the
1069  // reference to Q below.
1070  }
1071 
1072  // Project out the search columns from the left side
1073 
1074  // Q1:
1075  // "select from emp where emp.deptno in (select col1 from T)"
1076  //
1077  // is converted to
1078  //
1079  // "select from
1080  // emp inner join (select distinct col1 from T)) q
1081  // on emp.deptno = q.col1
1082  //
1083  // Q2:
1084  // "select from emp where emp.deptno not in (Q)"
1085  //
1086  // is converted to
1087  //
1088  // "select from
1089  // emp left outer join (select distinct col1, TRUE from T) q
1090  // on emp.deptno = q.col1
1091  // where emp.deptno <> null
1092  // and q.indicator <> TRUE"
1093  //
1094  // Note: Sub-query can be used as SqlUpdate#condition like below:
1095  //
1096  // UPDATE emp
1097  // SET empno = 1 WHERE emp.empno IN (
1098  // SELECT emp.empno FROM emp WHERE emp.empno = 2)
1099  //
1100  // In such case, when converting SqlUpdate#condition, bb.root is null
1101  // and it makes no sense to do the sub-query substitution.
1102  if (bb.root == null) {
1103  return;
1104  }
1105  final RelDataType targetRowType = SqlTypeUtil.promoteToRowType(
1106  typeFactory, validator.getValidatedNodeType(leftKeyNode), null);
1107  final boolean notIn = call.getOperator().kind == SqlKind.NOT_IN;
1108  converted = convertExists(
1109  query, RelOptUtil.SubQueryType.IN, subQuery.logic, notIn, targetRowType);
1110  if (converted.indicator) {
1111  // Generate
1112  // emp CROSS JOIN (SELECT COUNT(*) AS c,
1113  // COUNT(deptno) AS ck FROM dept)
1114  final RelDataType longType = typeFactory.createSqlType(SqlTypeName.BIGINT);
1115  final RelNode seek = converted.r.getInput(0); // fragile
1116  final int keyCount = leftKeys.size();
1117  final List<Integer> args = ImmutableIntList.range(0, keyCount);
1118  LogicalAggregate aggregate = LogicalAggregate.create(seek,
1119  ImmutableList.of(),
1120  ImmutableBitSet.of(),
1121  null,
1122  ImmutableList.of(AggregateCall.create(SqlStdOperatorTable.COUNT,
1123  false,
1124  false,
1125  false,
1126  ImmutableList.of(),
1127  -1,
1128  RelCollations.EMPTY,
1129  longType,
1130  null),
1131  AggregateCall.create(SqlStdOperatorTable.COUNT,
1132  false,
1133  false,
1134  false,
1135  args,
1136  -1,
1137  RelCollations.EMPTY,
1138  longType,
1139  null)));
1140  LogicalJoin join = LogicalJoin.create(bb.root,
1141  aggregate,
1142  ImmutableList.of(),
1143  rexBuilder.makeLiteral(true),
1144  ImmutableSet.of(),
1145  JoinRelType.INNER);
1146  bb.setRoot(join, false);
1147  }
1148  final RexNode rex = bb.register(converted.r,
1149  converted.outerJoin ? JoinRelType.LEFT : JoinRelType.INNER,
1150  leftKeys);
1151 
1152  RelOptUtil.Logic logic = subQuery.logic;
1153  switch (logic) {
1154  case TRUE_FALSE_UNKNOWN:
1155  case UNKNOWN_AS_TRUE:
1156  if (!converted.indicator) {
1157  logic = RelOptUtil.Logic.TRUE_FALSE;
1158  }
1159  }
1160  subQuery.expr = translateIn(logic, bb.root, rex);
1161  if (notIn) {
1162  subQuery.expr = rexBuilder.makeCall(SqlStdOperatorTable.NOT, subQuery.expr);
1163  }
1164  return;
1165 
1166  case EXISTS:
1167  // "select from emp where exists (select a from T)"
1168  //
1169  // is converted to the following if the sub-query is correlated:
1170  //
1171  // "select from emp left outer join (select AGG_TRUE() as indicator
1172  // from T group by corr_var) q where q.indicator is true"
1173  //
1174  // If there is no correlation, the expression is replaced with a
1175  // boolean indicating whether the sub-query returned 0 or >= 1 row.
1176  call = (SqlBasicCall) subQuery.node;
1177  query = call.operand(0);
1178  if (!isExpand) {
1179  return;
1180  }
1181  final SqlValidatorScope seekScope = (query instanceof SqlSelect)
1182  ? validator.getSelectScope((SqlSelect) query)
1183  : null;
1184  final Blackboard seekBb = createBlackboard(seekScope, null, false);
1185  final RelNode seekRel = convertQueryOrInList(seekBb, query, null);
1186  // An EXIST sub-query whose inner child has at least 1 tuple
1187  // (e.g. an Aggregate with no grouping columns or non-empty Values
1188  // node) should be simplified to a Boolean constant expression.
1189  final RelMetadataQuery mq = seekRel.getCluster().getMetadataQuery();
1190  final Double minRowCount = mq.getMinRowCount(seekRel);
1191  if (minRowCount != null && minRowCount >= 1D) {
1192  subQuery.expr = rexBuilder.makeLiteral(true);
1193  return;
1194  }
1195  converted = RelOptUtil.createExistsPlan(seekRel,
1196  RelOptUtil.SubQueryType.EXISTS,
1197  subQuery.logic,
1198  true,
1199  relBuilder);
1200  assert !converted.indicator;
1201  if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, true)) {
1202  return;
1203  }
1204  subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
1205  return;
1206 
1207  case SCALAR_QUERY:
1208  // Convert the sub-query. If it's non-correlated, convert it
1209  // to a constant expression.
1210  if (!isExpand) {
1211  return;
1212  }
1213  call = (SqlBasicCall) subQuery.node;
1214  query = call.operand(0);
1215  converted = convertExists(
1216  query, RelOptUtil.SubQueryType.SCALAR, subQuery.logic, true, null);
1217  assert !converted.indicator;
1218  if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, false)) {
1219  return;
1220  }
1221  rel = convertToSingleValueSubq(query, converted.r);
1222  subQuery.expr = bb.register(rel, JoinRelType.LEFT);
1223  return;
1224 
1225  case SELECT:
1226  // This is used when converting multiset queries:
1227  //
1228  // select * from unnest(select multiset[deptno] from emps);
1229  //
1230  converted = convertExists(subQuery.node,
1231  RelOptUtil.SubQueryType.SCALAR,
1232  subQuery.logic,
1233  true,
1234  null);
1235  assert !converted.indicator;
1236  subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
1237 
1238  // This is used when converting window table functions:
1239  //
1240  // select * from table(table emps, descriptor(deptno), interval '3' DAY)
1241  //
1242  bb.cursors.add(converted.r);
1243  return;
1244 
1245  default:
1246  throw new AssertionError("unexpected kind of sub-query: " + subQuery.node);
1247  }
1248  }
1249 
1250  private RexNode translateIn(RelOptUtil.Logic logic, RelNode root, final RexNode rex) {
1251  switch (logic) {
1252  case TRUE:
1253  return rexBuilder.makeLiteral(true);
1254 
1255  case TRUE_FALSE:
1256  case UNKNOWN_AS_FALSE:
1257  assert rex instanceof RexRangeRef;
1258  final int fieldCount = rex.getType().getFieldCount();
1259  RexNode rexNode = rexBuilder.makeFieldAccess(rex, fieldCount - 1);
1260  rexNode = rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, rexNode);
1261 
1262  // Then append the IS NOT NULL(leftKeysForIn).
1263  //
1264  // RexRangeRef contains the following fields:
1265  // leftKeysForIn,
1266  // rightKeysForIn (the original sub-query select list),
1267  // nullIndicator
1268  //
1269  // The first two lists contain the same number of fields.
1270  final int k = (fieldCount - 1) / 2;
1271  for (int i = 0; i < k; i++) {
1272  rexNode = rexBuilder.makeCall(SqlStdOperatorTable.AND,
1273  rexNode,
1274  rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
1275  rexBuilder.makeFieldAccess(rex, i)));
1276  }
1277  return rexNode;
1278 
1279  case TRUE_FALSE_UNKNOWN:
1280  case UNKNOWN_AS_TRUE:
1281  // select e.deptno,
1282  // case
1283  // when ct.c = 0 then false
1284  // when dt.i is not null then true
1285  // when e.deptno is null then null
1286  // when ct.ck < ct.c then null
1287  // else false
1288  // end
1289  // from e
1290  // cross join (select count(*) as c, count(deptno) as ck from v) as ct
1291  // left join (select distinct deptno, true as i from v) as dt
1292  // on e.deptno = dt.deptno
1293  final Join join = (Join) root;
1294  final Project left = (Project) join.getLeft();
1295  final RelNode leftLeft = ((Join) left.getInput()).getLeft();
1296  final int leftLeftCount = leftLeft.getRowType().getFieldCount();
1297  final RelDataType longType = typeFactory.createSqlType(SqlTypeName.BIGINT);
1298  final RexNode cRef = rexBuilder.makeInputRef(root, leftLeftCount);
1299  final RexNode ckRef = rexBuilder.makeInputRef(root, leftLeftCount + 1);
1300  final RexNode iRef =
1301  rexBuilder.makeInputRef(root, root.getRowType().getFieldCount() - 1);
1302 
1303  final RexLiteral zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO, longType);
1304  final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
1305  final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
1306  final RexNode unknownLiteral = rexBuilder.makeNullLiteral(trueLiteral.getType());
1307 
1308  final ImmutableList.Builder<RexNode> args = ImmutableList.builder();
1309  args.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, cRef, zero),
1310  falseLiteral,
1311  rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, iRef),
1312  trueLiteral);
1313  final JoinInfo joinInfo = join.analyzeCondition();
1314  for (int leftKey : joinInfo.leftKeys) {
1315  final RexNode kRef = rexBuilder.makeInputRef(root, leftKey);
1316  args.add(
1317  rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, kRef), unknownLiteral);
1318  }
1319  args.add(rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ckRef, cRef),
1320  unknownLiteral,
1321  falseLiteral);
1322 
1323  return rexBuilder.makeCall(SqlStdOperatorTable.CASE, args.build());
1324 
1325  default:
1326  throw new AssertionError(logic);
1327  }
1328  }
1329 
1330  private static boolean containsNullLiteral(SqlNodeList valueList) {
1331  for (SqlNode node : valueList.getList()) {
1332  if (node instanceof SqlLiteral) {
1333  SqlLiteral lit = (SqlLiteral) node;
1334  if (lit.getValue() == null) {
1335  return true;
1336  }
1337  }
1338  }
1339  return false;
1340  }
1341 
1353  SubQuery subQuery, Blackboard bb, RelNode converted, boolean isExists) {
1354  SqlCall call = (SqlBasicCall) subQuery.node;
1355  if (subQueryConverter.canConvertSubQuery()
1356  && isSubQueryNonCorrelated(converted, bb)) {
1357  // First check if the sub-query has already been converted
1358  // because it's a nested sub-query. If so, don't re-evaluate
1359  // it again.
1360  RexNode constExpr = mapConvertedNonCorrSubqs.get(call);
1361  if (constExpr == null) {
1362  constExpr = subQueryConverter.convertSubQuery(
1363  call, this, isExists, config.isExplain());
1364  }
1365  if (constExpr != null) {
1366  subQuery.expr = constExpr;
1367  mapConvertedNonCorrSubqs.put(call, constExpr);
1368  return true;
1369  }
1370  }
1371  return false;
1372  }
1373 
1382  public RelNode convertToSingleValueSubq(SqlNode query, RelNode plan) {
1383  // Check whether query is guaranteed to produce a single value.
1384  if (query instanceof SqlSelect) {
1385  SqlSelect select = (SqlSelect) query;
1386  SqlNodeList selectList = select.getSelectList();
1387  SqlNodeList groupList = select.getGroup();
1388 
1389  if ((selectList.size() == 1) && ((groupList == null) || (groupList.size() == 0))) {
1390  SqlNode selectExpr = selectList.get(0);
1391  if (selectExpr instanceof SqlCall) {
1392  SqlCall selectExprCall = (SqlCall) selectExpr;
1393  if (Util.isSingleValue(selectExprCall)) {
1394  return plan;
1395  }
1396  }
1397 
1398  // If there is a limit with 0 or 1,
1399  // it is ensured to produce a single value
1400  if (select.getFetch() != null && select.getFetch() instanceof SqlNumericLiteral) {
1401  SqlNumericLiteral limitNum = (SqlNumericLiteral) select.getFetch();
1402  if (((BigDecimal) limitNum.getValue()).intValue() < 2) {
1403  return plan;
1404  }
1405  }
1406  }
1407  } else if (query instanceof SqlCall) {
1408  // If the query is (values ...),
1409  // it is necessary to look into the operands to determine
1410  // whether SingleValueAgg is necessary
1411  SqlCall exprCall = (SqlCall) query;
1412  if (exprCall.getOperator() instanceof SqlValuesOperator
1413  && Util.isSingleValue(exprCall)) {
1414  return plan;
1415  }
1416  }
1417 
1418  // If not, project SingleValueAgg
1419  return RelOptUtil.createSingleValueAggRel(cluster, plan);
1420  }
1421 
1430  private RexNode convertInToOr(final Blackboard bb,
1431  final List<RexNode> leftKeys,
1432  SqlNodeList valuesList,
1433  SqlInOperator op) {
1434  final List<RexNode> comparisons = new ArrayList<>();
1435  for (SqlNode rightVals : valuesList) {
1436  RexNode rexComparison;
1437  final SqlOperator comparisonOp;
1438  if (op instanceof SqlQuantifyOperator) {
1439  comparisonOp = RelOptUtil.op(
1440  ((SqlQuantifyOperator) op).comparisonKind, SqlStdOperatorTable.EQUALS);
1441  } else {
1442  comparisonOp = SqlStdOperatorTable.EQUALS;
1443  }
1444  if (leftKeys.size() == 1) {
1445  rexComparison = rexBuilder.makeCall(comparisonOp,
1446  leftKeys.get(0),
1447  ensureSqlType(
1448  leftKeys.get(0).getType(), bb.convertExpression(rightVals)));
1449  } else {
1450  assert rightVals instanceof SqlCall;
1451  final SqlBasicCall call = (SqlBasicCall) rightVals;
1452  assert (call.getOperator() instanceof SqlRowOperator)
1453  && call.operandCount() == leftKeys.size();
1454  rexComparison = RexUtil.composeConjunction(rexBuilder,
1455  Iterables.transform(Pair.zip(leftKeys, call.getOperandList()),
1456  pair
1457  -> rexBuilder.makeCall(comparisonOp,
1458  pair.left,
1459  ensureSqlType(pair.left.getType(),
1460  bb.convertExpression(pair.right)))));
1461  }
1462  comparisons.add(rexComparison);
1463  }
1464 
1465  switch (op.kind) {
1466  case ALL:
1467  return RexUtil.composeConjunction(rexBuilder, comparisons, true);
1468  case NOT_IN:
1469  return rexBuilder.makeCall(SqlStdOperatorTable.NOT,
1470  RexUtil.composeDisjunction(rexBuilder, comparisons, true));
1471  case IN:
1472  case SOME:
1473  return RexUtil.composeDisjunction(rexBuilder, comparisons, true);
1474  default:
1475  throw new AssertionError();
1476  }
1477  }
1478 
1484  private RexNode ensureSqlType(RelDataType type, RexNode node) {
1485  if (type.getSqlTypeName() == node.getType().getSqlTypeName()
1486  || (type.getSqlTypeName() == SqlTypeName.VARCHAR
1487  && node.getType().getSqlTypeName() == SqlTypeName.CHAR)) {
1488  return node;
1489  }
1490  return rexBuilder.ensureType(type, node, true);
1491  }
1492 
1502  @Deprecated // to be removed before 2.0
1503  protected int getInSubqueryThreshold() {
1504  return config.getInSubQueryThreshold();
1505  }
1506 
1524  private RelOptUtil.Exists convertExists(SqlNode seek,
1525  RelOptUtil.SubQueryType subQueryType,
1526  RelOptUtil.Logic logic,
1527  boolean notIn,
1528  RelDataType targetDataType) {
1529  final SqlValidatorScope seekScope = (seek instanceof SqlSelect)
1530  ? validator.getSelectScope((SqlSelect) seek)
1531  : null;
1532  final Blackboard seekBb = createBlackboard(seekScope, null, false);
1533  RelNode seekRel = convertQueryOrInList(seekBb, seek, targetDataType);
1534 
1535  return RelOptUtil.createExistsPlan(seekRel, subQueryType, logic, notIn, relBuilder);
1536  }
1537 
1538  private RelNode convertQueryOrInList(
1539  Blackboard bb, SqlNode seek, RelDataType targetRowType) {
1540  // NOTE: Once we start accepting single-row queries as row constructors,
1541  // there will be an ambiguity here for a case like X IN ((SELECT Y FROM
1542  // Z)). The SQL standard resolves the ambiguity by saying that a lone
1543  // select should be interpreted as a table expression, not a row
1544  // expression. The semantic difference is that a table expression can
1545  // return multiple rows.
1546  if (seek instanceof SqlNodeList) {
1547  return convertRowValues(
1548  bb, seek, ((SqlNodeList) seek).getList(), false, targetRowType);
1549  } else {
1550  return convertQueryRecursive(seek, false, null).project();
1551  }
1552  }
1553 
1554  private RelNode convertRowValues(Blackboard bb,
1555  SqlNode rowList,
1556  Collection<SqlNode> rows,
1557  boolean allowLiteralsOnly,
1558  RelDataType targetRowType) {
1559  // NOTE jvs 30-Apr-2006: We combine all rows consisting entirely of
1560  // literals into a single LogicalValues; this gives the optimizer a smaller
1561  // input tree. For everything else (computed expressions, row
1562  // sub-queries), we union each row in as a projection on top of a
1563  // LogicalOneRow.
1564 
1565  final ImmutableList.Builder<ImmutableList<RexLiteral>> tupleList =
1566  ImmutableList.builder();
1567  final RelDataType rowType;
1568  if (targetRowType != null) {
1569  rowType = targetRowType;
1570  } else {
1571  rowType = SqlTypeUtil.promoteToRowType(
1572  typeFactory, validator.getValidatedNodeType(rowList), null);
1573  }
1574 
1575  final List<RelNode> unionInputs = new ArrayList<>();
1576  for (SqlNode node : rows) {
1577  SqlBasicCall call;
1578  if (isRowConstructor(node)) {
1579  call = (SqlBasicCall) node;
1580  ImmutableList.Builder<RexLiteral> tuple = ImmutableList.builder();
1581  for (Ord<SqlNode> operand : Ord.zip(call.operands)) {
1582  RexLiteral rexLiteral =
1583  convertLiteralInValuesList(operand.e, bb, rowType, operand.i);
1584  if ((rexLiteral == null) && allowLiteralsOnly) {
1585  return null;
1586  }
1587  if ((rexLiteral == null) || !config.isCreateValuesRel()) {
1588  // fallback to convertRowConstructor
1589  tuple = null;
1590  break;
1591  }
1592  tuple.add(rexLiteral);
1593  }
1594  if (tuple != null) {
1595  tupleList.add(tuple.build());
1596  continue;
1597  }
1598  } else {
1599  RexLiteral rexLiteral = convertLiteralInValuesList(node, bb, rowType, 0);
1600  if ((rexLiteral != null) && config.isCreateValuesRel()) {
1601  tupleList.add(ImmutableList.of(rexLiteral));
1602  continue;
1603  } else {
1604  if ((rexLiteral == null) && allowLiteralsOnly) {
1605  return null;
1606  }
1607  }
1608 
1609  // convert "1" to "row(1)"
1610  call = (SqlBasicCall) SqlStdOperatorTable.ROW.createCall(SqlParserPos.ZERO, node);
1611  }
1612  unionInputs.add(convertRowConstructor(bb, call));
1613  }
1614  LogicalValues values = LogicalValues.create(cluster, rowType, tupleList.build());
1615  RelNode resultRel;
1616  if (unionInputs.isEmpty()) {
1617  resultRel = values;
1618  } else {
1619  if (!values.getTuples().isEmpty()) {
1620  unionInputs.add(values);
1621  }
1622  resultRel = LogicalUnion.create(unionInputs, true);
1623  }
1624  leaves.put(resultRel, resultRel.getRowType().getFieldCount());
1625  return resultRel;
1626  }
1627 
1628  private RexLiteral convertLiteralInValuesList(
1629  SqlNode sqlNode, Blackboard bb, RelDataType rowType, int iField) {
1630  if (!(sqlNode instanceof SqlLiteral)) {
1631  return null;
1632  }
1633  RelDataTypeField field = rowType.getFieldList().get(iField);
1634  RelDataType type = field.getType();
1635  if (type.isStruct()) {
1636  // null literals for weird stuff like UDT's need
1637  // special handling during type flattening, so
1638  // don't use LogicalValues for those
1639  return null;
1640  }
1641 
1642  RexNode literalExpr = exprConverter.convertLiteral(bb, (SqlLiteral) sqlNode);
1643 
1644  if (!(literalExpr instanceof RexLiteral)) {
1645  assert literalExpr.isA(SqlKind.CAST);
1646  RexNode child = ((RexCall) literalExpr).getOperands().get(0);
1647  assert RexLiteral.isNullLiteral(child);
1648 
1649  // NOTE jvs 22-Nov-2006: we preserve type info
1650  // in LogicalValues digest, so it's OK to lose it here
1651  return (RexLiteral) child;
1652  }
1653 
1654  RexLiteral literal = (RexLiteral) literalExpr;
1655 
1656  Comparable value = literal.getValue();
1657 
1658  if (SqlTypeUtil.isExactNumeric(type) && SqlTypeUtil.hasScale(type)) {
1659  BigDecimal roundedValue =
1660  NumberUtil.rescaleBigDecimal((BigDecimal) value, type.getScale());
1661  return rexBuilder.makeExactLiteral(roundedValue, type);
1662  }
1663 
1664  if ((value instanceof NlsString) && (type.getSqlTypeName() == SqlTypeName.CHAR)) {
1665  // pad fixed character type
1666  NlsString unpadded = (NlsString) value;
1667  return rexBuilder.makeCharLiteral(
1668  new NlsString(Spaces.padRight(unpadded.getValue(), type.getPrecision()),
1669  unpadded.getCharsetName(),
1670  unpadded.getCollation()));
1671  }
1672  return literal;
1673  }
1674 
1675  private boolean isRowConstructor(SqlNode node) {
1676  if (!(node.getKind() == SqlKind.ROW)) {
1677  return false;
1678  }
1679  SqlCall call = (SqlCall) node;
1680  return call.getOperator().getName().equalsIgnoreCase("row");
1681  }
1682 
1699  private void findSubQueries(Blackboard bb,
1700  SqlNode node,
1701  RelOptUtil.Logic logic,
1702  boolean registerOnlyScalarSubQueries) {
1703  final SqlKind kind = node.getKind();
1704  switch (kind) {
1705  case EXISTS:
1706  case SELECT:
1707  case MULTISET_QUERY_CONSTRUCTOR:
1708  case MULTISET_VALUE_CONSTRUCTOR:
1709  case ARRAY_QUERY_CONSTRUCTOR:
1710  case CURSOR:
1711  case SCALAR_QUERY:
1712  if (!registerOnlyScalarSubQueries || (kind == SqlKind.SCALAR_QUERY)) {
1713  bb.registerSubQuery(node, RelOptUtil.Logic.TRUE_FALSE);
1714  }
1715  return;
1716  case IN:
1717  break;
1718  case NOT_IN:
1719  case NOT:
1720  logic = logic.negate();
1721  break;
1722  }
1723  if (node instanceof SqlCall) {
1724  switch (kind) {
1725  // Do no change logic for AND, IN and NOT IN expressions;
1726  // but do change logic for OR, NOT and others;
1727  // EXISTS was handled already.
1728  case AND:
1729  case IN:
1730  case NOT_IN:
1731  break;
1732  default:
1733  logic = RelOptUtil.Logic.TRUE_FALSE_UNKNOWN;
1734  break;
1735  }
1736  for (SqlNode operand : ((SqlCall) node).getOperandList()) {
1737  if (operand != null) {
1738  // In the case of an IN expression, locate scalar
1739  // sub-queries so we can convert them to constants
1740  findSubQueries(bb,
1741  operand,
1742  logic,
1743  kind == SqlKind.IN || kind == SqlKind.NOT_IN || kind == SqlKind.SOME
1744  || kind == SqlKind.ALL || registerOnlyScalarSubQueries);
1745  }
1746  }
1747  } else if (node instanceof SqlNodeList) {
1748  for (SqlNode child : (SqlNodeList) node) {
1749  findSubQueries(bb,
1750  child,
1751  logic,
1752  kind == SqlKind.IN || kind == SqlKind.NOT_IN || kind == SqlKind.SOME
1753  || kind == SqlKind.ALL || registerOnlyScalarSubQueries);
1754  }
1755  }
1756 
1757  // Now that we've located any scalar sub-queries inside the IN
1758  // expression, register the IN expression itself. We need to
1759  // register the scalar sub-queries first so they can be converted
1760  // before the IN expression is converted.
1761  switch (kind) {
1762  case IN:
1763  case NOT_IN:
1764  case SOME:
1765  case ALL:
1766  switch (logic) {
1767  case TRUE_FALSE_UNKNOWN:
1768  RelDataType type = validator.getValidatedNodeTypeIfKnown(node);
1769  if (type == null) {
1770  // The node might not be validated if we still don't know type of the node.
1771  // Therefore return directly.
1772  return;
1773  } else {
1774  break;
1775  }
1776  // fall through
1777  case UNKNOWN_AS_FALSE:
1778  logic = RelOptUtil.Logic.TRUE;
1779  }
1780  bb.registerSubQuery(node, logic);
1781  break;
1782  }
1783  }
1784 
1791  public RexNode convertExpression(SqlNode node) {
1792  Map<String, RelDataType> nameToTypeMap = Collections.emptyMap();
1793  final ParameterScope scope =
1794  new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
1795  final Blackboard bb = createBlackboard(scope, null, false);
1796  return bb.convertExpression(node);
1797  }
1798 
1810  public RexNode convertExpression(SqlNode node, Map<String, RexNode> nameToNodeMap) {
1811  final Map<String, RelDataType> nameToTypeMap = new HashMap<>();
1812  for (Map.Entry<String, RexNode> entry : nameToNodeMap.entrySet()) {
1813  nameToTypeMap.put(entry.getKey(), entry.getValue().getType());
1814  }
1815  final ParameterScope scope =
1816  new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
1817  final Blackboard bb = createBlackboard(scope, nameToNodeMap, false);
1818  return bb.convertExpression(node);
1819  }
1820 
1833  protected RexNode convertExtendedExpression(SqlNode node, Blackboard bb) {
1834  return null;
1835  }
1836 
1837  private RexNode convertOver(Blackboard bb, SqlNode node) {
1838  SqlCall call = (SqlCall) node;
1839  SqlCall aggCall = call.operand(0);
1840  boolean ignoreNulls = false;
1841  switch (aggCall.getKind()) {
1842  case IGNORE_NULLS:
1843  ignoreNulls = true;
1844  // fall through
1845  case RESPECT_NULLS:
1846  aggCall = aggCall.operand(0);
1847  }
1848 
1849  SqlNode windowOrRef = call.operand(1);
1850  final SqlWindow window = validator.resolveWindow(windowOrRef, bb.scope, true);
1851 
1852  // ROW_NUMBER() expects specific kind of framing.
1853  if (aggCall.getKind() == SqlKind.ROW_NUMBER) {
1854  window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
1855  window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
1856  window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));
1857  }
1858  final SqlNodeList partitionList = window.getPartitionList();
1859  final ImmutableList.Builder<RexNode> partitionKeys = ImmutableList.builder();
1860  for (SqlNode partition : partitionList) {
1861  partitionKeys.add(bb.convertExpression(partition));
1862  }
1863  RexNode lowerBound = bb.convertExpression(window.getLowerBound());
1864  RexNode upperBound = bb.convertExpression(window.getUpperBound());
1865  SqlNodeList orderList = window.getOrderList();
1866  if ((orderList.size() == 0) && !window.isRows()) {
1867  // A logical range requires an ORDER BY clause. Use the implicit
1868  // ordering of this relation. There must be one, otherwise it would
1869  // have failed validation.
1870  orderList = bb.scope.getOrderList();
1871  if (orderList == null) {
1872  throw new AssertionError("Relation should have sort key for implicit ORDER BY");
1873  }
1874  }
1875 
1876  final ImmutableList.Builder<RexFieldCollation> orderKeys = ImmutableList.builder();
1877  for (SqlNode order : orderList) {
1878  orderKeys.add(bb.convertSortExpression(order,
1879  RelFieldCollation.Direction.ASCENDING,
1880  RelFieldCollation.NullDirection.UNSPECIFIED));
1881  }
1882 
1883  try {
1884  Preconditions.checkArgument(bb.window == null, "already in window agg mode");
1885  bb.window = window;
1886  RexNode rexAgg = exprConverter.convertCall(bb, aggCall);
1887  rexAgg = rexBuilder.ensureType(validator.getValidatedNodeType(call), rexAgg, false);
1888 
1889  // Walk over the tree and apply 'over' to all agg functions. This is
1890  // necessary because the returned expression is not necessarily a call
1891  // to an agg function. For example, AVG(x) becomes SUM(x) / COUNT(x).
1892 
1893  final SqlLiteral q = aggCall.getFunctionQuantifier();
1894  final boolean isDistinct = q != null && q.getValue() == SqlSelectKeyword.DISTINCT;
1895 
1896  final RexShuttle visitor = new HistogramShuttle(partitionKeys.build(),
1897  orderKeys.build(),
1898  RexWindowBound.create(window.getLowerBound(), lowerBound),
1899  RexWindowBound.create(window.getUpperBound(), upperBound),
1900  window,
1901  isDistinct,
1902  ignoreNulls);
1903  RexNode overNode = rexAgg.accept(visitor);
1904 
1905  return overNode;
1906  } finally {
1907  bb.window = null;
1908  }
1909  }
1910 
1928  protected void convertFrom(Blackboard bb, SqlNode from) {
1929  if (from == null) {
1930  bb.setRoot(LogicalValues.createOneRow(cluster), false);
1931  return;
1932  }
1933 
1934  final SqlCall call;
1935  final SqlNode[] operands;
1936  switch (from.getKind()) {
1937  case MATCH_RECOGNIZE:
1938  convertMatchRecognize(bb, (SqlCall) from);
1939  return;
1940 
1941  case AS:
1942  call = (SqlCall) from;
1943  convertFrom(bb, call.operand(0));
1944  if (call.operandCount() > 2
1945  && (bb.root instanceof Values || bb.root instanceof Uncollect)) {
1946  final List<String> fieldNames = new ArrayList<>();
1947  for (SqlNode node : Util.skip(call.getOperandList(), 2)) {
1948  fieldNames.add(((SqlIdentifier) node).getSimple());
1949  }
1950  bb.setRoot(relBuilder.push(bb.root).rename(fieldNames).build(), true);
1951  }
1952  return;
1953 
1954  case WITH_ITEM:
1955  convertFrom(bb, ((SqlWithItem) from).query);
1956  return;
1957 
1958  case WITH:
1959  convertFrom(bb, ((SqlWith) from).body);
1960  return;
1961 
1962  case TABLESAMPLE:
1963  operands = ((SqlBasicCall) from).getOperands();
1964  SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands[1]);
1965  if (sampleSpec instanceof SqlSampleSpec.SqlSubstitutionSampleSpec) {
1966  String sampleName =
1967  ((SqlSampleSpec.SqlSubstitutionSampleSpec) sampleSpec).getName();
1968  datasetStack.push(sampleName);
1969  convertFrom(bb, operands[0]);
1970  datasetStack.pop();
1971  } else if (sampleSpec instanceof SqlSampleSpec.SqlTableSampleSpec) {
1972  SqlSampleSpec.SqlTableSampleSpec tableSampleSpec =
1973  (SqlSampleSpec.SqlTableSampleSpec) sampleSpec;
1974  convertFrom(bb, operands[0]);
1975  RelOptSamplingParameters params =
1976  new RelOptSamplingParameters(tableSampleSpec.isBernoulli(),
1977  tableSampleSpec.getSamplePercentage(),
1978  tableSampleSpec.isRepeatable(),
1979  tableSampleSpec.getRepeatableSeed());
1980  bb.setRoot(new Sample(cluster, bb.root, params), false);
1981  } else {
1982  throw new AssertionError("unknown TABLESAMPLE type: " + sampleSpec);
1983  }
1984  return;
1985 
1986  case TABLE_REF:
1987  call = (SqlCall) from;
1988  convertIdentifier(bb, call.operand(0), null, call.operand(1));
1989  return;
1990 
1991  case IDENTIFIER:
1992  convertIdentifier(bb, (SqlIdentifier) from, null, null);
1993  return;
1994 
1995  case EXTEND:
1996  call = (SqlCall) from;
1997  final SqlNode operand0 = call.getOperandList().get(0);
1998  final SqlIdentifier id = operand0.getKind() == SqlKind.TABLE_REF
1999  ? ((SqlCall) operand0).operand(0)
2000  : (SqlIdentifier) operand0;
2001  SqlNodeList extendedColumns = (SqlNodeList) call.getOperandList().get(1);
2002  convertIdentifier(bb, id, extendedColumns, null);
2003  return;
2004 
2005  case SNAPSHOT:
2006  convertTemporalTable(bb, (SqlCall) from);
2007  return;
2008 
2009  case JOIN:
2010  final SqlJoin join = (SqlJoin) from;
2011  final SqlValidatorScope scope = validator.getJoinScope(from);
2012  final Blackboard fromBlackboard = createBlackboard(scope, null, false);
2013  SqlNode left = join.getLeft();
2014  SqlNode right = join.getRight();
2015  final boolean isNatural = join.isNatural();
2016  final JoinType joinType = join.getJoinType();
2017  final SqlValidatorScope leftScope = Util.first(
2018  validator.getJoinScope(left), ((DelegatingScope) bb.scope).getParent());
2019  final Blackboard leftBlackboard = createBlackboard(leftScope, null, false);
2020  final SqlValidatorScope rightScope = Util.first(
2021  validator.getJoinScope(right), ((DelegatingScope) bb.scope).getParent());
2022  final Blackboard rightBlackboard = createBlackboard(rightScope, null, false);
2023  convertFrom(leftBlackboard, left);
2024  RelNode leftRel = leftBlackboard.root;
2025  convertFrom(rightBlackboard, right);
2026  RelNode rightRel = rightBlackboard.root;
2027  JoinRelType convertedJoinType = convertJoinType(joinType);
2028  RexNode conditionExp;
2029  final SqlValidatorNamespace leftNamespace = validator.getNamespace(left);
2030  final SqlValidatorNamespace rightNamespace = validator.getNamespace(right);
2031  if (isNatural) {
2032  final RelDataType leftRowType = leftNamespace.getRowType();
2033  final RelDataType rightRowType = rightNamespace.getRowType();
2034  final List<String> columnList = SqlValidatorUtil.deriveNaturalJoinColumnList(
2035  catalogReader.nameMatcher(), leftRowType, rightRowType);
2036  conditionExp = convertUsing(leftNamespace, rightNamespace, columnList);
2037  } else {
2038  conditionExp = convertJoinCondition(fromBlackboard,
2039  leftNamespace,
2040  rightNamespace,
2041  join.getCondition(),
2042  join.getConditionType(),
2043  leftRel,
2044  rightRel);
2045  }
2046 
2047  final RelNode joinRel = createJoin(
2048  fromBlackboard, leftRel, rightRel, conditionExp, convertedJoinType);
2049  bb.setRoot(joinRel, false);
2050  return;
2051 
2052  case SELECT:
2053  case INTERSECT:
2054  case EXCEPT:
2055  case UNION:
2056  final RelNode rel = convertQueryRecursive(from, false, null).project();
2057  bb.setRoot(rel, true);
2058  return;
2059 
2060  case VALUES:
2061  convertValuesImpl(bb, (SqlCall) from, null);
2062  return;
2063 
2064  case UNNEST:
2065  call = (SqlCall) from;
2066  final List<SqlNode> nodes = call.getOperandList();
2067  final SqlUnnestOperator operator = (SqlUnnestOperator) call.getOperator();
2068  for (SqlNode node : nodes) {
2069  replaceSubQueries(bb, node, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2070  }
2071  final List<RexNode> exprs = new ArrayList<>();
2072  final List<String> fieldNames = new ArrayList<>();
2073  for (Ord<SqlNode> node : Ord.zip(nodes)) {
2074  exprs.add(bb.convertExpression(node.e));
2075  fieldNames.add(validator.deriveAlias(node.e, node.i));
2076  }
2077  RelNode child = (null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster);
2078  relBuilder.push(child).projectNamed(exprs, fieldNames, false);
2079 
2080  Uncollect uncollect = new Uncollect(cluster,
2081  cluster.traitSetOf(Convention.NONE),
2082  relBuilder.build(),
2083  operator.withOrdinality);
2084  bb.setRoot(uncollect, true);
2085  return;
2086 
2087  case COLLECTION_TABLE:
2088  call = (SqlCall) from;
2089 
2090  // Dig out real call; TABLE() wrapper is just syntactic.
2091  assert call.getOperandList().size() == 1;
2092  final SqlCall call2 = call.operand(0);
2093  convertCollectionTable(bb, call2);
2094  return;
2095 
2096  default:
2097  throw new AssertionError("not a join operator " + from);
2098  }
2099  }
2100 
2101  protected void convertMatchRecognize(Blackboard bb, SqlCall call) {
2102  final SqlMatchRecognize matchRecognize = (SqlMatchRecognize) call;
2103  final SqlValidatorNamespace ns = validator.getNamespace(matchRecognize);
2104  final SqlValidatorScope scope = validator.getMatchRecognizeScope(matchRecognize);
2105 
2106  final Blackboard matchBb = createBlackboard(scope, null, false);
2107  final RelDataType rowType = ns.getRowType();
2108  // convert inner query, could be a table name or a derived table
2109  SqlNode expr = matchRecognize.getTableRef();
2110  convertFrom(matchBb, expr);
2111  final RelNode input = matchBb.root;
2112 
2113  // PARTITION BY
2114  final SqlNodeList partitionList = matchRecognize.getPartitionList();
2115  final ImmutableBitSet.Builder partitionKeys = ImmutableBitSet.builder();
2116  for (SqlNode partition : partitionList) {
2117  RexNode e = matchBb.convertExpression(partition);
2118  partitionKeys.set(((RexInputRef) e).getIndex());
2119  }
2120 
2121  // ORDER BY
2122  final SqlNodeList orderList = matchRecognize.getOrderList();
2123  final List<RelFieldCollation> orderKeys = new ArrayList<>();
2124  for (SqlNode order : orderList) {
2125  final RelFieldCollation.Direction direction;
2126  switch (order.getKind()) {
2127  case DESCENDING:
2128  direction = RelFieldCollation.Direction.DESCENDING;
2129  order = ((SqlCall) order).operand(0);
2130  break;
2131  case NULLS_FIRST:
2132  case NULLS_LAST:
2133  throw new AssertionError();
2134  default:
2135  direction = RelFieldCollation.Direction.ASCENDING;
2136  break;
2137  }
2138  final RelFieldCollation.NullDirection nullDirection =
2139  validator.getDefaultNullCollation().last(desc(direction))
2140  ? RelFieldCollation.NullDirection.LAST
2141  : RelFieldCollation.NullDirection.FIRST;
2142  RexNode e = matchBb.convertExpression(order);
2143  orderKeys.add(new RelFieldCollation(
2144  ((RexInputRef) e).getIndex(), direction, nullDirection));
2145  }
2146  final RelCollation orders = cluster.traitSet().canonize(RelCollations.of(orderKeys));
2147 
2148  // convert pattern
2149  final Set<String> patternVarsSet = new HashSet<>();
2150  SqlNode pattern = matchRecognize.getPattern();
2151  final SqlBasicVisitor<RexNode> patternVarVisitor = new SqlBasicVisitor<RexNode>() {
2152  @Override
2153  public RexNode visit(SqlCall call) {
2154  List<SqlNode> operands = call.getOperandList();
2155  List<RexNode> newOperands = new ArrayList<>();
2156  for (SqlNode node : operands) {
2157  newOperands.add(node.accept(this));
2158  }
2159  return rexBuilder.makeCall(
2160  validator.getUnknownType(), call.getOperator(), newOperands);
2161  }
2162 
2163  @Override
2164  public RexNode visit(SqlIdentifier id) {
2165  assert id.isSimple();
2166  patternVarsSet.add(id.getSimple());
2167  return rexBuilder.makeLiteral(id.getSimple());
2168  }
2169 
2170  @Override
2171  public RexNode visit(SqlLiteral literal) {
2172  if (literal instanceof SqlNumericLiteral) {
2173  return rexBuilder.makeExactLiteral(BigDecimal.valueOf(literal.intValue(true)));
2174  } else {
2175  return rexBuilder.makeLiteral(literal.booleanValue());
2176  }
2177  }
2178  };
2179  final RexNode patternNode = pattern.accept(patternVarVisitor);
2180 
2181  SqlLiteral interval = matchRecognize.getInterval();
2182  RexNode intervalNode = null;
2183  if (interval != null) {
2184  intervalNode = matchBb.convertLiteral(interval);
2185  }
2186 
2187  // convert subset
2188  final SqlNodeList subsets = matchRecognize.getSubsetList();
2189  final Map<String, TreeSet<String>> subsetMap = new HashMap<>();
2190  for (SqlNode node : subsets) {
2191  List<SqlNode> operands = ((SqlCall) node).getOperandList();
2192  SqlIdentifier left = (SqlIdentifier) operands.get(0);
2193  patternVarsSet.add(left.getSimple());
2194  SqlNodeList rights = (SqlNodeList) operands.get(1);
2195  final TreeSet<String> list = new TreeSet<>();
2196  for (SqlNode right : rights) {
2197  assert right instanceof SqlIdentifier;
2198  list.add(((SqlIdentifier) right).getSimple());
2199  }
2200  subsetMap.put(left.getSimple(), list);
2201  }
2202 
2203  SqlNode afterMatch = matchRecognize.getAfter();
2204  if (afterMatch == null) {
2205  afterMatch =
2206  SqlMatchRecognize.AfterOption.SKIP_TO_NEXT_ROW.symbol(SqlParserPos.ZERO);
2207  }
2208 
2209  final RexNode after;
2210  if (afterMatch instanceof SqlCall) {
2211  List<SqlNode> operands = ((SqlCall) afterMatch).getOperandList();
2212  SqlOperator operator = ((SqlCall) afterMatch).getOperator();
2213  assert operands.size() == 1;
2214  SqlIdentifier id = (SqlIdentifier) operands.get(0);
2215  assert patternVarsSet.contains(id.getSimple())
2216  : id.getSimple()
2217  + " not defined in pattern";
2218  RexNode rex = rexBuilder.makeLiteral(id.getSimple());
2219  after = rexBuilder.makeCall(
2220  validator.getUnknownType(), operator, ImmutableList.of(rex));
2221  } else {
2222  after = matchBb.convertExpression(afterMatch);
2223  }
2224 
2225  matchBb.setPatternVarRef(true);
2226 
2227  // convert measures
2228  final ImmutableMap.Builder<String, RexNode> measureNodes = ImmutableMap.builder();
2229  for (SqlNode measure : matchRecognize.getMeasureList()) {
2230  List<SqlNode> operands = ((SqlCall) measure).getOperandList();
2231  String alias = ((SqlIdentifier) operands.get(1)).getSimple();
2232  RexNode rex = matchBb.convertExpression(operands.get(0));
2233  measureNodes.put(alias, rex);
2234  }
2235 
2236  // convert definitions
2237  final ImmutableMap.Builder<String, RexNode> definitionNodes = ImmutableMap.builder();
2238  for (SqlNode def : matchRecognize.getPatternDefList()) {
2239  replaceSubQueries(matchBb, def, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
2240  List<SqlNode> operands = ((SqlCall) def).getOperandList();
2241  String alias = ((SqlIdentifier) operands.get(1)).getSimple();
2242  RexNode rex = matchBb.convertExpression(operands.get(0));
2243  definitionNodes.put(alias, rex);
2244  }
2245 
2246  final SqlLiteral rowsPerMatch = matchRecognize.getRowsPerMatch();
2247  final boolean allRows = rowsPerMatch != null
2248  && rowsPerMatch.getValue() == SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS;
2249 
2250  matchBb.setPatternVarRef(false);
2251 
2252  final RelFactories.MatchFactory factory = RelFactories.DEFAULT_MATCH_FACTORY;
2253  final RelNode rel = factory.createMatch(input,
2254  patternNode,
2255  rowType,
2256  matchRecognize.getStrictStart().booleanValue(),
2257  matchRecognize.getStrictEnd().booleanValue(),
2258  definitionNodes.build(),
2259  measureNodes.build(),
2260  after,
2261  subsetMap,
2262  allRows,
2263  partitionKeys.build(),
2264  orders,
2265  intervalNode);
2266  bb.setRoot(rel, false);
2267  }
2268 
2270  SqlIdentifier id,
2271  SqlNodeList extendedColumns,
2272  SqlNodeList tableHints) {
2273  final SqlValidatorNamespace fromNamespace = validator.getNamespace(id).resolve();
2274  if (fromNamespace.getNode() != null) {
2275  convertFrom(bb, fromNamespace.getNode());
2276  return;
2277  }
2278  final String datasetName = datasetStack.isEmpty() ? null : datasetStack.peek();
2279  final boolean[] usedDataset = {false};
2280  RelOptTable table = SqlValidatorUtil.getRelOptTable(
2281  fromNamespace, catalogReader, datasetName, usedDataset);
2282  if (extendedColumns != null && extendedColumns.size() > 0) {
2283  assert table != null;
2284  final SqlValidatorTable validatorTable = table.unwrap(SqlValidatorTable.class);
2285  final List<RelDataTypeField> extendedFields = SqlValidatorUtil.getExtendedColumns(
2286  validator, validatorTable, extendedColumns);
2287  table = table.extend(extendedFields);
2288  }
2289  final RelNode tableRel;
2290  // Review Danny 2020-01-13: hacky to construct a new table scan
2291  // in order to apply the hint strategies.
2292  final List<RelHint> hints =
2293  hintStrategies.apply(SqlUtil.getRelHint(hintStrategies, tableHints),
2294  LogicalTableScan.create(cluster, table, ImmutableList.of()));
2295  tableRel = toRel(table, hints);
2296  bb.setRoot(tableRel, true);
2297  if (usedDataset[0]) {
2298  bb.setDataset(datasetName);
2299  }
2300  }
2301 
2302  protected void convertCollectionTable(Blackboard bb, SqlCall call) {
2303  final SqlOperator operator = call.getOperator();
2304  if (operator == SqlStdOperatorTable.TABLESAMPLE) {
2305  final String sampleName =
2306  SqlLiteral.unchain(call.operand(0)).getValueAs(String.class);
2307  datasetStack.push(sampleName);
2308  SqlCall cursorCall = call.operand(1);
2309  SqlNode query = cursorCall.operand(0);
2310  RelNode converted = convertQuery(query, false, false).rel;
2311  bb.setRoot(converted, false);
2312  datasetStack.pop();
2313  return;
2314  }
2315  replaceSubQueries(bb, call, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2316 
2317  // Expand table macro if possible. It's more efficient than
2318  // LogicalTableFunctionScan.
2319  final SqlCallBinding callBinding =
2320  new SqlCallBinding(bb.scope.getValidator(), bb.scope, call);
2321  if (operator instanceof SqlUserDefinedTableMacro) {
2322  final SqlUserDefinedTableMacro udf = (SqlUserDefinedTableMacro) operator;
2323  final TranslatableTable table = udf.getTable(typeFactory, callBinding.operands());
2324  final RelDataType rowType = table.getRowType(typeFactory);
2325  RelOptTable relOptTable =
2326  RelOptTableImpl.create(null, rowType, table, udf.getNameAsId().names);
2327  RelNode converted = toRel(relOptTable, ImmutableList.of());
2328  bb.setRoot(converted, true);
2329  return;
2330  }
2331 
2332  Type elementType;
2333  if (operator instanceof SqlUserDefinedTableFunction) {
2334  SqlUserDefinedTableFunction udtf = (SqlUserDefinedTableFunction) operator;
2335  elementType = udtf.getElementType(typeFactory, callBinding.operands());
2336  } else {
2337  elementType = null;
2338  }
2339 
2340  RexNode rexCall = bb.convertExpression(call);
2341  final List<RelNode> inputs = bb.retrieveCursors();
2342  Set<RelColumnMapping> columnMappings = getColumnMappings(operator);
2343  LogicalTableFunctionScan callRel = LogicalTableFunctionScan.create(cluster,
2344  inputs,
2345  rexCall,
2346  elementType,
2347  validator.getValidatedNodeType(call),
2348  columnMappings);
2349  bb.setRoot(callRel, true);
2350  afterTableFunction(bb, call, callRel);
2351  }
2352 
2354  SqlCall call,
2355  LogicalTableFunctionScan callRel) {}
2356 
2357  private void convertTemporalTable(Blackboard bb, SqlCall call) {
2358  final SqlSnapshot snapshot = (SqlSnapshot) call;
2359  final RexNode period = bb.convertExpression(snapshot.getPeriod());
2360 
2361  // convert inner query, could be a table name or a derived table
2362  SqlNode expr = snapshot.getTableRef();
2363  convertFrom(bb, expr);
2364  final TableScan scan = (TableScan) bb.root;
2365 
2366  final RelNode snapshotRel = relBuilder.push(scan).snapshot(period).build();
2367 
2368  bb.setRoot(snapshotRel, false);
2369  }
2370 
2371  private Set<RelColumnMapping> getColumnMappings(SqlOperator op) {
2372  SqlReturnTypeInference rti = op.getReturnTypeInference();
2373  if (rti == null) {
2374  return null;
2375  }
2376  if (rti instanceof TableFunctionReturnTypeInference) {
2377  TableFunctionReturnTypeInference tfrti = (TableFunctionReturnTypeInference) rti;
2378  return tfrti.getColumnMappings();
2379  } else {
2380  return null;
2381  }
2382  }
2383 
2389  private static class RexAccessShuttle extends RexShuttle {
2390  private final RexBuilder builder;
2391  private final RexCorrelVariable rexCorrel;
2392  private final BitSet varCols = new BitSet();
2393 
2394  RexAccessShuttle(RexBuilder builder, RexCorrelVariable rexCorrel) {
2395  this.builder = builder;
2396  this.rexCorrel = rexCorrel;
2397  }
2398 
2399  @Override
2400  public RexNode visitInputRef(RexInputRef input) {
2401  int i = input.getIndex() - rexCorrel.getType().getFieldCount();
2402  if (i < 0) {
2403  varCols.set(input.getIndex());
2404  return builder.makeFieldAccess(rexCorrel, input.getIndex());
2405  }
2406  return builder.makeInputRef(input.getType(), i);
2407  }
2408  }
2409 
2410  protected RelNode createJoin(Blackboard bb,
2411  RelNode leftRel,
2412  RelNode rightRel,
2413  RexNode joinCond,
2414  JoinRelType joinType) {
2415  assert joinCond != null;
2416 
2417  final CorrelationUse p = getCorrelationUse(bb, rightRel);
2418  if (p != null) {
2419  RelNode innerRel = p.r;
2420  ImmutableBitSet requiredCols = p.requiredColumns;
2421 
2422  if (!joinCond.isAlwaysTrue()) {
2423  final RelFactories.FilterFactory factory = RelFactories.DEFAULT_FILTER_FACTORY;
2424  final RexCorrelVariable rexCorrel =
2425  (RexCorrelVariable) rexBuilder.makeCorrel(leftRel.getRowType(), p.id);
2426  final RexAccessShuttle shuttle = new RexAccessShuttle(rexBuilder, rexCorrel);
2427 
2428  // Replace outer RexInputRef with RexFieldAccess,
2429  // and push lateral join predicate into inner child
2430  final RexNode newCond = joinCond.accept(shuttle);
2431  innerRel = factory.createFilter(p.r, newCond, ImmutableSet.of());
2432  requiredCols =
2433  ImmutableBitSet.fromBitSet(shuttle.varCols).union(p.requiredColumns);
2434  }
2435 
2436  LogicalCorrelate corr =
2437  LogicalCorrelate.create(leftRel, innerRel, p.id, requiredCols, joinType);
2438  return corr;
2439  }
2440 
2441  final Join originalJoin = (Join) RelFactories.DEFAULT_JOIN_FACTORY.createJoin(leftRel,
2442  rightRel,
2443  ImmutableList.of(),
2444  joinCond,
2445  ImmutableSet.of(),
2446  joinType,
2447  false);
2448 
2449  RelNode node;
2450 
2451  boolean applyPushdown =
2452  config.getPushdownJoinCondition().test(bb.getTopNode(), originalJoin);
2453  if (applyPushdown) {
2454  node = RelOptUtil.pushDownJoinConditions(originalJoin, relBuilder);
2455  } else {
2456  node = originalJoin;
2457  }
2458 
2459  // If join conditions are pushed down, update the leaves.
2460  if (node instanceof Project) {
2461  final Join newJoin = (Join) node.getInputs().get(0);
2462  if (leaves.containsKey(leftRel)) {
2463  leaves.put(newJoin.getLeft(), leaves.get(leftRel));
2464  }
2465  if (leaves.containsKey(rightRel)) {
2466  leaves.put(newJoin.getRight(), leaves.get(rightRel));
2467  }
2468  }
2469  return node;
2470  }
2471 
2472  private CorrelationUse getCorrelationUse(Blackboard bb, final RelNode r0) {
2473  final Set<CorrelationId> correlatedVariables = RelOptUtil.getVariablesUsed(r0);
2474  if (correlatedVariables.isEmpty()) {
2475  return null;
2476  }
2477  final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
2478  final List<CorrelationId> correlNames = new ArrayList<>();
2479 
2480  // All correlations must refer the same namespace since correlation
2481  // produces exactly one correlation source.
2482  // The same source might be referenced by different variables since
2483  // DeferredLookups are not de-duplicated at create time.
2484  SqlValidatorNamespace prevNs = null;
2485 
2486  for (CorrelationId correlName : correlatedVariables) {
2487  DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
2488  RexFieldAccess fieldAccess = lookup.getFieldAccess(correlName);
2489  String originalRelName = lookup.getOriginalRelName();
2490  String originalFieldName = fieldAccess.getField().getName();
2491 
2492  final SqlNameMatcher nameMatcher =
2493  bb.getValidator().getCatalogReader().nameMatcher();
2494  final SqlValidatorScope.ResolvedImpl resolved =
2495  new SqlValidatorScope.ResolvedImpl();
2496  lookup.bb.scope.resolve(
2497  ImmutableList.of(originalRelName), nameMatcher, false, resolved);
2498  assert resolved.count() == 1;
2499  final SqlValidatorScope.Resolve resolve = resolved.only();
2500  final SqlValidatorNamespace foundNs = resolve.namespace;
2501  final RelDataType rowType = resolve.rowType();
2502  final int childNamespaceIndex = resolve.path.steps().get(0).i;
2503  final SqlValidatorScope ancestorScope = resolve.scope;
2504  boolean correlInCurrentScope = bb.scope.isWithin(ancestorScope);
2505 
2506  if (!correlInCurrentScope) {
2507  continue;
2508  }
2509 
2510  if (prevNs == null) {
2511  prevNs = foundNs;
2512  } else {
2513  assert prevNs
2514  == foundNs : "All correlation variables should resolve"
2515  + " to the same namespace."
2516  + " Prev ns="
2517  + prevNs
2518  + ", new ns="
2519  + foundNs;
2520  }
2521 
2522  int namespaceOffset = 0;
2523  if (childNamespaceIndex > 0) {
2524  // If not the first child, need to figure out the width
2525  // of output types from all the preceding namespaces
2526  assert ancestorScope instanceof ListScope;
2527  List<SqlValidatorNamespace> children = ((ListScope) ancestorScope).getChildren();
2528 
2529  for (int i = 0; i < childNamespaceIndex; i++) {
2530  SqlValidatorNamespace child = children.get(i);
2531  namespaceOffset += child.getRowType().getFieldCount();
2532  }
2533  }
2534 
2535  RexFieldAccess topLevelFieldAccess = fieldAccess;
2536  while (topLevelFieldAccess.getReferenceExpr() instanceof RexFieldAccess) {
2537  topLevelFieldAccess = (RexFieldAccess) topLevelFieldAccess.getReferenceExpr();
2538  }
2539  final RelDataTypeField field = rowType.getFieldList().get(
2540  topLevelFieldAccess.getField().getIndex() - namespaceOffset);
2541  int pos = namespaceOffset + field.getIndex();
2542 
2543  assert field.getType() == topLevelFieldAccess.getField().getType();
2544 
2545  assert pos != -1;
2546 
2547  if (bb.mapRootRelToFieldProjection.containsKey(bb.root)) {
2548  // bb.root is an aggregate and only projects group by
2549  // keys.
2550  Map<Integer, Integer> exprProjection =
2551  bb.mapRootRelToFieldProjection.get(bb.root);
2552 
2553  // sub-query can reference group by keys projected from
2554  // the root of the outer relation.
2555  if (exprProjection.containsKey(pos)) {
2556  pos = exprProjection.get(pos);
2557  } else {
2558  // correl not grouped
2559  throw new AssertionError("Identifier '" + originalRelName + "."
2560  + originalFieldName + "' is not a group expr");
2561  }
2562  }
2563 
2564  requiredColumns.set(pos);
2565  correlNames.add(correlName);
2566  }
2567 
2568  if (correlNames.isEmpty()) {
2569  // None of the correlating variables originated in this scope.
2570  return null;
2571  }
2572 
2573  RelNode r = r0;
2574  if (correlNames.size() > 1) {
2575  // The same table was referenced more than once.
2576  // So we deduplicate.
2577  r = DeduplicateCorrelateVariables.go(
2578  rexBuilder, correlNames.get(0), Util.skip(correlNames), r0);
2579  // Add new node to leaves.
2580  leaves.put(r, r.getRowType().getFieldCount());
2581  }
2582  return new CorrelationUse(correlNames.get(0), requiredColumns.build(), r);
2583  }
2584 
2595  private boolean isSubQueryNonCorrelated(RelNode subq, Blackboard bb) {
2596  Set<CorrelationId> correlatedVariables = RelOptUtil.getVariablesUsed(subq);
2597  for (CorrelationId correlName : correlatedVariables) {
2598  DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
2599  String originalRelName = lookup.getOriginalRelName();
2600 
2601  final SqlNameMatcher nameMatcher =
2602  lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
2603  final SqlValidatorScope.ResolvedImpl resolved =
2604  new SqlValidatorScope.ResolvedImpl();
2605  lookup.bb.scope.resolve(
2606  ImmutableList.of(originalRelName), nameMatcher, false, resolved);
2607 
2608  SqlValidatorScope ancestorScope = resolved.only().scope;
2609 
2610  // If the correlated reference is in a scope that's "above" the
2611  // sub-query, then this is a correlated sub-query.
2612  SqlValidatorScope parentScope = bb.scope;
2613  do {
2614  if (ancestorScope == parentScope) {
2615  return false;
2616  }
2617  if (parentScope instanceof DelegatingScope) {
2618  parentScope = ((DelegatingScope) parentScope).getParent();
2619  } else {
2620  break;
2621  }
2622  } while (parentScope != null);
2623  }
2624  return true;
2625  }
2626 
2632  protected List<RelDataTypeField> getSystemFields() {
2633  return Collections.emptyList();
2634  }
2635 
2636  private RexNode convertJoinCondition(Blackboard bb,
2637  SqlValidatorNamespace leftNamespace,
2638  SqlValidatorNamespace rightNamespace,
2639  SqlNode condition,
2640  JoinConditionType conditionType,
2641  RelNode leftRel,
2642  RelNode rightRel) {
2643  if (condition == null) {
2644  return rexBuilder.makeLiteral(true);
2645  }
2646  bb.setRoot(ImmutableList.of(leftRel, rightRel));
2647  replaceSubQueries(bb, condition, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
2648  switch (conditionType) {
2649  case ON:
2650  bb.setRoot(ImmutableList.of(leftRel, rightRel));
2651  return bb.convertExpression(condition);
2652  case USING:
2653  final SqlNodeList list = (SqlNodeList) condition;
2654  final List<String> nameList = new ArrayList<>();
2655  for (SqlNode columnName : list) {
2656  final SqlIdentifier id = (SqlIdentifier) columnName;
2657  String name = id.getSimple();
2658  nameList.add(name);
2659  }
2660  return convertUsing(leftNamespace, rightNamespace, nameList);
2661  default:
2662  throw Util.unexpected(conditionType);
2663  }
2664  }
2665 
2677  private RexNode convertUsing(SqlValidatorNamespace leftNamespace,
2678  SqlValidatorNamespace rightNamespace,
2679  List<String> nameList) {
2680  final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
2681  final List<RexNode> list = new ArrayList<>();
2682  for (String name : nameList) {
2683  List<RexNode> operands = new ArrayList<>();
2684  int offset = 0;
2685  for (SqlValidatorNamespace n : ImmutableList.of(leftNamespace, rightNamespace)) {
2686  final RelDataType rowType = n.getRowType();
2687  final RelDataTypeField field = nameMatcher.field(rowType, name);
2688  operands.add(rexBuilder.makeInputRef(field.getType(), offset + field.getIndex()));
2689  offset += rowType.getFieldList().size();
2690  }
2691  list.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, operands));
2692  }
2693  return RexUtil.composeConjunction(rexBuilder, list);
2694  }
2695 
2696  private static JoinRelType convertJoinType(JoinType joinType) {
2697  switch (joinType) {
2698  case COMMA:
2699  case INNER:
2700  case CROSS:
2701  return JoinRelType.INNER;
2702  case FULL:
2703  return JoinRelType.FULL;
2704  case LEFT:
2705  return JoinRelType.LEFT;
2706  case RIGHT:
2707  return JoinRelType.RIGHT;
2708  default:
2709  throw Util.unexpected(joinType);
2710  }
2711  }
2712 
2726  protected void convertAgg(
2727  Blackboard bb, SqlSelect select, List<SqlNode> orderExprList) {
2728  assert bb.root != null : "precondition: child != null";
2729  SqlNodeList groupList = select.getGroup();
2730  SqlNodeList selectList = select.getSelectList();
2731  SqlNode having = select.getHaving();
2732 
2733  final AggConverter aggConverter = new AggConverter(bb, select);
2734  createAggImpl(bb, aggConverter, selectList, groupList, having, orderExprList);
2735  }
2736 
2737  protected final void createAggImpl(Blackboard bb,
2738  final AggConverter aggConverter,
2739  SqlNodeList selectList,
2740  SqlNodeList groupList,
2741  SqlNode having,
2742  List<SqlNode> orderExprList) {
2743  // Find aggregate functions in SELECT and HAVING clause
2744  final AggregateFinder aggregateFinder = new AggregateFinder();
2745  selectList.accept(aggregateFinder);
2746  if (having != null) {
2747  having.accept(aggregateFinder);
2748  }
2749 
2750  // first replace the sub-queries inside the aggregates
2751  // because they will provide input rows to the aggregates.
2752  replaceSubQueries(bb, aggregateFinder.list, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2753 
2754  // also replace sub-queries inside filters in the aggregates
2756  bb, aggregateFinder.filterList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2757 
2758  // also replace sub-queries inside ordering spec in the aggregates
2759  replaceSubQueries(bb, aggregateFinder.orderList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2760 
2761  // If group-by clause is missing, pretend that it has zero elements.
2762  if (groupList == null) {
2763  groupList = SqlNodeList.EMPTY;
2764  }
2765 
2766  replaceSubQueries(bb, groupList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2767 
2768  // register the group exprs
2769 
2770  // build a map to remember the projections from the top scope to the
2771  // output of the current root.
2772  //
2773  // Calcite allows expressions, not just column references in
2774  // group by list. This is not SQL 2003 compliant, but hey.
2775 
2776  final AggregatingSelectScope scope = aggConverter.aggregatingSelectScope;
2777  final AggregatingSelectScope.Resolved r = scope.resolved.get();
2778  for (SqlNode groupExpr : r.groupExprList) {
2779  aggConverter.addGroupExpr(groupExpr);
2780  }
2781 
2782  final RexNode havingExpr;
2783  final List<Pair<RexNode, String>> projects = new ArrayList<>();
2784 
2785  try {
2786  Preconditions.checkArgument(bb.agg == null, "already in agg mode");
2787  bb.agg = aggConverter;
2788 
2789  // convert the select and having expressions, so that the
2790  // agg converter knows which aggregations are required
2791 
2792  selectList.accept(aggConverter);
2793  // Assert we don't have dangling items left in the stack
2794  assert !aggConverter.inOver;
2795  for (SqlNode expr : orderExprList) {
2796  expr.accept(aggConverter);
2797  assert !aggConverter.inOver;
2798  }
2799  if (having != null) {
2800  having.accept(aggConverter);
2801  assert !aggConverter.inOver;
2802  }
2803 
2804  // compute inputs to the aggregator
2805  List<Pair<RexNode, String>> preExprs = aggConverter.getPreExprs();
2806 
2807  if (preExprs.size() == 0) {
2808  // Special case for COUNT(*), where we can end up with no inputs
2809  // at all. The rest of the system doesn't like 0-tuples, so we
2810  // select a dummy constant here.
2811  final RexNode zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO);
2812  preExprs = ImmutableList.of(Pair.of(zero, (String) null));
2813  }
2814 
2815  final RelNode inputRel = bb.root;
2816 
2817  // Project the expressions required by agg and having.
2818  bb.setRoot(relBuilder.push(inputRel)
2819  .projectNamed(Pair.left(preExprs), Pair.right(preExprs), false)
2820  .build(),
2821  false);
2822  bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
2823 
2824  // REVIEW jvs 31-Oct-2007: doesn't the declaration of
2825  // monotonicity here assume sort-based aggregation at
2826  // the physical level?
2827 
2828  // Tell bb which of group columns are sorted.
2829  bb.columnMonotonicities.clear();
2830  for (SqlNode groupItem : groupList) {
2831  bb.columnMonotonicities.add(bb.scope.getMonotonicity(groupItem));
2832  }
2833 
2834  final RelNode relNode = aggConverter.containsGroupId()
2835  ? rewriteAggregateWithGroupId(bb, r, aggConverter)
2836  : createAggregate(bb, r.groupSet, r.groupSets, aggConverter.getAggCalls());
2837 
2838  bb.setRoot(relNode, false);
2839  bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
2840 
2841  // Replace sub-queries in having here and modify having to use
2842  // the replaced expressions
2843  if (having != null) {
2844  SqlNode newHaving = pushDownNotForIn(bb.scope, having);
2845  replaceSubQueries(bb, newHaving, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
2846  havingExpr = bb.convertExpression(newHaving);
2847  } else {
2848  havingExpr = relBuilder.literal(true);
2849  }
2850 
2851  // Now convert the other sub-queries in the select list.
2852  // This needs to be done separately from the sub-query inside
2853  // any aggregate in the select list, and after the aggregate rel
2854  // is allocated.
2855  replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2856 
2857  // Now sub-queries in the entire select list have been converted.
2858  // Convert the select expressions to get the final list to be
2859  // projected.
2860  int k = 0;
2861 
2862  // For select expressions, use the field names previously assigned
2863  // by the validator. If we derive afresh, we might generate names
2864  // like "EXPR$2" that don't match the names generated by the
2865  // validator. This is especially the case when there are system
2866  // fields; system fields appear in the relnode's rowtype but do not
2867  // (yet) appear in the validator type.
2868  final SelectScope selectScope = SqlValidatorUtil.getEnclosingSelectScope(bb.scope);
2869  assert selectScope != null;
2870  final SqlValidatorNamespace selectNamespace =
2871  validator.getNamespace(selectScope.getNode());
2872  final List<String> names = selectNamespace.getRowType().getFieldNames();
2873  int sysFieldCount = selectList.size() - names.size();
2874  for (SqlNode expr : selectList) {
2875  projects.add(Pair.of(bb.convertExpression(expr),
2876  k < sysFieldCount ? validator.deriveAlias(expr, k++)
2877  : names.get(k++ - sysFieldCount)));
2878  }
2879 
2880  for (SqlNode expr : orderExprList) {
2881  projects.add(
2882  Pair.of(bb.convertExpression(expr), validator.deriveAlias(expr, k++)));
2883  }
2884  } finally {
2885  bb.agg = null;
2886  }
2887 
2888  // implement HAVING (we have already checked that it is non-trivial)
2889  relBuilder.push(bb.root);
2890  if (havingExpr != null) {
2891  relBuilder.filter(havingExpr);
2892  }
2893 
2894  // implement the SELECT list
2895  relBuilder.project(Pair.left(projects), Pair.right(projects))
2896  .rename(Pair.right(projects));
2897  bb.setRoot(relBuilder.build(), false);
2898 
2899  // Tell bb which of group columns are sorted.
2900  bb.columnMonotonicities.clear();
2901  for (SqlNode selectItem : selectList) {
2902  bb.columnMonotonicities.add(bb.scope.getMonotonicity(selectItem));
2903  }
2904  }
2905 
2920  Blackboard bb, AggregatingSelectScope.Resolved r, AggConverter converter) {
2921  final List<AggregateCall> aggregateCalls = converter.getAggCalls();
2922  final ImmutableBitSet groupSet = r.groupSet;
2923  final Map<ImmutableBitSet, Integer> groupSetCount = r.groupSetCount;
2924 
2925  final List<String> fieldNamesIfNoRewrite =
2926  createAggregate(bb, groupSet, r.groupSets, aggregateCalls)
2927  .getRowType()
2928  .getFieldNames();
2929 
2930  // If n duplicates exist for a particular grouping, the {@code GROUP_ID()}
2931  // function produces values in the range 0 to n-1. For each value,
2932  // we need to figure out the corresponding group sets.
2933  //
2934  // For example, "... GROUPING SETS (a, a, b, c, c, c, c)"
2935  // (i) The max value of the GROUP_ID() function returns is 3
2936  // (ii) GROUPING SETS (a, b, c) produces value 0,
2937  // GROUPING SETS (a, c) produces value 1,
2938  // GROUPING SETS (c) produces value 2
2939  // GROUPING SETS (c) produces value 3
2940  final Map<Integer, Set<ImmutableBitSet>> groupIdToGroupSets = new HashMap<>();
2941  int maxGroupId = 0;
2942  for (Map.Entry<ImmutableBitSet, Integer> entry : groupSetCount.entrySet()) {
2943  int groupId = entry.getValue() - 1;
2944  if (groupId > maxGroupId) {
2945  maxGroupId = groupId;
2946  }
2947  for (int i = 0; i <= groupId; i++) {
2948  groupIdToGroupSets
2949  .computeIfAbsent(i, k -> Sets.newTreeSet(ImmutableBitSet.COMPARATOR))
2950  .add(entry.getKey());
2951  }
2952  }
2953 
2954  // AggregateCall list without GROUP_ID function
2955  final List<AggregateCall> aggregateCallsWithoutGroupId = new ArrayList<>();
2956  for (AggregateCall aggregateCall : aggregateCalls) {
2957  if (aggregateCall.getAggregation().kind != SqlKind.GROUP_ID) {
2958  aggregateCallsWithoutGroupId.add(aggregateCall);
2959  }
2960  }
2961  final List<RelNode> projects = new ArrayList<>();
2962  // For each group id value , we first construct an Aggregate without
2963  // GROUP_ID() function call, and then create a Project node on top of it.
2964  // The Project adds literal value for group id in right position.
2965  for (int groupId = 0; groupId <= maxGroupId; groupId++) {
2966  // Create the Aggregate node without GROUP_ID() call
2967  final ImmutableList<ImmutableBitSet> groupSets =
2968  ImmutableList.copyOf(groupIdToGroupSets.get(groupId));
2969  final RelNode aggregate =
2970  createAggregate(bb, groupSet, groupSets, aggregateCallsWithoutGroupId);
2971 
2972  // RexLiteral for each GROUP_ID, note the type should be BIGINT
2973  final RelDataType groupIdType = typeFactory.createSqlType(SqlTypeName.BIGINT);
2974  final RexNode groupIdLiteral =
2975  rexBuilder.makeExactLiteral(BigDecimal.valueOf(groupId), groupIdType);
2976 
2977  relBuilder.push(aggregate);
2978  final List<RexNode> selectList = new ArrayList<>();
2979  final int groupExprLength = r.groupExprList.size();
2980  // Project fields in group by expressions
2981  for (int i = 0; i < groupExprLength; i++) {
2982  selectList.add(relBuilder.field(i));
2983  }
2984  // Project fields in aggregate calls
2985  int groupIdCount = 0;
2986  for (int i = 0; i < aggregateCalls.size(); i++) {
2987  if (aggregateCalls.get(i).getAggregation().kind == SqlKind.GROUP_ID) {
2988  selectList.add(groupIdLiteral);
2989  groupIdCount++;
2990  } else {
2991  int ordinal = groupExprLength + i - groupIdCount;
2992  selectList.add(relBuilder.field(ordinal));
2993  }
2994  }
2995  final RelNode project =
2996  relBuilder.project(selectList, fieldNamesIfNoRewrite).build();
2997  projects.add(project);
2998  }
2999  // Skip to create Union when there is only one child, i.e., no duplicate group
3000  // set.
3001  if (projects.size() == 1) {
3002  return projects.get(0);
3003  }
3004  return LogicalUnion.create(projects, true);
3005  }
3006 
3026  protected RelNode createAggregate(Blackboard bb,
3027  ImmutableBitSet groupSet,
3028  ImmutableList<ImmutableBitSet> groupSets,
3029  List<AggregateCall> aggCalls) {
3030  return LogicalAggregate.create(
3031  bb.root, ImmutableList.of(), groupSet, groupSets, aggCalls);
3032  }
3033 
3034  public RexDynamicParam convertDynamicParam(final SqlDynamicParam dynamicParam) {
3035  // REVIEW jvs 8-Jan-2005: dynamic params may be encountered out of
3036  // order. Should probably cross-check with the count from the parser
3037  // at the end and make sure they all got filled in. Why doesn't List
3038  // have a resize() method?!? Make this a utility.
3039  while (dynamicParam.getIndex() >= dynamicParamSqlNodes.size()) {
3040  dynamicParamSqlNodes.add(null);
3041  }
3042 
3043  dynamicParamSqlNodes.set(dynamicParam.getIndex(), dynamicParam);
3044  return rexBuilder.makeDynamicParam(
3045  getDynamicParamType(dynamicParam.getIndex()), dynamicParam.getIndex());
3046  }
3047 
3062  protected void gatherOrderExprs(Blackboard bb,
3063  SqlSelect select,
3064  SqlNodeList orderList,
3065  List<SqlNode> extraOrderExprs,
3066  List<RelFieldCollation> collationList) {
3067  // TODO: add validation rules to SqlValidator also
3068  assert bb.root != null : "precondition: child != null";
3069  assert select != null;
3070  if (orderList == null) {
3071  return;
3072  }
3073 
3074  if (!bb.top) {
3075  SqlNode offset = select.getOffset();
3076  if ((offset == null
3077  || (offset instanceof SqlLiteral
3078  && ((SqlLiteral) offset)
3079  .bigDecimalValue()
3080  .equals(BigDecimal.ZERO)))
3081  && select.getFetch() == null) {
3082  return;
3083  }
3084  }
3085 
3086  for (SqlNode orderItem : orderList) {
3087  collationList.add(convertOrderItem(select,
3088  orderItem,
3089  extraOrderExprs,
3090  RelFieldCollation.Direction.ASCENDING,
3091  RelFieldCollation.NullDirection.UNSPECIFIED));
3092  }
3093  }
3094 
3095  protected RelFieldCollation convertOrderItem(SqlSelect select,
3096  SqlNode orderItem,
3097  List<SqlNode> extraExprs,
3098  RelFieldCollation.Direction direction,
3099  RelFieldCollation.NullDirection nullDirection) {
3100  assert select != null;
3101  // Handle DESC keyword, e.g. 'select a, b from t order by a desc'.
3102  switch (orderItem.getKind()) {
3103  case DESCENDING:
3104  return convertOrderItem(select,
3105  ((SqlCall) orderItem).operand(0),
3106  extraExprs,
3107  RelFieldCollation.Direction.DESCENDING,
3108  nullDirection);
3109  case NULLS_FIRST:
3110  return convertOrderItem(select,
3111  ((SqlCall) orderItem).operand(0),
3112  extraExprs,
3113  direction,
3114  RelFieldCollation.NullDirection.FIRST);
3115  case NULLS_LAST:
3116  return convertOrderItem(select,
3117  ((SqlCall) orderItem).operand(0),
3118  extraExprs,
3119  direction,
3120  RelFieldCollation.NullDirection.LAST);
3121  }
3122 
3123  SqlNode converted = validator.expandOrderExpr(select, orderItem);
3124 
3125  switch (nullDirection) {
3126  case UNSPECIFIED:
3127  nullDirection = validator.getDefaultNullCollation().last(desc(direction))
3128  ? RelFieldCollation.NullDirection.LAST
3129  : RelFieldCollation.NullDirection.FIRST;
3130  }
3131 
3132  // Scan the select list and order exprs for an identical expression.
3133  final SelectScope selectScope = validator.getRawSelectScope(select);
3134  int ordinal = -1;
3135  for (SqlNode selectItem : selectScope.getExpandedSelectList()) {
3136  ++ordinal;
3137  if (converted.equalsDeep(stripAs(selectItem), Litmus.IGNORE)) {
3138  return new RelFieldCollation(ordinal, direction, nullDirection);
3139  }
3140  }
3141 
3142  for (SqlNode extraExpr : extraExprs) {
3143  ++ordinal;
3144  if (converted.equalsDeep(extraExpr, Litmus.IGNORE)) {
3145  return new RelFieldCollation(ordinal, direction, nullDirection);
3146  }
3147  }
3148 
3149  // TODO: handle collation sequence
3150  // TODO: flag expressions as non-standard
3151 
3152  extraExprs.add(converted);
3153  return new RelFieldCollation(ordinal + 1, direction, nullDirection);
3154  }
3155 
3156  private static boolean desc(RelFieldCollation.Direction direction) {
3157  switch (direction) {
3158  case DESCENDING:
3159  case STRICTLY_DESCENDING:
3160  return true;
3161  default:
3162  return false;
3163  }
3164  }
3165 
3166  @Deprecated // to be removed before 2.0
3167  protected boolean enableDecorrelation() {
3168  // disable sub-query decorrelation when needed.
3169  // e.g. if outer joins are not supported.
3170  return config.isDecorrelationEnabled();
3171  }
3172 
3173  protected RelNode decorrelateQuery(RelNode rootRel) {
3174  return RelDecorrelator.decorrelateQuery(rootRel, relBuilder);
3175  }
3176 
3182  @Deprecated // to be removed before 2.0
3183  public boolean isTrimUnusedFields() {
3184  return config.isTrimUnusedFields();
3185  }
3186 
3196  protected RelRoot convertQueryRecursive(
3197  SqlNode query, boolean top, RelDataType targetRowType) {
3198  final SqlKind kind = query.getKind();
3199  switch (kind) {
3200  case SELECT:
3201  return RelRoot.of(convertSelect((SqlSelect) query, top), kind);
3202  case INSERT:
3203  return RelRoot.of(convertInsert((SqlInsert) query), kind);
3204  case DELETE:
3205  return RelRoot.of(convertDelete((SqlDelete) query), kind);
3206  case UPDATE:
3207  return RelRoot.of(convertUpdate((SqlUpdate) query), kind);
3208  case MERGE:
3209  return RelRoot.of(convertMerge((SqlMerge) query), kind);
3210  case UNION:
3211  case INTERSECT:
3212  case EXCEPT:
3213  return RelRoot.of(convertSetOp((SqlCall) query), kind);
3214  case WITH:
3215  return convertWith((SqlWith) query, top);
3216  case VALUES:
3217  return RelRoot.of(convertValues((SqlCall) query, targetRowType), kind);
3218  default:
3219  throw new AssertionError("not a query: " + query);
3220  }
3221  }
3222 
3230  protected RelNode convertSetOp(SqlCall call) {
3231  final RelNode left = convertQueryRecursive(call.operand(0), false, null).project();
3232  final RelNode right = convertQueryRecursive(call.operand(1), false, null).project();
3233  switch (call.getKind()) {
3234  case UNION:
3235  return LogicalUnion.create(ImmutableList.of(left, right), all(call));
3236 
3237  case INTERSECT:
3238  return LogicalIntersect.create(ImmutableList.of(left, right), all(call));
3239 
3240  case EXCEPT:
3241  return LogicalMinus.create(ImmutableList.of(left, right), all(call));
3242 
3243  default:
3244  throw Util.unexpected(call.getKind());
3245  }
3246  }
3247 
3248  private boolean all(SqlCall call) {
3249  return ((SqlSetOperator) call.getOperator()).isAll();
3250  }
3251 
3252  protected RelNode convertInsert(SqlInsert call) {
3253  RelOptTable targetTable = getTargetTable(call);
3254 
3255  final RelDataType targetRowType = validator.getValidatedNodeType(call);
3256  assert targetRowType != null;
3257  RelNode sourceRel =
3258  convertQueryRecursive(call.getSource(), true, targetRowType).project();
3259  RelNode massagedRel = convertColumnList(call, sourceRel);
3260 
3261  return createModify(targetTable, massagedRel);
3262  }
3263 
3265  private RelNode createModify(RelOptTable targetTable, RelNode source) {
3266  final ModifiableTable modifiableTable = targetTable.unwrap(ModifiableTable.class);
3267  if (modifiableTable != null && modifiableTable == targetTable.unwrap(Table.class)) {
3268  return modifiableTable.toModificationRel(cluster,
3269  targetTable,
3270  catalogReader,
3271  source,
3272  LogicalTableModify.Operation.INSERT,
3273  null,
3274  null,
3275  false);
3276  }
3277  final ModifiableView modifiableView = targetTable.unwrap(ModifiableView.class);
3278  if (modifiableView != null) {
3279  final Table delegateTable = modifiableView.getTable();
3280  final RelDataType delegateRowType = delegateTable.getRowType(typeFactory);
3281  final RelOptTable delegateRelOptTable = RelOptTableImpl.create(
3282  null, delegateRowType, delegateTable, modifiableView.getTablePath());
3283  final RelNode newSource =
3284  createSource(targetTable, source, modifiableView, delegateRowType);
3285  return createModify(delegateRelOptTable, newSource);
3286  }
3287  return LogicalTableModify.create(targetTable,
3288  catalogReader,
3289  source,
3290  LogicalTableModify.Operation.INSERT,
3291  null,
3292  null,
3293  false);
3294  }
3295 
3309  private RelNode createSource(RelOptTable targetTable,
3310  RelNode source,
3311  ModifiableView modifiableView,
3312  RelDataType delegateRowType) {
3313  final ImmutableIntList mapping = modifiableView.getColumnMapping();
3314  assert mapping.size() == targetTable.getRowType().getFieldCount();
3315 
3316  // For columns represented in the mapping, the expression is just a field
3317  // reference.
3318  final Map<Integer, RexNode> projectMap = new HashMap<>();
3319  final List<RexNode> filters = new ArrayList<>();
3320  for (int i = 0; i < mapping.size(); i++) {
3321  int target = mapping.get(i);
3322  if (target >= 0) {
3323  projectMap.put(target, RexInputRef.of(i, source.getRowType()));
3324  }
3325  }
3326 
3327  // For columns that are not in the mapping, and have a constraint of the
3328  // form "column = value", the expression is the literal "value".
3329  //
3330  // If a column has multiple constraints, the extra ones will become a
3331  // filter.
3332  final RexNode constraint = modifiableView.getConstraint(rexBuilder, delegateRowType);
3333  RelOptUtil.inferViewPredicates(projectMap, filters, constraint);
3334  final List<Pair<RexNode, String>> projects = new ArrayList<>();
3335  for (RelDataTypeField field : delegateRowType.getFieldList()) {
3336  RexNode node = projectMap.get(field.getIndex());
3337  if (node == null) {
3338  node = rexBuilder.makeNullLiteral(field.getType());
3339  }
3340  projects.add(Pair.of(
3341  rexBuilder.ensureType(field.getType(), node, false), field.getName()));
3342  }
3343 
3344  return relBuilder.push(source)
3345  .projectNamed(Pair.left(projects), Pair.right(projects), false)
3346  .filter(filters)
3347  .build();
3348  }
3349 
3350  private RelOptTable.ToRelContext createToRelContext(List<RelHint> hints) {
3351  return ViewExpanders.toRelContext(viewExpander, cluster, hints);
3352  }
3353 
3354  public RelNode toRel(final RelOptTable table, final List<RelHint> hints) {
3355  final RelNode scan = table.toRel(createToRelContext(hints));
3356 
3357  final InitializerExpressionFactory ief =
3358  Util.first(table.unwrap(InitializerExpressionFactory.class),
3359  NullInitializerExpressionFactory.INSTANCE);
3360 
3361  boolean hasVirtualFields = table.getRowType().getFieldList().stream().anyMatch(
3362  f -> ief.generationStrategy(table, f.getIndex()) == ColumnStrategy.VIRTUAL);
3363 
3364  if (hasVirtualFields) {
3365  final RexNode sourceRef = rexBuilder.makeRangeReference(scan);
3367  table, sourceRef, table.getRowType().getFieldNames());
3368  final List<RexNode> list = new ArrayList<>();
3369  for (RelDataTypeField f : table.getRowType().getFieldList()) {
3370  final ColumnStrategy strategy = ief.generationStrategy(table, f.getIndex());
3371  switch (strategy) {
3372  case VIRTUAL:
3373  list.add(ief.newColumnDefaultValue(table, f.getIndex(), bb));
3374  break;
3375  default:
3376  list.add(rexBuilder.makeInputRef(
3377  scan, RelOptTableImpl.realOrdinal(table, f.getIndex())));
3378  }
3379  }
3380  relBuilder.push(scan);
3381  relBuilder.project(list);
3382  final RelNode project = relBuilder.build();
3383  if (ief.postExpressionConversionHook() != null) {
3384  return ief.postExpressionConversionHook().apply(bb, project);
3385  } else {
3386  return project;
3387  }
3388  }
3389 
3390  return scan;
3391  }
3392 
3393  protected RelOptTable getTargetTable(SqlNode call) {
3394  final SqlValidatorNamespace targetNs = validator.getNamespace(call);
3395  if (targetNs.isWrapperFor(SqlValidatorImpl.DmlNamespace.class)) {
3396  final SqlValidatorImpl.DmlNamespace dmlNamespace =
3397  targetNs.unwrap(SqlValidatorImpl.DmlNamespace.class);
3398  return SqlValidatorUtil.getRelOptTable(dmlNamespace, catalogReader, null, null);
3399  }
3400  final SqlValidatorNamespace resolvedNamespace = targetNs.resolve();
3401  return SqlValidatorUtil.getRelOptTable(resolvedNamespace, catalogReader, null, null);
3402  }
3403 
3421  protected RelNode convertColumnList(final SqlInsert call, RelNode source) {
3422  RelDataType sourceRowType = source.getRowType();
3423  final RexNode sourceRef = rexBuilder.makeRangeReference(sourceRowType, 0, false);
3424  final List<String> targetColumnNames = new ArrayList<>();
3425  final List<RexNode> columnExprs = new ArrayList<>();
3426  collectInsertTargets(call, sourceRef, targetColumnNames, columnExprs);
3427 
3428  final RelOptTable targetTable = getTargetTable(call);
3429  final RelDataType targetRowType = RelOptTableImpl.realRowType(targetTable);
3430  final List<RelDataTypeField> targetFields = targetRowType.getFieldList();
3431  final List<RexNode> sourceExps =
3432  new ArrayList<>(Collections.nCopies(targetFields.size(), null));
3433  final List<String> fieldNames =
3434  new ArrayList<>(Collections.nCopies(targetFields.size(), null));
3435 
3436  final InitializerExpressionFactory initializerFactory =
3437  getInitializerFactory(validator.getNamespace(call).getTable());
3438 
3439  // Walk the name list and place the associated value in the
3440  // expression list according to the ordinal value returned from
3441  // the table construct, leaving nulls in the list for columns
3442  // that are not referenced.
3443  final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
3444  for (Pair<String, RexNode> p : Pair.zip(targetColumnNames, columnExprs)) {
3445  RelDataTypeField field = nameMatcher.field(targetRowType, p.left);
3446  assert field != null : "column " + p.left + " not found";
3447  sourceExps.set(field.getIndex(), p.right);
3448  }
3449 
3450  // Lazily create a blackboard that contains all non-generated columns.
3451  final Supplier<Blackboard> bb =
3452  () -> createInsertBlackboard(targetTable, sourceRef, targetColumnNames);
3453 
3454  // Walk the expression list and get default values for any columns
3455  // that were not supplied in the statement. Get field names too.
3456  for (int i = 0; i < targetFields.size(); ++i) {
3457  final RelDataTypeField field = targetFields.get(i);
3458  final String fieldName = field.getName();
3459  fieldNames.set(i, fieldName);
3460  if (sourceExps.get(i) == null || sourceExps.get(i).getKind() == SqlKind.DEFAULT) {
3461  sourceExps.set(
3462  i, initializerFactory.newColumnDefaultValue(targetTable, i, bb.get()));
3463 
3464  // bare nulls are dangerous in the wrong hands
3465  sourceExps.set(i, castNullLiteralIfNeeded(sourceExps.get(i), field.getType()));
3466  }
3467  }
3468 
3469  return relBuilder.push(source).projectNamed(sourceExps, fieldNames, false).build();
3470  }
3471 
3477  RelOptTable targetTable, RexNode sourceRef, List<String> targetColumnNames) {
3478  final Map<String, RexNode> nameToNodeMap = new HashMap<>();
3479  int j = 0;
3480 
3481  // Assign expressions for non-generated columns.
3482  final List<ColumnStrategy> strategies = targetTable.getColumnStrategies();
3483  final List<String> targetFields = targetTable.getRowType().getFieldNames();
3484  for (String targetColumnName : targetColumnNames) {
3485  final int i = targetFields.indexOf(targetColumnName);
3486  switch (strategies.get(i)) {
3487  case STORED:
3488  case VIRTUAL:
3489  break;
3490  default:
3491  nameToNodeMap.put(targetColumnName, rexBuilder.makeFieldAccess(sourceRef, j++));
3492  }
3493  }
3494  return createBlackboard(null, nameToNodeMap, false);
3495  }
3496 
3497  private InitializerExpressionFactory getInitializerFactory(
3498  SqlValidatorTable validatorTable) {
3499  // We might unwrap a null instead of a InitializerExpressionFactory.
3500  final Table table = unwrap(validatorTable, Table.class);
3501  if (table != null) {
3502  InitializerExpressionFactory f = unwrap(table, InitializerExpressionFactory.class);
3503  if (f != null) {
3504  return f;
3505  }
3506  }
3507  return NullInitializerExpressionFactory.INSTANCE;
3508  }
3509 
3510  private static <T> T unwrap(Object o, Class<T> clazz) {
3511  if (o instanceof Wrapper) {
3512  return ((Wrapper) o).unwrap(clazz);
3513  }
3514  return null;
3515  }
3516 
3517  private RexNode castNullLiteralIfNeeded(RexNode node, RelDataType type) {
3518  if (!RexLiteral.isNullLiteral(node)) {
3519  return node;
3520  }
3521  return rexBuilder.makeCast(type, node);
3522  }
3523 
3534  protected void collectInsertTargets(SqlInsert call,
3535  final RexNode sourceRef,
3536  final List<String> targetColumnNames,
3537  List<RexNode> columnExprs) {
3538  final RelOptTable targetTable = getTargetTable(call);
3539  final RelDataType tableRowType = targetTable.getRowType();
3540  SqlNodeList targetColumnList = call.getTargetColumnList();
3541  if (targetColumnList == null) {
3542  if (validator.getConformance().isInsertSubsetColumnsAllowed()) {
3543  final RelDataType targetRowType =
3544  typeFactory.createStructType(tableRowType.getFieldList().subList(
3545  0, sourceRef.getType().getFieldCount()));
3546  targetColumnNames.addAll(targetRowType.getFieldNames());
3547  } else {
3548  targetColumnNames.addAll(tableRowType.getFieldNames());
3549  }
3550  } else {
3551  for (int i = 0; i < targetColumnList.size(); i++) {
3552  SqlIdentifier id = (SqlIdentifier) targetColumnList.get(i);
3553  RelDataTypeField field = SqlValidatorUtil.getTargetField(
3554  tableRowType, typeFactory, id, catalogReader, targetTable);
3555  assert field != null : "column " + id.toString() + " not found";
3556  targetColumnNames.add(field.getName());
3557  }
3558  }
3559 
3560  final Blackboard bb =
3561  createInsertBlackboard(targetTable, sourceRef, targetColumnNames);
3562 
3563  // Next, assign expressions for generated columns.
3564  final List<ColumnStrategy> strategies = targetTable.getColumnStrategies();
3565  for (String columnName : targetColumnNames) {
3566  final int i = tableRowType.getFieldNames().indexOf(columnName);
3567  final RexNode expr;
3568  switch (strategies.get(i)) {
3569  case STORED:
3570  final InitializerExpressionFactory f =
3571  Util.first(targetTable.unwrap(InitializerExpressionFactory.class),
3572  NullInitializerExpressionFactory.INSTANCE);
3573  expr = f.newColumnDefaultValue(targetTable, i, bb);
3574  break;
3575  case VIRTUAL:
3576  expr = null;
3577  break;
3578  default:
3579  expr = bb.nameToNodeMap.get(columnName);
3580  }
3581  columnExprs.add(expr);
3582  }
3583 
3584  // Remove virtual columns from the list.
3585  for (int i = 0; i < targetColumnNames.size(); i++) {
3586  if (columnExprs.get(i) == null) {
3587  columnExprs.remove(i);
3588  targetColumnNames.remove(i);
3589  --i;
3590  }
3591  }
3592  }
3593 
3594  private RelNode convertDelete(SqlDelete call) {
3595  RelOptTable targetTable = getTargetTable(call);
3596  RelNode sourceRel = convertSelect(call.getSourceSelect(), false);
3597  return LogicalTableModify.create(targetTable,
3598  catalogReader,
3599  sourceRel,
3600  LogicalTableModify.Operation.DELETE,
3601  null,
3602  null,
3603  false);
3604  }
3605 
3606  private RelNode convertUpdate(SqlUpdate call) {
3607  final SqlValidatorScope scope = validator.getWhereScope(call.getSourceSelect());
3608  Blackboard bb = createBlackboard(scope, null, false);
3609 
3610  replaceSubQueries(bb, call, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
3611 
3612  RelOptTable targetTable = getTargetTable(call);
3613 
3614  // convert update column list from SqlIdentifier to String
3615  final List<String> targetColumnNameList = new ArrayList<>();
3616  final RelDataType targetRowType = targetTable.getRowType();
3617  for (SqlNode node : call.getTargetColumnList()) {
3618  SqlIdentifier id = (SqlIdentifier) node;
3619  RelDataTypeField field = SqlValidatorUtil.getTargetField(
3620  targetRowType, typeFactory, id, catalogReader, targetTable);
3621  assert field != null : "column " + id.toString() + " not found";
3622  targetColumnNameList.add(field.getName());
3623  }
3624 
3625  RelNode sourceRel = convertSelect(call.getSourceSelect(), false);
3626 
3627  bb.setRoot(sourceRel, false);
3628  Builder<RexNode> rexNodeSourceExpressionListBuilder = ImmutableList.builder();
3629  for (SqlNode n : call.getSourceExpressionList()) {
3630  RexNode rn = bb.convertExpression(n);
3631  rexNodeSourceExpressionListBuilder.add(rn);
3632  }
3633 
3634  return LogicalTableModify.create(targetTable,
3635  catalogReader,
3636  sourceRel,
3637  LogicalTableModify.Operation.UPDATE,
3638  targetColumnNameList,
3639  rexNodeSourceExpressionListBuilder.build(),
3640  false);
3641  }
3642 
3643  private RelNode convertMerge(SqlMerge call) {
3644  RelOptTable targetTable = getTargetTable(call);
3645 
3646  // convert update column list from SqlIdentifier to String
3647  final List<String> targetColumnNameList = new ArrayList<>();
3648  final RelDataType targetRowType = targetTable.getRowType();
3649  SqlUpdate updateCall = call.getUpdateCall();
3650  if (updateCall != null) {
3651  for (SqlNode targetColumn : updateCall.getTargetColumnList()) {
3652  SqlIdentifier id = (SqlIdentifier) targetColumn;
3653  RelDataTypeField field = SqlValidatorUtil.getTargetField(
3654  targetRowType, typeFactory, id, catalogReader, targetTable);
3655  assert field != null : "column " + id.toString() + " not found";
3656  targetColumnNameList.add(field.getName());
3657  }
3658  }
3659 
3660  // replace the projection of the source select with a
3661  // projection that contains the following:
3662  // 1) the expressions corresponding to the new insert row (if there is
3663  // an insert)
3664  // 2) all columns from the target table (if there is an update)
3665  // 3) the set expressions in the update call (if there is an update)
3666 
3667  // first, convert the merge's source select to construct the columns
3668  // from the target table and the set expressions in the update call
3669  RelNode mergeSourceRel = convertSelect(call.getSourceSelect(), false);
3670 
3671  // then, convert the insert statement so we can get the insert
3672  // values expressions
3673  SqlInsert insertCall = call.getInsertCall();
3674  int nLevel1Exprs = 0;
3675  List<RexNode> level1InsertExprs = null;
3676  List<RexNode> level2InsertExprs = null;
3677  if (insertCall != null) {
3678  RelNode insertRel = convertInsert(insertCall);
3679 
3680  // if there are 2 level of projections in the insert source, combine
3681  // them into a single project; level1 refers to the topmost project;
3682  // the level1 projection contains references to the level2
3683  // expressions, except in the case where no target expression was
3684  // provided, in which case, the expression is the default value for
3685  // the column; or if the expressions directly map to the source
3686  // table
3687  level1InsertExprs = ((LogicalProject) insertRel.getInput(0)).getProjects();
3688  if (insertRel.getInput(0).getInput(0) instanceof LogicalProject) {
3689  level2InsertExprs =
3690  ((LogicalProject) insertRel.getInput(0).getInput(0)).getProjects();
3691  }
3692  nLevel1Exprs = level1InsertExprs.size();
3693  }
3694 
3695  LogicalJoin join = (LogicalJoin) mergeSourceRel.getInput(0);
3696  int nSourceFields = join.getLeft().getRowType().getFieldCount();
3697  final List<RexNode> projects = new ArrayList<>();
3698  for (int level1Idx = 0; level1Idx < nLevel1Exprs; level1Idx++) {
3699  if ((level2InsertExprs != null)
3700  && (level1InsertExprs.get(level1Idx) instanceof RexInputRef)) {
3701  int level2Idx = ((RexInputRef) level1InsertExprs.get(level1Idx)).getIndex();
3702  projects.add(level2InsertExprs.get(level2Idx));
3703  } else {
3704  projects.add(level1InsertExprs.get(level1Idx));
3705  }
3706  }
3707  if (updateCall != null) {
3708  final LogicalProject project = (LogicalProject) mergeSourceRel;
3709  projects.addAll(Util.skip(project.getProjects(), nSourceFields));
3710  }
3711 
3712  relBuilder.push(join).project(projects);
3713 
3714  return LogicalTableModify.create(targetTable,
3715  catalogReader,
3716  relBuilder.build(),
3717  LogicalTableModify.Operation.MERGE,
3718  targetColumnNameList,
3719  null,
3720  false);
3721  }
3722 
3727  private RexNode convertIdentifier(Blackboard bb, SqlIdentifier identifier) {
3728  // first check for reserved identifiers like CURRENT_USER
3729  final SqlCall call = bb.getValidator().makeNullaryCall(identifier);
3730  if (call != null) {
3731  return bb.convertExpression(call);
3732  }
3733 
3734  String pv = null;
3735  if (bb.isPatternVarRef && identifier.names.size() > 1) {
3736  pv = identifier.names.get(0);
3737  }
3738 
3739  final SqlQualified qualified;
3740  if (bb.scope != null) {
3741  qualified = bb.scope.fullyQualify(identifier);
3742  } else {
3743  qualified = SqlQualified.create(null, 1, null, identifier);
3744  }
3745  final Pair<RexNode, Map<String, Integer>> e0 = bb.lookupExp(qualified);
3746  RexNode e = e0.left;
3747  for (String name : qualified.suffix()) {
3748  if (e == e0.left && e0.right != null) {
3749  int i = e0.right.get(name);
3750  e = rexBuilder.makeFieldAccess(e, i);
3751  } else {
3752  final boolean caseSensitive = true; // name already fully-qualified
3753  if (identifier.isStar() && bb.scope instanceof MatchRecognizeScope) {
3754  e = rexBuilder.makeFieldAccess(e, 0);
3755  } else {
3756  e = rexBuilder.makeFieldAccess(e, name, caseSensitive);
3757  }
3758  }
3759  }
3760  if (e instanceof RexInputRef) {
3761  // adjust the type to account for nulls introduced by outer joins
3762  e = adjustInputRef(bb, (RexInputRef) e);
3763  if (pv != null) {
3764  e = RexPatternFieldRef.of(pv, (RexInputRef) e);
3765  }
3766  }
3767 
3768  if (e0.left instanceof RexCorrelVariable) {
3769  assert e instanceof RexFieldAccess;
3770  final RexNode prev = bb.mapCorrelateToRex.put(
3771  ((RexCorrelVariable) e0.left).id, (RexFieldAccess) e);
3772  assert prev == null;
3773  }
3774  return e;
3775  }
3776 
3786  protected RexNode adjustInputRef(Blackboard bb, RexInputRef inputRef) {
3787  RelDataTypeField field = bb.getRootField(inputRef);
3788  if (field != null) {
3789  return rexBuilder.makeInputRef(field.getType(), inputRef.getIndex());
3790  }
3791  return inputRef;
3792  }
3793 
3801  private RelNode convertRowConstructor(Blackboard bb, SqlCall rowConstructor) {
3802  Preconditions.checkArgument(isRowConstructor(rowConstructor));
3803  final List<SqlNode> operands = rowConstructor.getOperandList();
3804  return convertMultisets(operands, bb);
3805  }
3806 
3807  private RelNode convertCursor(Blackboard bb, SubQuery subQuery) {
3808  final SqlCall cursorCall = (SqlCall) subQuery.node;
3809  assert cursorCall.operandCount() == 1;
3810  SqlNode query = cursorCall.operand(0);
3811  RelNode converted = convertQuery(query, false, false).rel;
3812  int iCursor = bb.cursors.size();
3813  bb.cursors.add(converted);
3814  subQuery.expr = new RexInputRef(iCursor, converted.getRowType());
3815  return converted;
3816  }
3817 
3818  private RelNode convertMultisets(final List<SqlNode> operands, Blackboard bb) {
3819  // NOTE: Wael 2/04/05: this implementation is not the most efficient in
3820  // terms of planning since it generates XOs that can be reduced.
3821  final List<Object> joinList = new ArrayList<>();
3822  List<SqlNode> lastList = new ArrayList<>();
3823  for (int i = 0; i < operands.size(); i++) {
3824  SqlNode operand = operands.get(i);
3825  if (!(operand instanceof SqlCall)) {
3826  lastList.add(operand);
3827  continue;
3828  }
3829 
3830  final SqlCall call = (SqlCall) operand;
3831  final RelNode input;
3832  switch (call.getKind()) {
3833  case MULTISET_VALUE_CONSTRUCTOR:
3834  case ARRAY_VALUE_CONSTRUCTOR:
3835  final SqlNodeList list =
3836  new SqlNodeList(call.getOperandList(), call.getParserPosition());
3837  CollectNamespace nss = (CollectNamespace) validator.getNamespace(call);
3838  Blackboard usedBb;
3839  if (null != nss) {
3840  usedBb = createBlackboard(nss.getScope(), null, false);
3841  } else {
3842  usedBb = createBlackboard(new ListScope(bb.scope) {
3843  public SqlNode getNode() {
3844  return call;
3845  }
3846  }, null, false);
3847  }
3848  RelDataType multisetType = validator.getValidatedNodeType(call);
3849  ((SqlValidatorImpl) validator)
3850  .setValidatedNodeType(list, multisetType.getComponentType());
3851  input = convertQueryOrInList(usedBb, list, null);
3852  break;
3853  case MULTISET_QUERY_CONSTRUCTOR:
3854  case ARRAY_QUERY_CONSTRUCTOR:
3855  final RelRoot root = convertQuery(call.operand(0), false, true);
3856  input = root.rel;
3857  break;
3858  default:
3859  lastList.add(operand);
3860  continue;
3861  }
3862 
3863  if (lastList.size() > 0) {
3864  joinList.add(lastList);
3865  }
3866  lastList = new ArrayList<>();
3867  Collect collect = new Collect(cluster,
3868  cluster.traitSetOf(Convention.NONE),
3869  input,
3870  validator.deriveAlias(call, i));
3871  joinList.add(collect);
3872  }
3873 
3874  if (joinList.size() == 0) {
3875  joinList.add(lastList);
3876  }
3877 
3878  for (int i = 0; i < joinList.size(); i++) {
3879  Object o = joinList.get(i);
3880  if (o instanceof List) {
3881  @SuppressWarnings("unchecked")
3882  List<SqlNode> projectList = (List<SqlNode>) o;
3883  final List<RexNode> selectList = new ArrayList<>();
3884  final List<String> fieldNameList = new ArrayList<>();
3885  for (int j = 0; j < projectList.size(); j++) {
3886  SqlNode operand = projectList.get(j);
3887  selectList.add(bb.convertExpression(operand));
3888 
3889  // REVIEW angel 5-June-2005: Use deriveAliasFromOrdinal
3890  // instead of deriveAlias to match field names from
3891  // SqlRowOperator. Otherwise, get error Type
3892  // 'RecordType(INTEGER EMPNO)' has no field 'EXPR$0' when
3893  // doing select * from unnest( select multiset[empno]
3894  // from sales.emps);
3895 
3896  fieldNameList.add(SqlUtil.deriveAliasFromOrdinal(j));
3897  }
3898 
3899  relBuilder.push(LogicalValues.createOneRow(cluster))
3900  .projectNamed(selectList, fieldNameList, true);
3901 
3902  joinList.set(i, relBuilder.build());
3903  }
3904  }
3905 
3906  RelNode ret = (RelNode) joinList.get(0);
3907  for (int i = 1; i < joinList.size(); i++) {
3908  RelNode relNode = (RelNode) joinList.get(i);
3909  ret = RelFactories.DEFAULT_JOIN_FACTORY.createJoin(ret,
3910  relNode,
3911  ImmutableList.of(),
3912  rexBuilder.makeLiteral(true),
3913  ImmutableSet.of(),
3914  JoinRelType.INNER,
3915  false);
3916  }
3917  return ret;
3918  }
3919 
3920  private void convertSelectList(
3921  Blackboard bb, SqlSelect select, List<SqlNode> orderList) {
3922  SqlNodeList selectList = select.getSelectList();
3923  selectList = validator.expandStar(selectList, select, false);
3924 
3925  replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
3926 
3927  List<String> fieldNames = new ArrayList<>();
3928  final List<RexNode> exprs = new ArrayList<>();
3929  final Collection<String> aliases = new TreeSet<>();
3930 
3931  // Project any system fields. (Must be done before regular select items,
3932  // because offsets may be affected.)
3933  final List<SqlMonotonicity> columnMonotonicityList = new ArrayList<>();
3934  extraSelectItems(bb, select, exprs, fieldNames, aliases, columnMonotonicityList);
3935 
3936  // Project select clause.
3937  int i = -1;
3938  for (SqlNode expr : selectList) {
3939  ++i;
3940  exprs.add(bb.convertExpression(expr));
3941  fieldNames.add(deriveAlias(expr, aliases, i));
3942  }
3943 
3944  // Project extra fields for sorting.
3945  for (SqlNode expr : orderList) {
3946  ++i;
3947  SqlNode expr2 = validator.expandOrderExpr(select, expr);
3948  exprs.add(bb.convertExpression(expr2));
3949  fieldNames.add(deriveAlias(expr, aliases, i));
3950  }
3951 
3952  fieldNames = SqlValidatorUtil.uniquify(
3953  fieldNames, catalogReader.nameMatcher().isCaseSensitive());
3954 
3955  relBuilder.push(bb.root).projectNamed(exprs, fieldNames, true);
3956  bb.setRoot(relBuilder.build(), false);
3957 
3958  assert bb.columnMonotonicities.isEmpty();
3959  bb.columnMonotonicities.addAll(columnMonotonicityList);
3960  for (SqlNode selectItem : selectList) {
3961  bb.columnMonotonicities.add(selectItem.getMonotonicity(bb.scope));
3962  }
3963  }
3964 
3978  protected void extraSelectItems(Blackboard bb,
3979  SqlSelect select,
3980  List<RexNode> exprList,
3981  List<String> nameList,
3982  Collection<String> aliasList,
3983  List<SqlMonotonicity> columnMonotonicityList) {}
3984 
3985  private String deriveAlias(
3986  final SqlNode node, Collection<String> aliases, final int ordinal) {
3987  String alias = validator.deriveAlias(node, ordinal);
3988  if ((alias == null) || aliases.contains(alias)) {
3989  String aliasBase = (alias == null) ? "EXPR$" : alias;
3990  for (int j = 0;; j++) {
3991  alias = aliasBase + j;
3992  if (!aliases.contains(alias)) {
3993  break;
3994  }
3995  }
3996  }
3997  aliases.add(alias);
3998  return alias;
3999  }
4000 
4004  public RelRoot convertWith(SqlWith with, boolean top) {
4005  return convertQuery(with.body, false, top);
4006  }
4007 
4011  public RelNode convertValues(SqlCall values, RelDataType targetRowType) {
4012  final SqlValidatorScope scope = validator.getOverScope(values);
4013  assert scope != null;
4014  final Blackboard bb = createBlackboard(scope, null, false);
4015  convertValuesImpl(bb, values, targetRowType);
4016  return bb.root;
4017  }
4018 
4027  private void convertValuesImpl(
4028  Blackboard bb, SqlCall values, RelDataType targetRowType) {
4029  // Attempt direct conversion to LogicalValues; if that fails, deal with
4030  // fancy stuff like sub-queries below.
4031  RelNode valuesRel =
4032  convertRowValues(bb, values, values.getOperandList(), true, targetRowType);
4033  if (valuesRel != null) {
4034  bb.setRoot(valuesRel, true);
4035  return;
4036  }
4037 
4038  final List<RelNode> unionRels = new ArrayList<>();
4039  for (SqlNode rowConstructor1 : values.getOperandList()) {
4040  SqlCall rowConstructor = (SqlCall) rowConstructor1;
4041  Blackboard tmpBb = createBlackboard(bb.scope, null, false);
4042  replaceSubQueries(tmpBb, rowConstructor, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
4043  final List<Pair<RexNode, String>> exps = new ArrayList<>();
4044  for (Ord<SqlNode> operand : Ord.zip(rowConstructor.getOperandList())) {
4045  exps.add(Pair.of(tmpBb.convertExpression(operand.e),
4046  validator.deriveAlias(operand.e, operand.i)));
4047  }
4048  RelNode in =
4049  (null == tmpBb.root) ? LogicalValues.createOneRow(cluster) : tmpBb.root;
4050  unionRels.add(
4051  relBuilder.push(in).project(Pair.left(exps), Pair.right(exps)).build());
4052  }
4053 
4054  if (unionRels.size() == 0) {
4055  throw new AssertionError("empty values clause");
4056  } else if (unionRels.size() == 1) {
4057  bb.setRoot(unionRels.get(0), true);
4058  } else {
4059  bb.setRoot(LogicalUnion.create(unionRels, true), true);
4060  }
4061  }
4062 
4063  // ~ Inner Classes ----------------------------------------------------------
4064 
4068  protected class Blackboard
4069  implements SqlRexContext, SqlVisitor<RexNode>, InitializerContext {
4073  public final SqlValidatorScope scope;
4074  private final Map<String, RexNode> nameToNodeMap;
4075  public RelNode root;
4076  private List<RelNode> inputs;
4077  private final Map<CorrelationId, RexFieldAccess> mapCorrelateToRex = new HashMap<>();
4078 
4079  private boolean isPatternVarRef = false;
4080 
4081  final List<RelNode> cursors = new ArrayList<>();
4082 
4087  private final List<SubQuery> subQueryList = new ArrayList<>();
4088 
4092  AggConverter agg;
4093 
4098  SqlWindow window;
4099 
4105  private final Map<RelNode, Map<Integer, Integer>> mapRootRelToFieldProjection =
4106  new HashMap<>();
4107 
4108  private final List<SqlMonotonicity> columnMonotonicities = new ArrayList<>();
4109 
4110  private final List<RelDataTypeField> systemFieldList = new ArrayList<>();
4111  final boolean top;
4112 
4113  private final InitializerExpressionFactory initializerExpressionFactory =
4114  new NullInitializerExpressionFactory();
4115 
4127  protected Blackboard(
4128  SqlValidatorScope scope, Map<String, RexNode> nameToNodeMap, boolean top) {
4129  this.scope = scope;
4130  this.nameToNodeMap = nameToNodeMap;
4131  this.top = top;
4132  }
4133 
4134  public SqlNode getTopNode() {
4135  try {
4136  if (null == scope) {
4137  return null;
4138  }
4139  return scope.getNode();
4140  } catch (Exception e) {
4141  return null;
4142  }
4143  }
4144 
4145  public void setPatternVarRef(boolean isVarRef) {
4146  this.isPatternVarRef = isVarRef;
4147  }
4148 
4149  public RexNode register(RelNode rel, JoinRelType joinType) {
4150  return register(rel, joinType, null);
4151  }
4152 
4162  public RexNode register(RelNode rel, JoinRelType joinType, List<RexNode> leftKeys) {
4163  assert joinType != null;
4164  if (root == null) {
4165  assert leftKeys == null;
4166  setRoot(rel, false);
4167  return rexBuilder.makeRangeReference(root.getRowType(), 0, false);
4168  }
4169 
4170  final RexNode joinCond;
4171  final int origLeftInputCount = root.getRowType().getFieldCount();
4172  if (leftKeys != null) {
4173  List<RexNode> newLeftInputExprs = new ArrayList<>();
4174  for (int i = 0; i < origLeftInputCount; i++) {
4175  newLeftInputExprs.add(rexBuilder.makeInputRef(root, i));
4176  }
4177 
4178  final List<Integer> leftJoinKeys = new ArrayList<>();
4179  for (RexNode leftKey : leftKeys) {
4180  int index = newLeftInputExprs.indexOf(leftKey);
4181  if (index < 0 || joinType == JoinRelType.LEFT) {
4182  index = newLeftInputExprs.size();
4183  newLeftInputExprs.add(leftKey);
4184  }
4185  leftJoinKeys.add(index);
4186  }
4187 
4188  RelNode newLeftInput = relBuilder.push(root).project(newLeftInputExprs).build();
4189 
4190  // maintain the group by mapping in the new LogicalProject
4191  if (mapRootRelToFieldProjection.containsKey(root)) {
4192  mapRootRelToFieldProjection.put(
4193  newLeftInput, mapRootRelToFieldProjection.get(root));
4194  }
4195 
4196  setRoot(newLeftInput, false);
4197 
4198  // right fields appear after the LHS fields.
4199  final int rightOffset = root.getRowType().getFieldCount()
4200  - newLeftInput.getRowType().getFieldCount();
4201  final List<Integer> rightKeys =
4202  Util.range(rightOffset, rightOffset + leftKeys.size());
4203 
4204  joinCond = RelOptUtil.createEquiJoinCondition(
4205  newLeftInput, leftJoinKeys, rel, rightKeys, rexBuilder);
4206  } else {
4207  joinCond = rexBuilder.makeLiteral(true);
4208  }
4209 
4210  int leftFieldCount = root.getRowType().getFieldCount();
4211  final RelNode join = createJoin(this, root, rel, joinCond, joinType);
4212 
4213  setRoot(join, false);
4214 
4215  if (leftKeys != null && joinType == JoinRelType.LEFT) {
4216  final int leftKeyCount = leftKeys.size();
4217  int rightFieldLength = rel.getRowType().getFieldCount();
4218  assert leftKeyCount == rightFieldLength - 1;
4219 
4220  final int rexRangeRefLength = leftKeyCount + rightFieldLength;
4221  RelDataType returnType = typeFactory.createStructType(
4222  new AbstractList<Map.Entry<String, RelDataType>>() {
4223  public Map.Entry<String, RelDataType> get(int index) {
4224  return join.getRowType().getFieldList().get(
4225  origLeftInputCount + index);
4226  }
4227 
4228  public int size() {
4229  return rexRangeRefLength;
4230  }
4231  });
4232 
4233  return rexBuilder.makeRangeReference(returnType, origLeftInputCount, false);
4234  } else {
4235  return rexBuilder.makeRangeReference(
4236  rel.getRowType(), leftFieldCount, joinType.generatesNullsOnRight());
4237  }
4238  }
4239 
4251  public void setRoot(RelNode root, boolean leaf) {
4252  setRoot(Collections.singletonList(root), root, root instanceof LogicalJoin);
4253  if (leaf) {
4254  leaves.put(root, root.getRowType().getFieldCount());
4255  }
4256  this.columnMonotonicities.clear();
4257  }
4258 
4259  private void setRoot(List<RelNode> inputs, RelNode root, boolean hasSystemFields) {
4260  this.inputs = inputs;
4261  this.root = root;
4262  this.systemFieldList.clear();
4263  if (hasSystemFields) {
4264  this.systemFieldList.addAll(getSystemFields());
4265  }
4266  }
4267 
4278  public void setDataset(String datasetName) {}
4279 
4280  void setRoot(List<RelNode> inputs) {
4281  setRoot(inputs, null, false);
4282  }
4283 
4290  Pair<RexNode, Map<String, Integer>> lookupExp(SqlQualified qualified) {
4291  if (nameToNodeMap != null && qualified.prefixLength == 1) {
4292  RexNode node = nameToNodeMap.get(qualified.identifier.names.get(0));
4293  if (node == null) {
4294  throw new AssertionError("Unknown identifier '" + qualified.identifier
4295  + "' encountered while expanding expression");
4296  }
4297  return Pair.of(node, null);
4298  }
4299  final SqlNameMatcher nameMatcher =
4300  scope.getValidator().getCatalogReader().nameMatcher();
4301  final SqlValidatorScope.ResolvedImpl resolved =
4302  new SqlValidatorScope.ResolvedImpl();
4303  scope.resolve(qualified.prefix(), nameMatcher, false, resolved);
4304  if (!(resolved.count() == 1)) {
4305  return null;
4306  }
4307  final SqlValidatorScope.Resolve resolve = resolved.only();
4308  final RelDataType rowType = resolve.rowType();
4309 
4310  // Found in current query's from list. Find which from item.
4311  // We assume that the order of the from clause items has been
4312  // preserved.
4313  final SqlValidatorScope ancestorScope = resolve.scope;
4314  boolean isParent = ancestorScope != scope;
4315  if ((inputs != null) && !isParent) {
4316  final LookupContext rels =
4317  new LookupContext(this, inputs, systemFieldList.size());
4318  final RexNode node = lookup(resolve.path.steps().get(0).i, rels);
4319  if (node == null) {
4320  return null;
4321  } else {
4322  final Map<String, Integer> fieldOffsets = new HashMap<>();
4323  for (RelDataTypeField f : resolve.rowType().getFieldList()) {
4324  if (!fieldOffsets.containsKey(f.getName())) {
4325  fieldOffsets.put(f.getName(), f.getIndex());
4326  }
4327  }
4328  final Map<String, Integer> map = ImmutableMap.copyOf(fieldOffsets);
4329  return Pair.of(node, map);
4330  }
4331  } else {
4332  // We're referencing a relational expression which has not been
4333  // converted yet. This occurs when from items are correlated,
4334  // e.g. "select from emp as emp join emp.getDepts() as dept".
4335  // Create a temporary expression.
4336  DeferredLookup lookup =
4337  new DeferredLookup(this, qualified.identifier.names.get(0));
4338  final CorrelationId correlId = cluster.createCorrel();
4339  mapCorrelToDeferred.put(correlId, lookup);
4340  if (resolve.path.steps().get(0).i < 0) {
4341  return Pair.of(rexBuilder.makeCorrel(rowType, correlId), null);
4342  } else {
4343  final RelDataTypeFactory.Builder builder = typeFactory.builder();
4344  final ListScope ancestorScope1 = (ListScope) resolve.scope;
4345  final ImmutableMap.Builder<String, Integer> fields = ImmutableMap.builder();
4346  int i = 0;
4347  int offset = 0;
4348  for (SqlValidatorNamespace c : ancestorScope1.getChildren()) {
4349  builder.addAll(c.getRowType().getFieldList());
4350  if (i == resolve.path.steps().get(0).i) {
4351  for (RelDataTypeField field : c.getRowType().getFieldList()) {
4352  fields.put(field.getName(), field.getIndex() + offset);
4353  }
4354  }
4355  ++i;
4356  offset += c.getRowType().getFieldCount();
4357  }
4358  final RexNode c = rexBuilder.makeCorrel(builder.uniquify().build(), correlId);
4359  return Pair.of(c, fields.build());
4360  }
4361  }
4362  }
4363 
4368  RexNode lookup(int offset, LookupContext lookupContext) {
4369  Pair<RelNode, Integer> pair = lookupContext.findRel(offset);
4370  return rexBuilder.makeRangeReference(pair.left.getRowType(), pair.right, false);
4371  }
4372 
4373  RelDataTypeField getRootField(RexInputRef inputRef) {
4374  if (inputs == null) {
4375  return null;
4376  }
4377  int fieldOffset = inputRef.getIndex();
4378  for (RelNode input : inputs) {
4379  RelDataType rowType = input.getRowType();
4380  if (fieldOffset < rowType.getFieldCount()) {
4381  return rowType.getFieldList().get(fieldOffset);
4382  }
4383  fieldOffset -= rowType.getFieldCount();
4384  }
4385  return null;
4386  }
4387 
4388  public void flatten(List<RelNode> rels,
4389  int systemFieldCount,
4390  int[] start,
4391  List<Pair<RelNode, Integer>> relOffsetList) {
4392  for (RelNode rel : rels) {
4393  if (leaves.containsKey(rel)) {
4394  relOffsetList.add(Pair.of(rel, start[0]));
4395  start[0] += leaves.get(rel);
4396  } else if (rel instanceof LogicalMatch) {
4397  relOffsetList.add(Pair.of(rel, start[0]));
4398  start[0] += rel.getRowType().getFieldCount();
4399  } else {
4400  if (rel instanceof LogicalJoin || rel instanceof LogicalAggregate) {
4401  start[0] += systemFieldCount;
4402  }
4403  flatten(rel.getInputs(), systemFieldCount, start, relOffsetList);
4404  }
4405  }
4406  }
4407 
4408  void registerSubQuery(SqlNode node, RelOptUtil.Logic logic) {
4409  for (SubQuery subQuery : subQueryList) {
4410  // Compare the reference to make sure the matched node has
4411  // exact scope where it belongs.
4412  if (node == subQuery.node) {
4413  return;
4414  }
4415  }
4416  subQueryList.add(new SubQuery(node, logic));
4417  }
4418 
4419  SubQuery getSubQuery(SqlNode expr) {
4420  for (SubQuery subQuery : subQueryList) {
4421  // Compare the reference to make sure the matched node has
4422  // exact scope where it belongs.
4423  if (expr == subQuery.node) {
4424  return subQuery;
4425  }
4426  }
4427 
4428  return null;
4429  }
4430 
4431  ImmutableList<RelNode> retrieveCursors() {
4432  try {
4433  return ImmutableList.copyOf(cursors);
4434  } finally {
4435  cursors.clear();
4436  }
4437  }
4438 
4439  public RexNode convertExpression(SqlNode expr) {
4440  // If we're in aggregation mode and this is an expression in the
4441  // GROUP BY clause, return a reference to the field.
4442  if (agg != null) {
4443  final SqlNode expandedGroupExpr = validator.expand(expr, scope);
4444  final int ref = agg.lookupGroupExpr(expandedGroupExpr);
4445  if (ref >= 0) {
4446  return rexBuilder.makeInputRef(root, ref);
4447  }
4448  if (expr instanceof SqlCall) {
4449  final RexNode rex = agg.lookupAggregates((SqlCall) expr);
4450  if (rex != null) {
4451  return rex;
4452  }
4453  }
4454  }
4455 
4456  // Allow the derived class chance to override the standard
4457  // behavior for special kinds of expressions.
4458  RexNode rex = convertExtendedExpression(expr, this);
4459  if (rex != null) {
4460  return rex;
4461  }
4462 
4463  // Sub-queries and OVER expressions are not like ordinary
4464  // expressions.
4465  final SqlKind kind = expr.getKind();
4466  final SubQuery subQuery;
4467  boolean isExpand = config.getExpandPredicate().test(getTopNode(), expr);
4468  if (!isExpand) {
4469  final SqlCall call;
4470  final SqlNode query;
4471  final RelRoot root;
4472  switch (kind) {
4473  case IN:
4474  case NOT_IN:
4475  case SOME:
4476  case ALL:
4477  call = (SqlCall) expr;
4478  query = call.operand(1);
4479  if (!(query instanceof SqlNodeList)) {
4480  root = convertQueryRecursive(query, false, null);
4481  final SqlNode operand = call.operand(0);
4482  List<SqlNode> nodes;
4483  switch (operand.getKind()) {
4484  case ROW:
4485  nodes = ((SqlCall) operand).getOperandList();
4486  break;
4487  default:
4488  nodes = ImmutableList.of(operand);
4489  }
4490  final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
4491  for (SqlNode node : nodes) {
4492  builder.add(convertExpression(node));
4493  }
4494  final ImmutableList<RexNode> list = builder.build();
4495  switch (kind) {
4496  case IN:
4497  return RexSubQuery.in(root.rel, list);
4498  case NOT_IN:
4499  return rexBuilder.makeCall(
4500  SqlStdOperatorTable.NOT, RexSubQuery.in(root.rel, list));
4501  case SOME:
4502  return RexSubQuery.some(
4503  root.rel, list, (SqlQuantifyOperator) call.getOperator());
4504  case ALL:
4505  return rexBuilder.makeCall(SqlStdOperatorTable.NOT,
4506  RexSubQuery.some(root.rel,
4507  list,
4508  negate((SqlQuantifyOperator) call.getOperator())));
4509  default:
4510  throw new AssertionError(kind);
4511  }
4512  }
4513  break;
4514 
4515  case EXISTS:
4516  call = (SqlCall) expr;
4517  query = Iterables.getOnlyElement(call.getOperandList());
4518  root = convertQueryRecursive(query, false, null);
4519  RelNode rel = root.rel;
4520  while (rel instanceof Project
4521  || rel instanceof Sort && ((Sort) rel).fetch == null
4522  && ((Sort) rel).offset == null) {
4523  rel = ((SingleRel) rel).getInput();
4524  }
4525  return RexSubQuery.exists(rel);
4526 
4527  case SCALAR_QUERY:
4528  call = (SqlCall) expr;
4529  query = Iterables.getOnlyElement(call.getOperandList());
4530  root = convertQueryRecursive(query, false, null);
4531  return RexSubQuery.scalar(root.rel);
4532  }
4533  }
4534 
4535  switch (kind) {
4536  case SOME:
4537  case ALL:
4538  if (isExpand) {
4539  throw new RuntimeException(kind + " is only supported if expand = false");
4540  }
4541  // fall through
4542  case CURSOR:
4543  case IN:
4544  case NOT_IN:
4545  subQuery = Objects.requireNonNull(getSubQuery(expr));
4546  rex = Objects.requireNonNull(subQuery.expr);
4547  return StandardConvertletTable.castToValidatedType(
4548  expr, rex, validator, rexBuilder);
4549 
4550  case SELECT:
4551  case EXISTS:
4552  case SCALAR_QUERY:
4553  subQuery = getSubQuery(expr);
4554  assert subQuery != null;
4555  rex = subQuery.expr;
4556  assert rex != null : "rex != null";
4557 
4558  if (((kind == SqlKind.SCALAR_QUERY) || (kind == SqlKind.EXISTS))
4559  && isConvertedSubq(rex)) {
4560  // scalar sub-query or EXISTS has been converted to a
4561  // constant
4562  return rex;
4563  }
4564 
4565  // The indicator column is the last field of the sub-query.
4566  RexNode fieldAccess =
4567  rexBuilder.makeFieldAccess(rex, rex.getType().getFieldCount() - 1);
4568 
4569  // The indicator column will be nullable if it comes from
4570  // the null-generating side of the join. For EXISTS, add an
4571  // "IS TRUE" check so that the result is "BOOLEAN NOT NULL".
4572  if (fieldAccess.getType().isNullable() && kind == SqlKind.EXISTS) {
4573  fieldAccess =
4574  rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, fieldAccess);
4575  }
4576  return fieldAccess;
4577 
4578  case OVER:
4579  return convertOver(this, expr);
4580 
4581  default:
4582  // fall through
4583  }
4584 
4585  // Apply standard conversions.
4586  rex = expr.accept(this);
4587  return Objects.requireNonNull(rex);
4588  }
4589 
4594  public RexFieldCollation convertSortExpression(SqlNode expr,
4595  RelFieldCollation.Direction direction,
4596  RelFieldCollation.NullDirection nullDirection) {
4597  switch (expr.getKind()) {
4598  case DESCENDING:
4599  return convertSortExpression(((SqlCall) expr).operand(0),
4600  RelFieldCollation.Direction.DESCENDING,
4601  nullDirection);
4602  case NULLS_LAST:
4603  return convertSortExpression(((SqlCall) expr).operand(0),
4604  direction,
4605  RelFieldCollation.NullDirection.LAST);
4606  case NULLS_FIRST:
4607  return convertSortExpression(((SqlCall) expr).operand(0),
4608  direction,
4609  RelFieldCollation.NullDirection.FIRST);
4610  default:
4611  final Set<SqlKind> flags = EnumSet.noneOf(SqlKind.class);
4612  switch (direction) {
4613  case DESCENDING:
4614  flags.add(SqlKind.DESCENDING);
4615  }
4616  switch (nullDirection) {
4617  case UNSPECIFIED:
4618  final RelFieldCollation.NullDirection nullDefaultDirection =
4619  validator.getDefaultNullCollation().last(desc(direction))
4620  ? RelFieldCollation.NullDirection.LAST
4621  : RelFieldCollation.NullDirection.FIRST;
4622  if (nullDefaultDirection != direction.defaultNullDirection()) {
4623  SqlKind nullDirectionSqlKind =
4624  validator.getDefaultNullCollation().last(desc(direction))
4625  ? SqlKind.NULLS_LAST
4626  : SqlKind.NULLS_FIRST;
4627  flags.add(nullDirectionSqlKind);
4628  }
4629  break;
4630  case FIRST:
4631  flags.add(SqlKind.NULLS_FIRST);
4632  break;
4633  case LAST:
4634  flags.add(SqlKind.NULLS_LAST);
4635  break;
4636  }
4637  return new RexFieldCollation(convertExpression(expr), flags);
4638  }
4639  }
4640 
4649  private boolean isConvertedSubq(RexNode rex) {
4650  if ((rex instanceof RexLiteral) || (rex instanceof RexDynamicParam)) {
4651  return true;
4652  }
4653  if (rex instanceof RexCall) {
4654  RexCall call = (RexCall) rex;
4655  if (call.getOperator() == SqlStdOperatorTable.CAST) {
4656  RexNode operand = call.getOperands().get(0);
4657  if (operand instanceof RexLiteral) {
4658  return true;
4659  }
4660  }
4661  }
4662  return false;
4663  }
4664 
4665  public int getGroupCount() {
4666  if (agg != null) {
4667  return agg.groupExprs.size();
4668  }
4669  if (window != null) {
4670  return window.isAlwaysNonEmpty() ? 1 : 0;
4671  }
4672  return -1;
4673  }
4674 
4675  public RexBuilder getRexBuilder() {
4676  return rexBuilder;
4677  }
4678 
4679  public SqlNode validateExpression(RelDataType rowType, SqlNode expr) {
4680  return SqlValidatorUtil
4681  .validateExprWithRowType(catalogReader.nameMatcher().isCaseSensitive(),
4682  opTab,
4683  typeFactory,
4684  rowType,
4685  expr)
4686  .left;
4687  }
4688 
4689  public RexRangeRef getSubQueryExpr(SqlCall call) {
4690  final SubQuery subQuery = getSubQuery(call);
4691  assert subQuery != null;
4692  return (RexRangeRef) subQuery.expr;
4693  }
4694 
4695  public RelDataTypeFactory getTypeFactory() {
4696  return typeFactory;
4697  }
4698 
4699  public InitializerExpressionFactory getInitializerExpressionFactory() {
4700  return initializerExpressionFactory;
4701  }
4702 
4703  public SqlValidator getValidator() {
4704  return validator;
4705  }
4706 
4707  public RexNode convertLiteral(SqlLiteral literal) {
4708  return exprConverter.convertLiteral(this, literal);
4709  }
4710 
4711  public RexNode convertInterval(SqlIntervalQualifier intervalQualifier) {
4712  return exprConverter.convertInterval(this, intervalQualifier);
4713  }
4714 
4715  public RexNode visit(SqlLiteral literal) {
4716  return exprConverter.convertLiteral(this, literal);
4717  }
4718 
4719  public RexNode visit(SqlCall call) {
4720  if (agg != null) {
4721  final SqlOperator op = call.getOperator();
4722  if (window == null
4723  && (op.isAggregator() || op.getKind() == SqlKind.FILTER
4724  || op.getKind() == SqlKind.WITHIN_GROUP)) {
4725  return agg.lookupAggregates(call);
4726  }
4727  }
4728  return exprConverter.convertCall(
4729  this, new SqlCallBinding(validator, scope, call).permutedCall());
4730  }
4731 
4732  public RexNode visit(SqlNodeList nodeList) {
4733  throw new UnsupportedOperationException();
4734  }
4735 
4736  public RexNode visit(SqlIdentifier id) {
4737  return convertIdentifier(this, id);
4738  }
4739 
4740  public RexNode visit(SqlDataTypeSpec type) {
4741  throw new UnsupportedOperationException();
4742  }
4743 
4744  public RexNode visit(SqlDynamicParam param) {
4745  return convertDynamicParam(param);
4746  }
4747 
4748  public RexNode visit(SqlIntervalQualifier intervalQualifier) {
4749  return convertInterval(intervalQualifier);
4750  }
4751 
4752  public List<SqlMonotonicity> getColumnMonotonicities() {
4753  return columnMonotonicities;
4754  }
4755  }
4756 
4757  private SqlQuantifyOperator negate(SqlQuantifyOperator operator) {
4758  assert operator.kind == SqlKind.ALL;
4759  return SqlStdOperatorTable.some(operator.comparisonKind.negateNullSafe());
4760  }
4761 
4763  private static class DeferredLookup {
4766 
4767  DeferredLookup(Blackboard bb, String originalRelName) {
4768  this.bb = bb;
4769  this.originalRelName = originalRelName;
4770  }
4771 
4772  public RexFieldAccess getFieldAccess(CorrelationId name) {
4773  return (RexFieldAccess) bb.mapCorrelateToRex.get(name);
4774  }
4775 
4776  public String getOriginalRelName() {
4777  return originalRelName;
4778  }
4779  }
4780 
4784  private class NoOpSubQueryConverter implements SubQueryConverter {
4785  public boolean canConvertSubQuery() {
4786  return false;
4787  }
4788 
4789  public RexNode convertSubQuery(SqlCall subQuery,
4790  SqlToRelConverter parentConverter,
4791  boolean isExists,
4792  boolean isExplain) {
4793  throw new IllegalArgumentException();
4794  }
4795  }
4796 
4816  protected class AggConverter implements SqlVisitor<Void> {
4817  private final Blackboard bb;
4818  public final AggregatingSelectScope aggregatingSelectScope;
4819 
4820  private final Map<String, String> nameMap = new HashMap<>();
4821 
4825  private final SqlNodeList groupExprs = new SqlNodeList(SqlParserPos.ZERO);
4826 
4830  private final Map<SqlNode, Ord<AuxiliaryConverter>> auxiliaryGroupExprs =
4831  new HashMap<>();
4832 
4840  private final List<Pair<RexNode, String>> convertedInputExprs = new ArrayList<>();
4841 
4848  private final List<AggregateCall> aggCalls = new ArrayList<>();
4849  private final Map<SqlNode, RexNode> aggMapping = new HashMap<>();
4850  private final Map<AggregateCall, RexNode> aggCallMapping = new HashMap<>();
4851 
4853  private boolean inOver = false;
4854 
4865  public AggConverter(Blackboard bb, SqlSelect select) {
4866  this.bb = bb;
4867  this.aggregatingSelectScope =
4868  (AggregatingSelectScope) bb.getValidator().getSelectScope(select);
4869 
4870  // Collect all expressions used in the select list so that aggregate
4871  // calls can be named correctly.
4872  final SqlNodeList selectList = select.getSelectList();
4873  for (int i = 0; i < selectList.size(); i++) {
4874  SqlNode selectItem = selectList.get(i);
4875  String name = null;
4876  if (SqlUtil.isCallTo(selectItem, SqlStdOperatorTable.AS)) {
4877  final SqlCall call = (SqlCall) selectItem;
4878  selectItem = call.operand(0);
4879  name = call.operand(1).toString();
4880  }
4881  if (name == null) {
4882  name = validator.deriveAlias(selectItem, i);
4883  }
4884  nameMap.put(selectItem.toString(), name);
4885  }
4886  }
4887 
4888  public int addGroupExpr(SqlNode expr) {
4889  int ref = lookupGroupExpr(expr);
4890  if (ref >= 0) {
4891  return ref;
4892  }
4893  final int index = groupExprs.size();
4894  groupExprs.add(expr);
4895  String name = nameMap.get(expr.toString());
4896  RexNode convExpr = bb.convertExpression(expr);
4897  addExpr(convExpr, name);
4898 
4899  if (expr instanceof SqlCall) {
4900  SqlCall call = (SqlCall) expr;
4901  for (Pair<SqlNode, AuxiliaryConverter> p :
4902  SqlStdOperatorTable.convertGroupToAuxiliaryCalls(call)) {
4903  addAuxiliaryGroupExpr(p.left, index, p.right);
4904  }
4905  }
4906 
4907  return index;
4908  }
4909 
4910  void addAuxiliaryGroupExpr(SqlNode node, int index, AuxiliaryConverter converter) {
4911  for (SqlNode node2 : auxiliaryGroupExprs.keySet()) {
4912  if (node2.equalsDeep(node, Litmus.IGNORE)) {
4913  return;
4914  }
4915  }
4916  auxiliaryGroupExprs.put(node, Ord.of(index, converter));
4917  }
4918 
4925  private void addExpr(RexNode expr, String name) {
4926  if ((name == null) && (expr instanceof RexInputRef)) {
4927  final int i = ((RexInputRef) expr).getIndex();
4928  name = bb.root.getRowType().getFieldList().get(i).getName();
4929  }
4930  if (Pair.right(convertedInputExprs).contains(name)) {
4931  // In case like 'SELECT ... GROUP BY x, y, x', don't add
4932  // name 'x' twice.
4933  name = null;
4934  }
4935  convertedInputExprs.add(Pair.of(expr, name));
4936  }
4937 
4938  public Void visit(SqlIdentifier id) {
4939  return null;
4940  }
4941 
4942  public Void visit(SqlNodeList nodeList) {
4943  for (int i = 0; i < nodeList.size(); i++) {
4944  nodeList.get(i).accept(this);
4945  }
4946  return null;
4947  }
4948 
4949  public Void visit(SqlLiteral lit) {
4950  return null;
4951  }
4952 
4953  public Void visit(SqlDataTypeSpec type) {
4954  return null;
4955  }
4956 
4957  public Void visit(SqlDynamicParam param) {
4958  return null;
4959  }
4960 
4961  public Void visit(SqlIntervalQualifier intervalQualifier) {
4962  return null;
4963  }
4964 
4965  public Void visit(SqlCall call) {
4966  switch (call.getKind()) {
4967  case FILTER:
4968  case WITHIN_GROUP:
4969  translateAgg(call);
4970  return null;
4971  case SELECT:
4972  // rchen 2006-10-17:
4973  // for now do not detect aggregates in sub-queries.
4974  return null;
4975  }
4976  final boolean prevInOver = inOver;
4977  // Ignore window aggregates and ranking functions (associated with OVER
4978  // operator). However, do not ignore nested window aggregates.
4979  if (call.getOperator().getKind() == SqlKind.OVER) {
4980  // Track aggregate nesting levels only within an OVER operator.
4981  List<SqlNode> operandList = call.getOperandList();
4982  assert operandList.size() == 2;
4983 
4984  // Ignore the top level window aggregates and ranking functions
4985  // positioned as the first operand of a OVER operator
4986  inOver = true;
4987  operandList.get(0).accept(this);
4988 
4989  // Normal translation for the second operand of a OVER operator
4990  inOver = false;
4991  operandList.get(1).accept(this);
4992  return null;
4993  }
4994 
4995  // Do not translate the top level window aggregate. Only do so for
4996  // nested aggregates, if present
4997  if (call.getOperator().isAggregator()) {
4998  if (inOver) {
4999  // Add the parent aggregate level before visiting its children
5000  inOver = false;
5001  } else {
5002  // We're beyond the one ignored level
5003  translateAgg(call);
5004  return null;
5005  }
5006  }
5007  for (SqlNode operand : call.getOperandList()) {
5008  // Operands are occasionally null, e.g. switched CASE arg 0.
5009  if (operand != null) {
5010  operand.accept(this);
5011  }
5012  }
5013  // Remove the parent aggregate level after visiting its children
5014  inOver = prevInOver;
5015  return null;
5016  }
5017 
5018  private void translateAgg(SqlCall call) {
5019  translateAgg(call, null, null, false, call);
5020  }
5021 
5022  private void translateAgg(SqlCall call,
5023  SqlNode filter,
5024  SqlNodeList orderList,
5025  boolean ignoreNulls,
5026  SqlCall outerCall) {
5027  assert bb.agg == this;
5028  assert outerCall != null;
5029  switch (call.getKind()) {
5030  case FILTER:
5031  assert filter == null;
5032  translateAgg(
5033  call.operand(0), call.operand(1), orderList, ignoreNulls, outerCall);
5034  return;
5035  case WITHIN_GROUP:
5036  assert orderList == null;
5037  translateAgg(call.operand(0), filter, call.operand(1), ignoreNulls, outerCall);
5038  return;
5039  case IGNORE_NULLS:
5040  ignoreNulls = true;
5041  // fall through
5042  case RESPECT_NULLS:
5043  translateAgg(call.operand(0), filter, orderList, ignoreNulls, outerCall);
5044  return;
5045  }
5046  final List<Integer> args = new ArrayList<>();
5047  int filterArg = -1;
5048  final List<RelDataType> argTypes = call.getOperator() instanceof SqlCountAggFunction
5049  ? new ArrayList<>(call.getOperandList().size())
5050  : null;
5051  try {
5052  // switch out of agg mode
5053  bb.agg = null;
5054  for (SqlNode operand : call.getOperandList()) {
5055  // special case for COUNT(*): delete the *
5056  if (operand instanceof SqlIdentifier) {
5057  SqlIdentifier id = (SqlIdentifier) operand;
5058  if (id.isStar()) {
5059  assert call.operandCount() == 1;
5060  assert args.isEmpty();
5061  break;
5062  }
5063  }
5064  RexNode convertedExpr = bb.convertExpression(operand);
5065  assert convertedExpr != null;
5066  if (argTypes != null) {
5067  argTypes.add(convertedExpr.getType());
5068  }
5069  args.add(lookupOrCreateGroupExpr(convertedExpr));
5070  }
5071 
5072  if (filter != null) {
5073  RexNode convertedExpr = bb.convertExpression(filter);
5074  assert convertedExpr != null;
5075  if (convertedExpr.getType().isNullable()) {
5076  convertedExpr =
5077  rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, convertedExpr);
5078  }
5079  filterArg = lookupOrCreateGroupExpr(convertedExpr);
5080  }
5081  } finally {
5082  // switch back into agg mode
5083  bb.agg = this;
5084  }
5085 
5086  SqlAggFunction aggFunction = (SqlAggFunction) call.getOperator();
5087  final RelDataType type = validator.deriveType(bb.scope, call);
5088  boolean distinct = false;
5089  SqlLiteral quantifier = call.getFunctionQuantifier();
5090  if ((null != quantifier) && (quantifier.getValue() == SqlSelectKeyword.DISTINCT)) {
5091  distinct = true;
5092  }
5093  boolean approximate = false;
5094  if (aggFunction == SqlStdOperatorTable.APPROX_COUNT_DISTINCT) {
5095  aggFunction = SqlStdOperatorTable.COUNT;
5096  distinct = true;
5097  approximate = true;
5098  }
5099  final RelCollation collation;
5100  if (orderList == null || orderList.size() == 0) {
5101  collation = RelCollations.EMPTY;
5102  } else {
5103  collation = RelCollations.of(
5104  orderList.getList()
5105  .stream()
5106  .map(order
5107  -> bb.convertSortExpression(order,
5108  RelFieldCollation.Direction.ASCENDING,
5109  RelFieldCollation.NullDirection.UNSPECIFIED))
5110  .map(fieldCollation
5111  -> new RelFieldCollation(
5112  lookupOrCreateGroupExpr(fieldCollation.left),
5113  fieldCollation.getDirection(),
5114  fieldCollation.getNullDirection()))
5115  .collect(Collectors.toList()));
5116  }
5117  final AggregateCall aggCall = AggregateCall.create(aggFunction,
5118  distinct,
5119  approximate,
5120  ignoreNulls,
5121  args,
5122  filterArg,
5123  collation,
5124  type,
5125  nameMap.get(outerCall.toString()));
5126  final AggregatingSelectScope.Resolved r = aggregatingSelectScope.resolved.get();
5127  RexNode rex = rexBuilder.addAggCall(
5128  aggCall, groupExprs.size(), aggCalls, aggCallMapping, argTypes);
5129  aggMapping.put(outerCall, rex);
5130  }
5131 
5132  private int lookupOrCreateGroupExpr(RexNode expr) {
5133  int index = 0;
5134  for (RexNode convertedInputExpr : Pair.left(convertedInputExprs)) {
5135  if (expr.equals(convertedInputExpr)) {
5136  return index;
5137  }
5138  ++index;
5139  }
5140 
5141  // not found -- add it
5142  addExpr(expr, null);
5143  return index;
5144  }
5145 
5150  public int lookupGroupExpr(SqlNode expr) {
5151  for (int i = 0; i < groupExprs.size(); i++) {
5152  SqlNode groupExpr = groupExprs.get(i);
5153  if (expr.equalsDeep(groupExpr, Litmus.IGNORE)) {
5154  return i;
5155  }
5156  }
5157  return -1;
5158  }
5159 
5160  public RexNode lookupAggregates(SqlCall call) {
5161  // assert call.getOperator().isAggregator();
5162  assert bb.agg == this;
5163 
5164  for (Map.Entry<SqlNode, Ord<AuxiliaryConverter>> e :
5165  auxiliaryGroupExprs.entrySet()) {
5166  if (call.equalsDeep(e.getKey(), Litmus.IGNORE)) {
5167  AuxiliaryConverter converter = e.getValue().e;
5168  final int groupOrdinal = e.getValue().i;
5169  return converter.convert(rexBuilder,
5170  convertedInputExprs.get(groupOrdinal).left,
5171  rexBuilder.makeInputRef(bb.root, groupOrdinal));
5172  }
5173  }
5174 
5175  return aggMapping.get(call);
5176  }
5177 
5178  public List<Pair<RexNode, String>> getPreExprs() {
5179  return convertedInputExprs;
5180  }
5181 
5182  public List<AggregateCall> getAggCalls() {
5183  return aggCalls;
5184  }
5185 
5186  private boolean containsGroupId() {
5187  return aggCalls.stream().anyMatch(
5188  agg -> agg.getAggregation().kind == SqlKind.GROUP_ID);
5189  }
5190 
5191  public RelDataTypeFactory getTypeFactory() {
5192  return typeFactory;
5193  }
5194  }
5195 
5199  private static class LookupContext {
5200  private final List<Pair<RelNode, Integer>> relOffsetList = new ArrayList<>();
5201 
5209  LookupContext(Blackboard bb, List<RelNode> rels, int systemFieldCount) {
5210  bb.flatten(rels, systemFieldCount, new int[] {0}, relOffsetList);
5211  }
5212 
5225  Pair<RelNode, Integer> findRel(int offset) {
5226  return relOffsetList.get(offset);
5227  }
5228  }
5229 
5262  private class HistogramShuttle extends RexShuttle {
5267  static final boolean ENABLE_HISTOGRAM_AGG = false;
5268 
5269  private final List<RexNode> partitionKeys;
5270  private final ImmutableList<RexFieldCollation> orderKeys;
5271  private final RexWindowBound lowerBound;
5272  private final RexWindowBound upperBound;
5273  private final SqlWindow window;
5274  private final boolean distinct;
5275  private final boolean ignoreNulls;
5276 
5277  HistogramShuttle(List<RexNode> partitionKeys,
5278  ImmutableList<RexFieldCollation> orderKeys,
5279  RexWindowBound lowerBound,
5280  RexWindowBound upperBound,
5281  SqlWindow window,
5282  boolean distinct,
5283  boolean ignoreNulls) {
5284  this.partitionKeys = partitionKeys;
5285  this.orderKeys = orderKeys;
5286  this.lowerBound = lowerBound;
5287  this.upperBound = upperBound;
5288  this.window = window;
5289  this.distinct = distinct;
5290  this.ignoreNulls = ignoreNulls;
5291  }
5292 
5293  public RexNode visitCall(RexCall call) {
5294  final SqlOperator op = call.getOperator();
5295  if (!(op instanceof SqlAggFunction)) {
5296  return super.visitCall(call);
5297  }
5298  final SqlAggFunction aggOp = (SqlAggFunction) op;
5299  final RelDataType type = call.getType();
5300  List<RexNode> exprs = call.getOperands();
5301 
5302  SqlFunction histogramOp = !ENABLE_HISTOGRAM_AGG ? null : getHistogramOp(aggOp);
5303 
5304  if (histogramOp != null) {
5305  final RelDataType histogramType = computeHistogramType(type);
5306 
5307  // For DECIMAL, since it's already represented as a bigint we
5308  // want to do a reinterpretCast instead of a cast to avoid
5309  // losing any precision.
5310  boolean reinterpretCast = type.getSqlTypeName() == SqlTypeName.DECIMAL;
5311 
5312  // Replace original expression with CAST of not one
5313  // of the supported types
5314  if (histogramType != type) {
5315  exprs = new ArrayList<>(exprs);
5316  exprs.set(0,
5317  reinterpretCast ? rexBuilder.makeReinterpretCast(
5318  histogramType, exprs.get(0), rexBuilder.makeLiteral(false))
5319  : rexBuilder.makeCast(histogramType, exprs.get(0)));
5320  }
5321 
5322  RexCallBinding bind = new RexCallBinding(rexBuilder.getTypeFactory(),
5323  SqlStdOperatorTable.HISTOGRAM_AGG,
5324  exprs,
5325  ImmutableList.of());
5326 
5327  RexNode over = rexBuilder.makeOver(
5328  SqlStdOperatorTable.HISTOGRAM_AGG.inferReturnType(bind),
5329  SqlStdOperatorTable.HISTOGRAM_AGG,
5330  exprs,
5331  partitionKeys,
5332  orderKeys,
5333  lowerBound,
5334  upperBound,
5335  window.isRows(),
5336  window.isAllowPartial(),
5337  false,
5338  distinct,
5339  ignoreNulls);
5340 
5341  RexNode histogramCall =
5342  rexBuilder.makeCall(histogramType, histogramOp, ImmutableList.of(over));
5343 
5344  // If needed, post Cast result back to original
5345  // type.
5346  if (histogramType != type) {
5347  if (reinterpretCast) {
5348  histogramCall = rexBuilder.makeReinterpretCast(
5349  type, histogramCall, rexBuilder.makeLiteral(false));
5350  } else {
5351  histogramCall = rexBuilder.makeCast(type, histogramCall);
5352  }
5353  }
5354 
5355  return histogramCall;
5356  } else {
5357  boolean needSum0 = aggOp == SqlStdOperatorTable.SUM && type.isNullable();
5358  SqlAggFunction aggOpToUse = needSum0 ? SqlStdOperatorTable.SUM0 : aggOp;
5359  return rexBuilder.makeOver(type,
5360  aggOpToUse,
5361  exprs,
5362  partitionKeys,
5363  orderKeys,
5364  lowerBound,
5365  upperBound,
5366  window.isRows(),
5367  window.isAllowPartial(),
5368  needSum0,
5369  distinct,
5370  ignoreNulls);
5371  }
5372  }
5373 
5385  SqlFunction getHistogramOp(SqlAggFunction aggFunction) {
5386  if (aggFunction == SqlStdOperatorTable.MIN) {
5387  return SqlStdOperatorTable.HISTOGRAM_MIN;
5388  } else if (aggFunction == SqlStdOperatorTable.MAX) {
5389  return SqlStdOperatorTable.HISTOGRAM_MAX;
5390  } else if (aggFunction == SqlStdOperatorTable.FIRST_VALUE) {
5391  return SqlStdOperatorTable.HISTOGRAM_FIRST_VALUE;
5392  } else if (aggFunction == SqlStdOperatorTable.LAST_VALUE) {
5393  return SqlStdOperatorTable.HISTOGRAM_LAST_VALUE;
5394  } else {
5395  return null;
5396  }
5397  }
5398 
5403  private RelDataType computeHistogramType(RelDataType type) {
5404  if (SqlTypeUtil.isExactNumeric(type)
5405  && type.getSqlTypeName() != SqlTypeName.BIGINT) {
5406  return typeFactory.createSqlType(SqlTypeName.BIGINT);
5407  } else if (SqlTypeUtil.isApproximateNumeric(type)
5408  && type.getSqlTypeName() != SqlTypeName.DOUBLE) {
5409  return typeFactory.createSqlType(SqlTypeName.DOUBLE);
5410  } else {
5411  return type;
5412  }
5413  }
5414  }
5415 
5419  private static class SubQuery {
5420  final SqlNode node;
5421  final RelOptUtil.Logic logic;
5422  RexNode expr;
5423 
5424  private SubQuery(SqlNode node, RelOptUtil.Logic logic) {
5425  this.node = node;
5426  this.logic = logic;
5427  }
5428  }
5429 
5433  private static class AggregateFinder extends SqlBasicVisitor<Void> {
5434  final SqlNodeList list = new SqlNodeList(SqlParserPos.ZERO);
5435  final SqlNodeList filterList = new SqlNodeList(SqlParserPos.ZERO);
5436  final SqlNodeList orderList = new SqlNodeList(SqlParserPos.ZERO);
5437 
5438  @Override
5439  public Void visit(SqlCall call) {
5440  // ignore window aggregates and ranking functions (associated with OVER
5441  // operator)
5442  if (call.getOperator().getKind() == SqlKind.OVER) {
5443  return null;
5444  }
5445 
5446  if (call.getOperator().getKind() == SqlKind.FILTER) {
5447  // the WHERE in a FILTER must be tracked too so we can call replaceSubQueries on
5448  // it. see https://issues.apache.org/jira/browse/CALCITE-1910
5449  final SqlNode aggCall = call.getOperandList().get(0);
5450  final SqlNode whereCall = call.getOperandList().get(1);
5451  list.add(aggCall);
5452  filterList.add(whereCall);
5453  return null;
5454  }
5455 
5456  if (call.getOperator().getKind() == SqlKind.WITHIN_GROUP) {
5457  // the WHERE in a WITHIN_GROUP must be tracked too so we can call
5458  // replaceSubQueries on it. see
5459  // https://issues.apache.org/jira/browse/CALCITE-1910
5460  final SqlNode aggCall = call.getOperandList().get(0);
5461  final SqlNodeList orderList = (SqlNodeList) call.getOperandList().get(1);
5462  list.add(aggCall);
5463  orderList.getList().forEach(this.orderList::add);
5464  return null;
5465  }
5466 
5467  if (call.getOperator().isAggregator()) {
5468  list.add(call);
5469  return null;
5470  }
5471 
5472  // Don't traverse into sub-queries, even if they contain aggregate
5473  // functions.
5474  if (call instanceof SqlSelect) {
5475  return null;
5476  }
5477 
5478  return call.getOperator().acceptCall(this, call);
5479  }
5480  }
5481 
5485  private static class CorrelationUse {
5486  private final CorrelationId id;
5487  private final ImmutableBitSet requiredColumns;
5489  private final RelNode r;
5490 
5491  CorrelationUse(CorrelationId id, ImmutableBitSet requiredColumns, RelNode r) {
5492  this.id = id;
5493  this.requiredColumns = requiredColumns;
5494  this.r = r;
5495  }
5496  }
5497 
5499  public static ConfigBuilder configBuilder() {
5500  return new ConfigBuilder();
5501  }
5502 
5510  public interface Config {
5512  Config DEFAULT = configBuilder().build();
5513 
5524  @Deprecated // to be removed before 1.23
5525  boolean isConvertTableAccess();
5526 
5531  boolean isDecorrelationEnabled();
5532 
5537  boolean isTrimUnusedFields();
5538 
5544  boolean isCreateValuesRel();
5545 
5550  boolean isExplain();
5551 
5556  boolean isExpand();
5557 
5567  int getInSubQueryThreshold();
5568 
5573  RelBuilderFactory getRelBuilderFactory();
5574 
5579  HintStrategyTable getHintStrategyTable();
5580 
5587  BiPredicate<SqlNode, SqlNode> getExpandPredicate();
5588 
5593  BiPredicate<SqlNode, Join> getPushdownJoinCondition();
5594  }
5595 
5597  public static class ConfigBuilder {
5598  private boolean decorrelationEnabled = true;
5599  private boolean trimUnusedFields = false;
5600  private boolean createValuesRel = true;
5601  private boolean explain;
5602  private boolean expand = true;
5603  private int inSubQueryThreshold = DEFAULT_IN_SUB_QUERY_THRESHOLD;
5604  private RelBuilderFactory relBuilderFactory = RelFactories.LOGICAL_BUILDER;
5605  private HintStrategyTable hintStrategyTable = HintStrategyTable.EMPTY;
5606  private BiPredicate<SqlNode, Join> pushdownJoinCondition;
5607  private BiPredicate<SqlNode, SqlNode> expandPredicate;
5608 
5609  private ConfigBuilder() {}
5610 
5612  public ConfigBuilder withConfig(Config config) {
5613  this.decorrelationEnabled = config.isDecorrelationEnabled();
5614  this.trimUnusedFields = config.isTrimUnusedFields();
5615  this.createValuesRel = config.isCreateValuesRel();
5616  this.explain = config.isExplain();
5617  this.expand = config.isExpand();
5618  this.inSubQueryThreshold = config.getInSubQueryThreshold();
5619  this.relBuilderFactory = config.getRelBuilderFactory();
5620  this.hintStrategyTable = config.getHintStrategyTable();
5621 
5622  if (!(config.getExpandPredicate() instanceof ConfigImpl.DefaultExpandPredicate)) {
5623  this.expandPredicate = config.getExpandPredicate();
5624  }
5625  this.pushdownJoinCondition = config.getPushdownJoinCondition();
5626  return this;
5627  }
5628 
5629  @Deprecated // to be removed before 1.23
5630  public ConfigBuilder withConvertTableAccess(boolean convertTableAccess) {
5631  return this;
5632  }
5633 
5634  public ConfigBuilder withDecorrelationEnabled(boolean enabled) {
5635  this.decorrelationEnabled = enabled;
5636  return this;
5637  }
5638 
5639  public ConfigBuilder withTrimUnusedFields(boolean trimUnusedFields) {
5640  this.trimUnusedFields = trimUnusedFields;
5641  return this;
5642  }
5643 
5644  public ConfigBuilder withCreateValuesRel(boolean createValuesRel) {
5645  this.createValuesRel = createValuesRel;
5646  return this;
5647  }
5648 
5649  public ConfigBuilder withExplain(boolean explain) {
5650  this.explain = explain;
5651  return this;
5652  }
5653 
5654  public ConfigBuilder withExpand(boolean expand) {
5655  this.expand = expand;
5656  return this;
5657  }
5658 
5659  public ConfigBuilder withPushdownJoinCondition(BiPredicate<SqlNode, Join> pushdown) {
5660  this.pushdownJoinCondition = pushdown;
5661  return this;
5662  }
5663 
5664  public ConfigBuilder withExpandPredicate(BiPredicate<SqlNode, SqlNode> predicate) {
5665  this.expandPredicate = predicate;
5666  return this;
5667  }
5668 
5669  @Deprecated // to be removed before 2.0
5670  public ConfigBuilder withInSubqueryThreshold(int inSubQueryThreshold) {
5671  return withInSubQueryThreshold(inSubQueryThreshold);
5672  }
5673 
5674  public ConfigBuilder withInSubQueryThreshold(int inSubQueryThreshold) {
5675  this.inSubQueryThreshold = inSubQueryThreshold;
5676  return this;
5677  }
5678 
5679  public ConfigBuilder withRelBuilderFactory(RelBuilderFactory relBuilderFactory) {
5680  this.relBuilderFactory = relBuilderFactory;
5681  return this;
5682  }
5683 
5684  public ConfigBuilder withHintStrategyTable(HintStrategyTable hintStrategyTable) {
5685  this.hintStrategyTable = hintStrategyTable;
5686  return this;
5687  }
5688 
5690  public Config build() {
5691  return new ConfigImpl(decorrelationEnabled,
5692  trimUnusedFields,
5693  createValuesRel,
5694  explain,
5695  expand,
5696  pushdownJoinCondition,
5697  expandPredicate,
5698  inSubQueryThreshold,
5699  relBuilderFactory,
5700  hintStrategyTable);
5701  }
5702  }
5703 
5708  private static class ConfigImpl implements Config {
5709  private final boolean decorrelationEnabled;
5710  private final boolean trimUnusedFields;
5711  private final boolean createValuesRel;
5712  private final boolean explain;
5713  private final boolean expand;
5714  private final int inSubQueryThreshold;
5715  private final RelBuilderFactory relBuilderFactory;
5716  private final HintStrategyTable hintStrategyTable;
5717  private final BiPredicate<SqlNode, SqlNode> expandPredicate;
5718 
5719  private class DefaultExpandPredicate implements BiPredicate<SqlNode, SqlNode> {
5720  @Override
5721  public boolean test(SqlNode t, SqlNode u) {
5722  return expand;
5723  }
5724  }
5725 
5726  private BiPredicate<SqlNode, Join> pushdownJoinCondition =
5727  new BiPredicate<SqlNode, Join>() {
5728  public boolean test(SqlNode t, Join u) {
5729  return true;
5730  };
5731  };
5732 
5733  private ConfigImpl(boolean decorrelationEnabled,
5734  boolean trimUnusedFields,
5735  boolean createValuesRel,
5736  boolean explain,
5737  boolean expand,
5738  BiPredicate<SqlNode, Join> pushdownJoinCondition,
5739  BiPredicate<SqlNode, SqlNode> expandPredicate,
5740  int inSubQueryThreshold,
5741  RelBuilderFactory relBuilderFactory,
5742  HintStrategyTable hintStrategyTable) {
5743  this.decorrelationEnabled = decorrelationEnabled;
5744  this.trimUnusedFields = trimUnusedFields;
5745  this.createValuesRel = createValuesRel;
5746  this.explain = explain;
5747  this.expand = expand;
5748  this.inSubQueryThreshold = inSubQueryThreshold;
5749  this.relBuilderFactory = relBuilderFactory;
5750  this.hintStrategyTable = hintStrategyTable;
5751 
5752  if (null == expandPredicate) {
5753  expandPredicate = new DefaultExpandPredicate();
5754  }
5755  this.expandPredicate = expandPredicate;
5756 
5757  if (null != pushdownJoinCondition) {
5758  this.pushdownJoinCondition = pushdownJoinCondition;
5759  }
5760  }
5761 
5762  public boolean isConvertTableAccess() {
5763  return true;
5764  }
5765 
5766  public boolean isDecorrelationEnabled() {
5767  return decorrelationEnabled;
5768  }
5769 
5770  public boolean isTrimUnusedFields() {
5771  return trimUnusedFields;
5772  }
5773 
5774  public boolean isCreateValuesRel() {
5775  return createValuesRel;
5776  }
5777 
5778  public boolean isExplain() {
5779  return explain;
5780  }
5781 
5782  public boolean isExpand() {
5783  return expand;
5784  }
5785 
5786  public int getInSubQueryThreshold() {
5787  return inSubQueryThreshold;
5788  }
5789 
5790  public RelBuilderFactory getRelBuilderFactory() {
5791  return relBuilderFactory;
5792  }
5793 
5794  public HintStrategyTable getHintStrategyTable() {
5795  return hintStrategyTable;
5796  }
5797 
5798  public BiPredicate<SqlNode, Join> getPushdownJoinCondition() {
5799  return pushdownJoinCondition;
5800  }
5801 
5802  public BiPredicate<SqlNode, SqlNode> getExpandPredicate() {
5803  return expandPredicate;
5804  }
5805  }
5806 }
RelRoot convertWith(SqlWith with, boolean top)
RelOptTable.ToRelContext createToRelContext(List< RelHint > hints)
SqlQuantifyOperator negate(SqlQuantifyOperator operator)
JoinType
Definition: sqldefs.h:107
void setDynamicParamCountInExplain(int explainParamCount)
static SqlNode pushDownNotForIn(SqlValidatorScope scope, SqlNode sqlNode)
void extraSelectItems(Blackboard bb, SqlSelect select, List< RexNode > exprList, List< String > nameList, Collection< String > aliasList, List< SqlMonotonicity > columnMonotonicityList)
final Map< CorrelationId, RexFieldAccess > mapCorrelateToRex
void substituteSubQuery(Blackboard bb, SubQuery subQuery)
void convertCollectionTable(Blackboard bb, SqlCall call)
RexNode convertSubQuery(SqlCall subQuery, SqlToRelConverter parentConverter, boolean isExists, boolean isExplain)
void checkConvertedType(SqlNode query, RelNode result)
RexNode translateIn(RelOptUtil.Logic logic, RelNode root, final RexNode rex)
RelNode convertCursor(Blackboard bb, SubQuery subQuery)
RelNode convertQueryOrInList(Blackboard bb, SqlNode seek, RelDataType targetRowType)
std::string join(T const &container, std::string const &delim)
RexNode castNullLiteralIfNeeded(RexNode node, RelDataType type)
RexNode ensureSqlType(RelDataType type, RexNode node)
void afterTableFunction(SqlToRelConverter.Blackboard bb, SqlCall call, LogicalTableFunctionScan callRel)
RelNode toRel(final RelOptTable table, final List< RelHint > hints)
SqlToRelConverter(RelOptTable.ViewExpander viewExpander, SqlValidator validator, Prepare.CatalogReader catalogReader, RelOptCluster cluster, SqlRexConvertletTable convertletTable)
void convertValuesImpl(Blackboard bb, SqlCall values, RelDataType targetRowType)
void convertFrom(Blackboard bb, SqlNode from)
InitializerExpressionFactory getInitializerFactory(SqlValidatorTable validatorTable)
String deriveAlias(final SqlNode node, Collection< String > aliases, final int ordinal)
RelNode decorrelate(SqlNode query, RelNode rootRel)
void setRoot(List< RelNode > inputs, RelNode root, boolean hasSystemFields)
RexDynamicParam convertDynamicParam(final SqlDynamicParam dynamicParam)
RelNode convertRowValues(Blackboard bb, SqlNode rowList, Collection< SqlNode > rows, boolean allowLiteralsOnly, RelDataType targetRowType)
RexNode convertInToOr(final Blackboard bb, final List< RexNode > leftKeys, SqlNodeList valuesList, SqlInOperator op)
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
final Map< CorrelationId, DeferredLookup > mapCorrelToDeferred
RelOptUtil.Exists convertExists(SqlNode seek, RelOptUtil.SubQueryType subQueryType, RelOptUtil.Logic logic, boolean notIn, RelDataType targetDataType)
RelNode createSource(RelOptTable targetTable, RelNode source, ModifiableView modifiableView, RelDataType delegateRowType)
RelNode convertRowConstructor(Blackboard bb, SqlCall rowConstructor)
RelRoot convertQueryRecursive(SqlNode query, boolean top, RelDataType targetRowType)
SqlToRelConverter(RelOptTable.ViewExpander viewExpander, SqlValidator validator, Prepare.CatalogReader catalogReader, RelOptPlanner planner, RexBuilder rexBuilder, SqlRexConvertletTable convertletTable)
final List< SqlDynamicParam > dynamicParamSqlNodes
final Map< SqlNode, RexNode > mapConvertedNonCorrSubqs
RexLiteral convertLiteralInValuesList(SqlNode sqlNode, Blackboard bb, RelDataType rowType, int iField)
void distinctify(Blackboard bb, boolean checkForDupExprs)
RelNode createModify(RelOptTable targetTable, RelNode source)
RelNode trimUnusedFields(boolean ordered, RelNode rootRel)
RexNode convertUsing(SqlValidatorNamespace leftNamespace, SqlValidatorNamespace rightNamespace, List< String > nameList)
void convertSelectImpl(final Blackboard bb, SqlSelect select)
void addConvertedNonCorrSubqs(Map< SqlNode, RexNode > alreadyConvertedNonCorrSubqs)
RexNode convertJoinCondition(Blackboard bb, SqlValidatorNamespace leftNamespace, SqlValidatorNamespace rightNamespace, SqlNode condition, JoinConditionType conditionType, RelNode leftRel, RelNode rightRel)
void collectInsertTargets(SqlInsert call, final RexNode sourceRef, final List< String > targetColumnNames, List< RexNode > columnExprs)
void replaceSubQueries(final Blackboard bb, final SqlNode expr, RelOptUtil.Logic logic)
static< T > T unwrap(Object o, Class< T > clazz)
SqlToRelConverter(RelOptTable.ViewExpander viewExpander, SqlValidator validator, Prepare.CatalogReader catalogReader, RelOptCluster cluster, SqlRexConvertletTable convertletTable, Config config)
RelNode flattenTypes(RelNode rootRel, boolean restructure)
RelNode createAggregate(Blackboard bb, ImmutableBitSet groupSet, ImmutableList< ImmutableBitSet > groupSets, List< AggregateCall > aggCalls)
CorrelationUse getCorrelationUse(Blackboard bb, final RelNode r0)
RelNode convertValues(SqlCall values, RelDataType targetRowType)
void convertAgg(Blackboard bb, SqlSelect select, List< SqlNode > orderExprList)
RexNode convertOver(Blackboard bb, SqlNode node)
final void createAggImpl(Blackboard bb, final AggConverter aggConverter, SqlNodeList selectList, SqlNodeList groupList, SqlNode having, List< SqlNode > orderExprList)
Blackboard createInsertBlackboard(RelOptTable targetTable, RexNode sourceRef, List< String > targetColumnNames)
void convertIdentifier(Blackboard bb, SqlIdentifier id, SqlNodeList extendedColumns, SqlNodeList tableHints)
RelNode convertMultisets(final List< SqlNode > operands, Blackboard bb)
static boolean containsNullLiteral(SqlNodeList valueList)
void gatherOrderExprs(Blackboard bb, SqlSelect select, SqlNodeList orderList, List< SqlNode > extraOrderExprs, List< RelFieldCollation > collationList)
RexNode convertExtendedExpression(SqlNode node, Blackboard bb)
void convertMatchRecognize(Blackboard bb, SqlCall call)
void convertWhere(final Blackboard bb, final SqlNode where)
RexNode convertExpression(SqlNode node, Map< String, RexNode > nameToNodeMap)
Blackboard(SqlValidatorScope scope, Map< String, RexNode > nameToNodeMap, boolean top)
RelNode rewriteAggregateWithGroupId(Blackboard bb, AggregatingSelectScope.Resolved r, AggConverter converter)
static SqlNode reg(SqlValidatorScope scope, SqlNode e)
boolean convertNonCorrelatedSubQuery(SubQuery subQuery, Blackboard bb, RelNode converted, boolean isExists)
void findSubQueries(Blackboard bb, SqlNode node, RelOptUtil.Logic logic, boolean registerOnlyScalarSubQueries)
Pair< RexNode, Map< String, Integer > > lookupExp(SqlQualified qualified)
boolean isSubQueryNonCorrelated(RelNode subq, Blackboard bb)
RexNode convertIdentifier(Blackboard bb, SqlIdentifier identifier)
RelNode createJoin(Blackboard bb, RelNode leftRel, RelNode rightRel, RexNode joinCond, JoinRelType joinType)
RexAccessShuttle(RexBuilder builder, RexCorrelVariable rexCorrel)
RelNode convertColumnList(final SqlInsert call, RelNode source)
void convertTemporalTable(Blackboard bb, SqlCall call)
static boolean desc(RelFieldCollation.Direction direction)
Set< RelColumnMapping > getColumnMappings(SqlOperator op)
Blackboard createBlackboard(SqlValidatorScope scope, Map< String, RexNode > nameToNodeMap, boolean top)
RelRoot convertQuery(SqlNode query, final boolean needsValidation, final boolean top)
RelFieldCollation convertOrderItem(SqlSelect select, SqlNode orderItem, List< SqlNode > extraExprs, RelFieldCollation.Direction direction, RelFieldCollation.NullDirection nullDirection)
final Map< RelNode, Map< Integer, Integer > > mapRootRelToFieldProjection
RelNode convertToSingleValueSubq(SqlNode query, RelNode plan)
static JoinRelType convertJoinType(JoinType joinType)
void setSubQueryConverter(SubQueryConverter converter)
RexNode adjustInputRef(Blackboard bb, RexInputRef inputRef)
void convertOrder(SqlSelect select, Blackboard bb, RelCollation collation, List< SqlNode > orderExprList, SqlNode offset, SqlNode fetch)
void convertSelectList(Blackboard bb, SqlSelect select, List< SqlNode > orderList)
RexNode register(RelNode rel, JoinRelType joinType)
RelNode convertSelect(SqlSelect select, boolean top)