OmniSciDB  04ee39c94c
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 
28 import org.apache.calcite.avatica.util.Spaces;
29 import org.apache.calcite.linq4j.Ord;
30 import org.apache.calcite.plan.Convention;
31 import org.apache.calcite.plan.RelOptCluster;
32 import org.apache.calcite.plan.RelOptPlanner;
33 import org.apache.calcite.plan.RelOptSamplingParameters;
34 import org.apache.calcite.plan.RelOptTable;
35 import org.apache.calcite.plan.RelOptUtil;
36 import org.apache.calcite.plan.RelTraitSet;
37 import org.apache.calcite.plan.ViewExpanders;
38 import org.apache.calcite.prepare.Prepare;
39 import org.apache.calcite.prepare.RelOptTableImpl;
40 import org.apache.calcite.rel.RelCollation;
41 import org.apache.calcite.rel.RelCollationTraitDef;
42 import org.apache.calcite.rel.RelCollations;
43 import org.apache.calcite.rel.RelFieldCollation;
44 import org.apache.calcite.rel.RelNode;
45 import org.apache.calcite.rel.RelRoot;
46 import org.apache.calcite.rel.SingleRel;
47 import org.apache.calcite.rel.core.AggregateCall;
48 import org.apache.calcite.rel.core.Collect;
49 import org.apache.calcite.rel.core.CorrelationId;
50 import org.apache.calcite.rel.core.Filter;
51 import org.apache.calcite.rel.core.Join;
52 import org.apache.calcite.rel.core.JoinInfo;
53 import org.apache.calcite.rel.core.JoinRelType;
54 import org.apache.calcite.rel.core.Project;
55 import org.apache.calcite.rel.core.RelFactories;
56 import org.apache.calcite.rel.core.Sample;
57 import org.apache.calcite.rel.core.Sort;
58 import org.apache.calcite.rel.core.TableScan;
59 import org.apache.calcite.rel.core.Uncollect;
60 import org.apache.calcite.rel.core.Values;
61 import org.apache.calcite.rel.logical.LogicalAggregate;
62 import org.apache.calcite.rel.logical.LogicalCorrelate;
63 import org.apache.calcite.rel.logical.LogicalFilter;
64 import org.apache.calcite.rel.logical.LogicalIntersect;
65 import org.apache.calcite.rel.logical.LogicalJoin;
66 import org.apache.calcite.rel.logical.LogicalMatch;
67 import org.apache.calcite.rel.logical.LogicalMinus;
68 import org.apache.calcite.rel.logical.LogicalProject;
69 import org.apache.calcite.rel.logical.LogicalSort;
70 import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
71 import org.apache.calcite.rel.logical.LogicalTableModify;
72 import org.apache.calcite.rel.logical.LogicalTableScan;
73 import org.apache.calcite.rel.logical.LogicalUnion;
74 import org.apache.calcite.rel.logical.LogicalValues;
75 import org.apache.calcite.rel.metadata.JaninoRelMetadataProvider;
76 import org.apache.calcite.rel.metadata.RelColumnMapping;
77 import org.apache.calcite.rel.metadata.RelMetadataQuery;
78 import org.apache.calcite.rel.stream.Delta;
79 import org.apache.calcite.rel.stream.LogicalDelta;
80 import org.apache.calcite.rel.type.RelDataType;
81 import org.apache.calcite.rel.type.RelDataTypeFactory;
82 import org.apache.calcite.rel.type.RelDataTypeField;
83 import org.apache.calcite.rex.RexBuilder;
84 import org.apache.calcite.rex.RexCall;
85 import org.apache.calcite.rex.RexCallBinding;
86 import org.apache.calcite.rex.RexCorrelVariable;
87 import org.apache.calcite.rex.RexDynamicParam;
88 import org.apache.calcite.rex.RexFieldAccess;
89 import org.apache.calcite.rex.RexFieldCollation;
90 import org.apache.calcite.rex.RexInputRef;
91 import org.apache.calcite.rex.RexLiteral;
92 import org.apache.calcite.rex.RexNode;
93 import org.apache.calcite.rex.RexPatternFieldRef;
94 import org.apache.calcite.rex.RexRangeRef;
95 import org.apache.calcite.rex.RexShuttle;
96 import org.apache.calcite.rex.RexSubQuery;
97 import org.apache.calcite.rex.RexUtil;
98 import org.apache.calcite.rex.RexWindowBound;
99 import org.apache.calcite.schema.ColumnStrategy;
100 import org.apache.calcite.schema.ModifiableTable;
101 import org.apache.calcite.schema.ModifiableView;
102 import org.apache.calcite.schema.Table;
103 import org.apache.calcite.schema.TranslatableTable;
104 import org.apache.calcite.schema.Wrapper;
105 import org.apache.calcite.sql.JoinConditionType;
106 import org.apache.calcite.sql.JoinType;
107 import org.apache.calcite.sql.SqlAggFunction;
108 import org.apache.calcite.sql.SqlBasicCall;
109 import org.apache.calcite.sql.SqlCall;
110 import org.apache.calcite.sql.SqlCallBinding;
111 import org.apache.calcite.sql.SqlDataTypeSpec;
112 import org.apache.calcite.sql.SqlDelete;
113 import org.apache.calcite.sql.SqlDynamicParam;
114 import org.apache.calcite.sql.SqlExplainFormat;
115 import org.apache.calcite.sql.SqlExplainLevel;
116 import org.apache.calcite.sql.SqlFunction;
117 import org.apache.calcite.sql.SqlIdentifier;
118 import org.apache.calcite.sql.SqlInsert;
119 import org.apache.calcite.sql.SqlIntervalQualifier;
120 import org.apache.calcite.sql.SqlJoin;
121 import org.apache.calcite.sql.SqlKind;
122 import org.apache.calcite.sql.SqlLiteral;
123 import org.apache.calcite.sql.SqlMatchRecognize;
124 import org.apache.calcite.sql.SqlMerge;
125 import org.apache.calcite.sql.SqlNode;
126 import org.apache.calcite.sql.SqlNodeList;
127 import org.apache.calcite.sql.SqlNumericLiteral;
128 import org.apache.calcite.sql.SqlOperator;
129 import org.apache.calcite.sql.SqlOperatorTable;
130 import org.apache.calcite.sql.SqlOrderBy;
131 import org.apache.calcite.sql.SqlSampleSpec;
132 import org.apache.calcite.sql.SqlSelect;
133 import org.apache.calcite.sql.SqlSelectKeyword;
134 import org.apache.calcite.sql.SqlSetOperator;
135 import org.apache.calcite.sql.SqlSnapshot;
136 import org.apache.calcite.sql.SqlUnnestOperator;
137 import org.apache.calcite.sql.SqlUpdate;
138 import org.apache.calcite.sql.SqlUtil;
139 import org.apache.calcite.sql.SqlValuesOperator;
140 import org.apache.calcite.sql.SqlWindow;
141 import org.apache.calcite.sql.SqlWith;
142 import org.apache.calcite.sql.SqlWithItem;
143 import org.apache.calcite.sql.fun.SqlCase;
144 import org.apache.calcite.sql.fun.SqlCountAggFunction;
145 import org.apache.calcite.sql.fun.SqlInOperator;
146 import org.apache.calcite.sql.fun.SqlQuantifyOperator;
147 import org.apache.calcite.sql.fun.SqlRowOperator;
148 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
149 import org.apache.calcite.sql.parser.SqlParserPos;
150 import org.apache.calcite.sql.type.SqlReturnTypeInference;
151 import org.apache.calcite.sql.type.SqlTypeName;
152 import org.apache.calcite.sql.type.SqlTypeUtil;
153 import org.apache.calcite.sql.type.TableFunctionReturnTypeInference;
154 import org.apache.calcite.sql.util.SqlBasicVisitor;
155 import org.apache.calcite.sql.util.SqlVisitor;
156 import org.apache.calcite.sql.validate.AggregatingSelectScope;
157 import org.apache.calcite.sql.validate.CollectNamespace;
158 import org.apache.calcite.sql.validate.DelegatingScope;
159 import org.apache.calcite.sql.validate.ListScope;
160 import org.apache.calcite.sql.validate.MatchRecognizeScope;
161 import org.apache.calcite.sql.validate.ParameterScope;
162 import org.apache.calcite.sql.validate.SelectScope;
163 import org.apache.calcite.sql.validate.SqlMonotonicity;
164 import org.apache.calcite.sql.validate.SqlNameMatcher;
165 import org.apache.calcite.sql.validate.SqlQualified;
166 import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction;
167 import org.apache.calcite.sql.validate.SqlUserDefinedTableMacro;
168 import org.apache.calcite.sql.validate.SqlValidator;
169 import org.apache.calcite.sql.validate.SqlValidatorImpl;
170 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
171 import org.apache.calcite.sql.validate.SqlValidatorScope;
172 import org.apache.calcite.sql.validate.SqlValidatorTable;
173 import org.apache.calcite.sql.validate.SqlValidatorUtil;
174 import org.apache.calcite.tools.RelBuilder;
175 import org.apache.calcite.tools.RelBuilderFactory;
176 import org.apache.calcite.util.ImmutableBitSet;
177 import org.apache.calcite.util.ImmutableIntList;
178 import org.apache.calcite.util.Litmus;
179 import org.apache.calcite.util.NlsString;
180 import org.apache.calcite.util.NumberUtil;
181 import org.apache.calcite.util.Pair;
182 import org.apache.calcite.util.Util;
183 import org.apache.calcite.util.trace.CalciteTrace;
184 import org.slf4j.Logger;
185 
186 import java.lang.reflect.Type;
187 import java.math.BigDecimal;
188 import java.util.AbstractList;
189 import java.util.ArrayDeque;
190 import java.util.ArrayList;
191 import java.util.BitSet;
192 import java.util.Collection;
193 import java.util.Collections;
194 import java.util.Deque;
195 import java.util.EnumSet;
196 import java.util.HashMap;
197 import java.util.HashSet;
198 import java.util.LinkedHashSet;
199 import java.util.List;
200 import java.util.Map;
201 import java.util.Objects;
202 import java.util.Set;
203 import java.util.TreeSet;
204 import java.util.function.Supplier;
205 import java.util.stream.Collectors;
206 
215 public class SqlToRelConverter {
216  //~ Static fields/initializers ---------------------------------------------
217 
218  protected static final Logger SQL2REL_LOGGER = CalciteTrace.getSqlToRelTracer();
219 
220  private static final BigDecimal TWO = BigDecimal.valueOf(2L);
221 
226  public static final int DEFAULT_IN_SUB_QUERY_THRESHOLD = 20;
227 
228  @Deprecated // to be removed before 2.0
230 
231  //~ Instance fields --------------------------------------------------------
232 
233  protected final SqlValidator validator;
234  protected final RexBuilder rexBuilder;
235  protected final Prepare.CatalogReader catalogReader;
236  protected final RelOptCluster cluster;
237  private SubQueryConverter subQueryConverter;
238  protected final List<RelNode> leaves = new ArrayList<>();
239  private final List<SqlDynamicParam> dynamicParamSqlNodes = new ArrayList<>();
240  private final SqlOperatorTable opTab;
241  protected final RelDataTypeFactory typeFactory;
242  private final SqlNodeToRexConverter exprConverter;
243  private int explainParamCount;
245  private final RelBuilder relBuilder;
246 
250  private final Map<CorrelationId, DeferredLookup> mapCorrelToDeferred = new HashMap<>();
251 
256  private final Deque<String> datasetStack = new ArrayDeque<>();
257 
263  private final Map<SqlNode, RexNode> mapConvertedNonCorrSubqs = new HashMap<>();
264 
265  public final RelOptTable.ViewExpander viewExpander;
266 
267  //~ Constructors -----------------------------------------------------------
278  @Deprecated // to be removed before 2.0
279  public SqlToRelConverter(RelOptTable.ViewExpander viewExpander,
280  SqlValidator validator,
281  Prepare.CatalogReader catalogReader,
282  RelOptPlanner planner,
283  RexBuilder rexBuilder,
284  SqlRexConvertletTable convertletTable) {
285  this(viewExpander,
286  validator,
288  RelOptCluster.create(planner, rexBuilder),
289  convertletTable,
290  Config.DEFAULT);
291  }
292 
293  @Deprecated // to be removed before 2.0
294  public SqlToRelConverter(RelOptTable.ViewExpander viewExpander,
295  SqlValidator validator,
296  Prepare.CatalogReader catalogReader,
297  RelOptCluster cluster,
298  SqlRexConvertletTable convertletTable) {
299  this(viewExpander,
300  validator,
302  cluster,
303  convertletTable,
304  Config.DEFAULT);
305  }
306 
307  /* Creates a converter. */
308  public SqlToRelConverter(RelOptTable.ViewExpander viewExpander,
309  SqlValidator validator,
310  Prepare.CatalogReader catalogReader,
311  RelOptCluster cluster,
312  SqlRexConvertletTable convertletTable,
313  Config config) {
314  this.viewExpander = viewExpander;
315  this.opTab = (validator == null) ? SqlStdOperatorTable.instance()
316  : validator.getOperatorTable();
317  this.validator = validator;
319  this.subQueryConverter = new NoOpSubQueryConverter();
320  this.rexBuilder = cluster.getRexBuilder();
321  this.typeFactory = rexBuilder.getTypeFactory();
322  this.cluster = Objects.requireNonNull(cluster);
323  this.exprConverter = new SqlNodeToRexConverterImpl(convertletTable);
324  this.explainParamCount = 0;
325  this.config = new ConfigBuilder().withConfig(config).build();
326  this.relBuilder = config.getRelBuilderFactory().create(cluster, null);
327  }
328 
329  //~ Methods ----------------------------------------------------------------
330 
334  public RelOptCluster getCluster() {
335  return cluster;
336  }
337 
341  public RexBuilder getRexBuilder() {
342  return rexBuilder;
343  }
344 
351  public int getDynamicParamCount() {
352  return dynamicParamSqlNodes.size();
353  }
354 
361  public RelDataType getDynamicParamType(int index) {
362  SqlNode sqlNode = dynamicParamSqlNodes.get(index);
363  if (sqlNode == null) {
364  throw Util.needToImplement("dynamic param type inference");
365  }
366  return validator.getValidatedNodeType(sqlNode);
367  }
368 
376  public int getDynamicParamCountInExplain(boolean increment) {
377  int retVal = explainParamCount;
378  if (increment) {
380  }
381  return retVal;
382  }
383 
388  public Map<SqlNode, RexNode> getMapConvertedNonCorrSubqs() {
390  }
391 
400  Map<SqlNode, RexNode> alreadyConvertedNonCorrSubqs) {
401  mapConvertedNonCorrSubqs.putAll(alreadyConvertedNonCorrSubqs);
402  }
403 
410  public void setSubQueryConverter(SubQueryConverter converter) {
411  subQueryConverter = converter;
412  }
413 
420  public void setDynamicParamCountInExplain(int explainParamCount) {
421  assert config.isExplain();
422  this.explainParamCount = explainParamCount;
423  }
424 
425  private void checkConvertedType(SqlNode query, RelNode result) {
426  if (query.isA(SqlKind.DML)) {
427  return;
428  }
429  // Verify that conversion from SQL to relational algebra did
430  // not perturb any type information. (We can't do this if the
431  // SQL statement is something like an INSERT which has no
432  // validator type information associated with its result,
433  // hence the namespace check above.)
434  final List<RelDataTypeField> validatedFields =
435  validator.getValidatedNodeType(query).getFieldList();
436  final RelDataType validatedRowType =
437  validator.getTypeFactory().createStructType(Pair.right(validatedFields),
438  SqlValidatorUtil.uniquify(Pair.left(validatedFields),
439  catalogReader.nameMatcher().isCaseSensitive()));
440 
441  final List<RelDataTypeField> convertedFields =
442  result.getRowType().getFieldList().subList(0, validatedFields.size());
443  final RelDataType convertedRowType =
444  validator.getTypeFactory().createStructType(convertedFields);
445 
446  if (!RelOptUtil.equal("validated row type",
447  validatedRowType,
448  "converted row type",
449  convertedRowType,
450  Litmus.IGNORE)) {
451  throw new AssertionError("Conversion to relational algebra failed to "
452  + "preserve datatypes:\n"
453  + "validated type:\n" + validatedRowType.getFullTypeString()
454  + "\nconverted type:\n" + convertedRowType.getFullTypeString() + "\nrel:\n"
455  + RelOptUtil.toString(result));
456  }
457  }
458 
459  public RelNode flattenTypes(RelNode rootRel, boolean restructure) {
460  RelStructuredTypeFlattener typeFlattener = new RelStructuredTypeFlattener(
461  relBuilder, rexBuilder, createToRelContext(), restructure);
462  return typeFlattener.rewrite(rootRel);
463  }
464 
473  public RelNode decorrelate(SqlNode query, RelNode rootRel) {
474  if (!enableDecorrelation()) {
475  return rootRel;
476  }
477  final RelNode result = decorrelateQuery(rootRel);
478  if (result != rootRel) {
479  checkConvertedType(query, result);
480  }
481  return result;
482  }
483 
503  public RelNode trimUnusedFields(boolean ordered, RelNode rootRel) {
504  // Trim fields that are not used by their consumer.
505  if (isTrimUnusedFields()) {
506  final RelFieldTrimmer trimmer = newFieldTrimmer();
507  final List<RelCollation> collations =
508  rootRel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
509  rootRel = trimmer.trim(rootRel);
510  if (!ordered && collations != null && !collations.isEmpty()
511  && !collations.equals(ImmutableList.of(RelCollations.EMPTY))) {
512  final RelTraitSet traitSet =
513  rootRel.getTraitSet().replace(RelCollationTraitDef.INSTANCE, collations);
514  rootRel = rootRel.copy(traitSet, rootRel.getInputs());
515  }
516  if (SQL2REL_LOGGER.isDebugEnabled()) {
517  SQL2REL_LOGGER.debug(RelOptUtil.dumpPlan("Plan after trimming unused fields",
518  rootRel,
519  SqlExplainFormat.TEXT,
520  SqlExplainLevel.EXPPLAN_ATTRIBUTES));
521  }
522  }
523  return rootRel;
524  }
525 
531  protected RelFieldTrimmer newFieldTrimmer() {
532  return new RelFieldTrimmer(validator, relBuilder);
533  }
534 
546  public RelRoot convertQuery(
547  SqlNode query, final boolean needsValidation, final boolean top) {
548  if (needsValidation) {
549  query = validator.validate(query);
550  }
551 
552  RelMetadataQuery.THREAD_PROVIDERS.set(
553  JaninoRelMetadataProvider.of(cluster.getMetadataProvider()));
554  RelNode result = convertQueryRecursive(query, top, null).rel;
555  if (top) {
556  if (isStream(query)) {
557  result = new LogicalDelta(cluster, result.getTraitSet(), result);
558  }
559  }
560  RelCollation collation = RelCollations.EMPTY;
561  if (!query.isA(SqlKind.DML)) {
562  if (isOrdered(query)) {
563  collation = requiredCollation(result);
564  }
565  }
566  checkConvertedType(query, result);
567 
568  if (SQL2REL_LOGGER.isDebugEnabled()) {
569  SQL2REL_LOGGER.debug(RelOptUtil.dumpPlan("Plan after converting SqlNode to RelNode",
570  result,
571  SqlExplainFormat.TEXT,
572  SqlExplainLevel.EXPPLAN_ATTRIBUTES));
573  }
574 
575  final RelDataType validatedRowType = validator.getValidatedNodeType(query);
576  return RelRoot.of(result, validatedRowType, query.getKind()).withCollation(collation);
577  }
578 
579  private static boolean isStream(SqlNode query) {
580  return query instanceof SqlSelect
581  && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
582  }
583 
584  public static boolean isOrdered(SqlNode query) {
585  switch (query.getKind()) {
586  case SELECT:
587  return ((SqlSelect) query).getOrderList() != null
588  && ((SqlSelect) query).getOrderList().size() > 0;
589  case WITH:
590  return isOrdered(((SqlWith) query).body);
591  case ORDER_BY:
592  return ((SqlOrderBy) query).orderList.size() > 0;
593  default:
594  return false;
595  }
596  }
597 
598  private RelCollation requiredCollation(RelNode r) {
599  if (r instanceof Sort) {
600  return ((Sort) r).collation;
601  }
602  if (r instanceof Project) {
603  return requiredCollation(((Project) r).getInput());
604  }
605  if (r instanceof Delta) {
606  return requiredCollation(((Delta) r).getInput());
607  }
608  throw new AssertionError();
609  }
610 
614  public RelNode convertSelect(SqlSelect select, boolean top) {
615  final SqlValidatorScope selectScope = validator.getWhereScope(select);
616  final Blackboard bb = createBlackboard(selectScope, null, top);
617  convertSelectImpl(bb, select);
618  return bb.root;
619  }
620 
625  SqlValidatorScope scope, Map<String, RexNode> nameToNodeMap, boolean top) {
626  return new Blackboard(scope, nameToNodeMap, top);
627  }
628 
633  protected void convertSelectImpl(final Blackboard bb, SqlSelect select) {
634  convertFrom(bb, select.getFrom());
635  convertWhere(bb, select.getWhere());
636 
637  final List<SqlNode> orderExprList = new ArrayList<>();
638  final List<RelFieldCollation> collationList = new ArrayList<>();
639  gatherOrderExprs(bb, select, select.getOrderList(), orderExprList, collationList);
640  final RelCollation collation =
641  cluster.traitSet().canonize(RelCollations.of(collationList));
642 
643  if (validator.isAggregate(select)) {
644  convertAgg(bb, select, orderExprList);
645  } else {
646  convertSelectList(bb, select, orderExprList);
647  }
648 
649  if (select.isDistinct()) {
650  distinctify(bb, true);
651  }
652  convertOrder(
653  select, bb, collation, orderExprList, select.getOffset(), select.getFetch());
654  bb.setRoot(bb.root, true);
655  }
656 
669  private void distinctify(Blackboard bb, boolean checkForDupExprs) {
670  // Look for duplicate expressions in the project.
671  // Say we have 'select x, y, x, z'.
672  // Then dups will be {[2, 0]}
673  // and oldToNew will be {[0, 0], [1, 1], [2, 0], [3, 2]}
674  RelNode rel = bb.root;
675  if (checkForDupExprs && (rel instanceof LogicalProject)) {
676  LogicalProject project = (LogicalProject) rel;
677  final List<RexNode> projectExprs = project.getProjects();
678  final List<Integer> origins = new ArrayList<>();
679  int dupCount = 0;
680  for (int i = 0; i < projectExprs.size(); i++) {
681  int x = projectExprs.indexOf(projectExprs.get(i));
682  if (x >= 0 && x < i) {
683  origins.add(x);
684  ++dupCount;
685  } else {
686  origins.add(i);
687  }
688  }
689  if (dupCount == 0) {
690  distinctify(bb, false);
691  return;
692  }
693 
694  final Map<Integer, Integer> squished = new HashMap<>();
695  final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
696  final List<Pair<RexNode, String>> newProjects = new ArrayList<>();
697  for (int i = 0; i < fields.size(); i++) {
698  if (origins.get(i) == i) {
699  squished.put(i, newProjects.size());
700  newProjects.add(RexInputRef.of2(i, fields));
701  }
702  }
703  rel = LogicalProject.create(rel, Pair.left(newProjects), Pair.right(newProjects));
704  bb.root = rel;
705  distinctify(bb, false);
706  rel = bb.root;
707 
708  // Create the expressions to reverse the mapping.
709  // Project($0, $1, $0, $2).
710  final List<Pair<RexNode, String>> undoProjects = new ArrayList<>();
711  for (int i = 0; i < fields.size(); i++) {
712  final int origin = origins.get(i);
713  RelDataTypeField field = fields.get(i);
714  undoProjects.add(
715  Pair.of((RexNode) new RexInputRef(squished.get(origin), field.getType()),
716  field.getName()));
717  }
718 
719  rel = LogicalProject.create(rel, Pair.left(undoProjects), Pair.right(undoProjects));
720  bb.setRoot(rel, false);
721 
722  return;
723  }
724 
725  // Usual case: all of the expressions in the SELECT clause are
726  // different.
727  final ImmutableBitSet groupSet =
728  ImmutableBitSet.range(rel.getRowType().getFieldCount());
729  rel = createAggregate(bb, groupSet, ImmutableList.of(groupSet), ImmutableList.of());
730 
731  bb.setRoot(rel, false);
732  }
733 
749  protected void convertOrder(SqlSelect select,
750  Blackboard bb,
751  RelCollation collation,
752  List<SqlNode> orderExprList,
753  SqlNode offset,
754  SqlNode fetch) {
755  if (!bb.top || select.getOrderList() == null
756  || select.getOrderList().getList().isEmpty()) {
757  assert !bb.top || collation.getFieldCollations().isEmpty();
758  if ((offset == null
759  || (offset instanceof SqlLiteral
760  && ((SqlLiteral) offset)
761  .bigDecimalValue()
762  .equals(BigDecimal.ZERO)))
763  && fetch == null) {
764  return;
765  }
766  }
767 
768  // Create a sorter using the previously constructed collations.
769  bb.setRoot(LogicalSort.create(bb.root,
770  collation,
771  offset == null ? null : convertExpression(offset),
772  fetch == null ? null : convertExpression(fetch)),
773  false);
774 
775  // If extra expressions were added to the project list for sorting,
776  // add another project to remove them. But make the collation empty, because
777  // we can't represent the real collation.
778  //
779  // If it is the top node, use the real collation, but don't trim fields.
780  if (orderExprList.size() > 0 && !bb.top) {
781  final List<RexNode> exprs = new ArrayList<>();
782  final RelDataType rowType = bb.root.getRowType();
783  final int fieldCount = rowType.getFieldCount() - orderExprList.size();
784  for (int i = 0; i < fieldCount; i++) {
785  exprs.add(rexBuilder.makeInputRef(bb.root, i));
786  }
787  bb.setRoot(LogicalProject.create(
788  bb.root, exprs, rowType.getFieldNames().subList(0, fieldCount)),
789  false);
790  }
791  }
792 
798  private static boolean containsInOperator(SqlNode node) {
799  try {
800  SqlVisitor<Void> visitor = new SqlBasicVisitor<Void>() {
801  public Void visit(SqlCall call) {
802  if (call.getOperator() instanceof SqlInOperator) {
803  throw new Util.FoundOne(call);
804  }
805  return super.visit(call);
806  }
807  };
808  node.accept(visitor);
809  return false;
810  } catch (Util.FoundOne e) {
811  Util.swallow(e, null);
812  return true;
813  }
814  }
815 
823  private static SqlNode pushDownNotForIn(SqlValidatorScope scope, SqlNode sqlNode) {
824  if (!(sqlNode instanceof SqlCall) || !containsInOperator(sqlNode)) {
825  return sqlNode;
826  }
827  final SqlCall sqlCall = (SqlCall) sqlNode;
828  switch (sqlCall.getKind()) {
829  case AND:
830  case OR:
831  final List<SqlNode> operands = new ArrayList<>();
832  for (SqlNode operand : sqlCall.getOperandList()) {
833  operands.add(pushDownNotForIn(scope, operand));
834  }
835  final SqlCall newCall =
836  sqlCall.getOperator().createCall(sqlCall.getParserPosition(), operands);
837  return reg(scope, newCall);
838 
839  case NOT:
840  assert sqlCall.operand(0) instanceof SqlCall;
841  final SqlCall call = sqlCall.operand(0);
842  switch (sqlCall.operand(0).getKind()) {
843  case CASE:
844  final SqlCase caseNode = (SqlCase) call;
845  final SqlNodeList thenOperands = new SqlNodeList(SqlParserPos.ZERO);
846 
847  for (SqlNode thenOperand : caseNode.getThenOperands()) {
848  final SqlCall not =
849  SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO, thenOperand);
850  thenOperands.add(pushDownNotForIn(scope, reg(scope, not)));
851  }
852  SqlNode elseOperand = caseNode.getElseOperand();
853  if (!SqlUtil.isNull(elseOperand)) {
854  // "not(unknown)" is "unknown", so no need to simplify
855  final SqlCall not =
856  SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO, elseOperand);
857  elseOperand = pushDownNotForIn(scope, reg(scope, not));
858  }
859 
860  return reg(scope,
861  SqlStdOperatorTable.CASE.createCall(SqlParserPos.ZERO,
862  caseNode.getValueOperand(),
863  caseNode.getWhenOperands(),
864  thenOperands,
865  elseOperand));
866 
867  case AND:
868  final List<SqlNode> orOperands = new ArrayList<>();
869  for (SqlNode operand : call.getOperandList()) {
870  orOperands.add(pushDownNotForIn(scope,
871  reg(scope,
872  SqlStdOperatorTable.NOT.createCall(
873  SqlParserPos.ZERO, operand))));
874  }
875  return reg(scope,
876  SqlStdOperatorTable.OR.createCall(SqlParserPos.ZERO, orOperands));
877 
878  case OR:
879  final List<SqlNode> andOperands = new ArrayList<>();
880  for (SqlNode operand : call.getOperandList()) {
881  andOperands.add(pushDownNotForIn(scope,
882  reg(scope,
883  SqlStdOperatorTable.NOT.createCall(
884  SqlParserPos.ZERO, operand))));
885  }
886  return reg(scope,
887  SqlStdOperatorTable.AND.createCall(SqlParserPos.ZERO, andOperands));
888 
889  case NOT:
890  assert call.operandCount() == 1;
891  return pushDownNotForIn(scope, call.operand(0));
892 
893  case NOT_IN:
894  return reg(scope,
895  SqlStdOperatorTable.IN.createCall(
896  SqlParserPos.ZERO, call.getOperandList()));
897 
898  case IN:
899  return reg(scope,
900  SqlStdOperatorTable.NOT_IN.createCall(
901  SqlParserPos.ZERO, call.getOperandList()));
902  }
903  }
904  return sqlNode;
905  }
906 
911  private static SqlNode reg(SqlValidatorScope scope, SqlNode e) {
912  scope.getValidator().deriveType(scope, e);
913  return e;
914  }
915 
922  private void convertWhere(final Blackboard bb, final SqlNode where) {
923  if (where == null) {
924  return;
925  }
926  SqlNode newWhere = pushDownNotForIn(bb.scope, where);
927  replaceSubQueries(bb, newWhere, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
928  final RexNode convertedWhere = bb.convertExpression(newWhere);
929  final RexNode convertedWhere2 =
930  RexUtil.removeNullabilityCast(typeFactory, convertedWhere);
931 
932  // only allocate filter if the condition is not TRUE
933  if (convertedWhere2.isAlwaysTrue()) {
934  return;
935  }
936 
937  final RelFactories.FilterFactory filterFactory = RelFactories.DEFAULT_FILTER_FACTORY;
938  final RelNode filter = filterFactory.createFilter(bb.root, convertedWhere2);
939  final RelNode r;
940  final CorrelationUse p = getCorrelationUse(bb, filter);
941  if (p != null) {
942  assert p.r instanceof Filter;
943  Filter f = (Filter) p.r;
944  r = LogicalFilter.create(f.getInput(), f.getCondition(), ImmutableSet.of(p.id));
945  } else {
946  r = filter;
947  }
948 
949  bb.setRoot(r, false);
950  }
951 
952  private void replaceSubQueries(
953  final Blackboard bb, final SqlNode expr, RelOptUtil.Logic logic) {
954  findSubQueries(bb, expr, logic, false);
955  for (SubQuery node : bb.subQueryList) {
956  substituteSubQuery(bb, node);
957  }
958  }
959 
960  private void substituteSubQuery(Blackboard bb, SubQuery subQuery) {
961  final RexNode expr = subQuery.expr;
962  if (expr != null) {
963  // Already done.
964  return;
965  }
966 
967  final SqlBasicCall call;
968  final RelNode rel;
969  final SqlNode query;
970  final RelOptUtil.Exists converted;
971  switch (subQuery.node.getKind()) {
972  case CURSOR:
973  convertCursor(bb, subQuery);
974  return;
975 
976  case MULTISET_QUERY_CONSTRUCTOR:
977  case MULTISET_VALUE_CONSTRUCTOR:
978  case ARRAY_QUERY_CONSTRUCTOR:
979  rel = convertMultisets(ImmutableList.of(subQuery.node), bb);
980  subQuery.expr = bb.register(rel, JoinRelType.INNER);
981  return;
982 
983  case IN:
984  case NOT_IN:
985  case SOME:
986  case ALL:
987  call = (SqlBasicCall) subQuery.node;
988  query = call.operand(1);
989  if (!config.isExpand() && !(query instanceof SqlNodeList)) {
990  return;
991  }
992  final SqlNode leftKeyNode = call.operand(0);
993 
994  final List<RexNode> leftKeys;
995  switch (leftKeyNode.getKind()) {
996  case ROW:
997  leftKeys = new ArrayList<>();
998  for (SqlNode sqlExpr : ((SqlBasicCall) leftKeyNode).getOperandList()) {
999  leftKeys.add(bb.convertExpression(sqlExpr));
1000  }
1001  break;
1002  default:
1003  leftKeys = ImmutableList.of(bb.convertExpression(leftKeyNode));
1004  }
1005 
1006  if (query instanceof SqlNodeList) {
1007  SqlNodeList valueList = (SqlNodeList) query;
1008  if (!containsNullLiteral(valueList)
1009  && valueList.size() < config.getInSubQueryThreshold()) {
1010  // We're under the threshold, so convert to OR.
1011  subQuery.expr = convertInToOr(
1012  bb, leftKeys, valueList, (SqlInOperator) call.getOperator());
1013  return;
1014  }
1015 
1016  // Otherwise, let convertExists translate
1017  // values list into an inline table for the
1018  // reference to Q below.
1019  }
1020 
1021  // Project out the search columns from the left side
1022 
1023  // Q1:
1024  // "select from emp where emp.deptno in (select col1 from T)"
1025  //
1026  // is converted to
1027  //
1028  // "select from
1029  // emp inner join (select distinct col1 from T)) q
1030  // on emp.deptno = q.col1
1031  //
1032  // Q2:
1033  // "select from emp where emp.deptno not in (Q)"
1034  //
1035  // is converted to
1036  //
1037  // "select from
1038  // emp left outer join (select distinct col1, TRUE from T) q
1039  // on emp.deptno = q.col1
1040  // where emp.deptno <> null
1041  // and q.indicator <> TRUE"
1042  //
1043  final RelDataType targetRowType = SqlTypeUtil.promoteToRowType(
1044  typeFactory, validator.getValidatedNodeType(leftKeyNode), null);
1045  final boolean notIn = call.getOperator().kind == SqlKind.NOT_IN;
1046  converted = convertExists(
1047  query, RelOptUtil.SubQueryType.IN, subQuery.logic, notIn, targetRowType);
1048  if (converted.indicator) {
1049  // Generate
1050  // emp CROSS JOIN (SELECT COUNT(*) AS c,
1051  // COUNT(deptno) AS ck FROM dept)
1052  final RelDataType longType = typeFactory.createSqlType(SqlTypeName.BIGINT);
1053  final RelNode seek = converted.r.getInput(0); // fragile
1054  final int keyCount = leftKeys.size();
1055  final List<Integer> args = ImmutableIntList.range(0, keyCount);
1056  LogicalAggregate aggregate = LogicalAggregate.create(seek,
1057  ImmutableBitSet.of(),
1058  null,
1059  ImmutableList.of(AggregateCall.create(SqlStdOperatorTable.COUNT,
1060  false,
1061  false,
1062  false,
1063  ImmutableList.of(),
1064  -1,
1065  RelCollations.EMPTY,
1066  longType,
1067  null),
1068  AggregateCall.create(SqlStdOperatorTable.COUNT,
1069  false,
1070  false,
1071  false,
1072  args,
1073  -1,
1074  RelCollations.EMPTY,
1075  longType,
1076  null)));
1077  LogicalJoin join = LogicalJoin.create(bb.root,
1078  aggregate,
1079  rexBuilder.makeLiteral(true),
1080  ImmutableSet.of(),
1081  JoinRelType.INNER);
1082  bb.setRoot(join, false);
1083  }
1084  final RexNode rex = bb.register(converted.r,
1085  converted.outerJoin ? JoinRelType.LEFT : JoinRelType.INNER,
1086  leftKeys);
1087 
1088  RelOptUtil.Logic logic = subQuery.logic;
1089  switch (logic) {
1090  case TRUE_FALSE_UNKNOWN:
1091  case UNKNOWN_AS_TRUE:
1092  if (!converted.indicator) {
1093  logic = RelOptUtil.Logic.TRUE_FALSE;
1094  }
1095  }
1096  subQuery.expr = translateIn(logic, bb.root, rex);
1097  if (notIn) {
1098  subQuery.expr = rexBuilder.makeCall(SqlStdOperatorTable.NOT, subQuery.expr);
1099  }
1100  return;
1101 
1102  case EXISTS:
1103  // "select from emp where exists (select a from T)"
1104  //
1105  // is converted to the following if the sub-query is correlated:
1106  //
1107  // "select from emp left outer join (select AGG_TRUE() as indicator
1108  // from T group by corr_var) q where q.indicator is true"
1109  //
1110  // If there is no correlation, the expression is replaced with a
1111  // boolean indicating whether the sub-query returned 0 or >= 1 row.
1112  call = (SqlBasicCall) subQuery.node;
1113  query = call.operand(0);
1114  if (!config.isExpand()) {
1115  return;
1116  }
1117  final SqlValidatorScope seekScope = (query instanceof SqlSelect)
1118  ? validator.getSelectScope((SqlSelect) query)
1119  : null;
1120  final Blackboard seekBb = createBlackboard(seekScope, null, false);
1121  final RelNode seekRel = convertQueryOrInList(seekBb, query, null);
1122  // An EXIST sub-query whose inner child has at least 1 tuple
1123  // (e.g. an Aggregate with no grouping columns or non-empty Values
1124  // node) should be simplified to a Boolean constant expression.
1125  final RelMetadataQuery mq = seekRel.getCluster().getMetadataQuery();
1126  final Double minRowCount = mq.getMinRowCount(seekRel);
1127  if (minRowCount != null && minRowCount >= 1D) {
1128  subQuery.expr = rexBuilder.makeLiteral(true);
1129  return;
1130  }
1131  converted = RelOptUtil.createExistsPlan(seekRel,
1132  RelOptUtil.SubQueryType.EXISTS,
1133  subQuery.logic,
1134  true,
1135  relBuilder);
1136  assert !converted.indicator;
1137  if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, true)) {
1138  return;
1139  }
1140  subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
1141  return;
1142 
1143  case SCALAR_QUERY:
1144  // Convert the sub-query. If it's non-correlated, convert it
1145  // to a constant expression.
1146  if (!config.isExpand()) {
1147  return;
1148  }
1149  call = (SqlBasicCall) subQuery.node;
1150  query = call.operand(0);
1151  converted = convertExists(
1152  query, RelOptUtil.SubQueryType.SCALAR, subQuery.logic, true, null);
1153  assert !converted.indicator;
1154  if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, false)) {
1155  return;
1156  }
1157  rel = convertToSingleValueSubq(query, converted.r);
1158  subQuery.expr = bb.register(rel, JoinRelType.LEFT);
1159  return;
1160 
1161  case SELECT:
1162  // This is used when converting multiset queries:
1163  //
1164  // select * from unnest(select multiset[deptno] from emps);
1165  //
1166  converted = convertExists(subQuery.node,
1167  RelOptUtil.SubQueryType.SCALAR,
1168  subQuery.logic,
1169  true,
1170  null);
1171  assert !converted.indicator;
1172  subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
1173  return;
1174 
1175  default:
1176  throw new AssertionError("unexpected kind of sub-query: " + subQuery.node);
1177  }
1178  }
1179 
1180  private RexNode translateIn(RelOptUtil.Logic logic, RelNode root, final RexNode rex) {
1181  switch (logic) {
1182  case TRUE:
1183  return rexBuilder.makeLiteral(true);
1184 
1185  case TRUE_FALSE:
1186  case UNKNOWN_AS_FALSE:
1187  assert rex instanceof RexRangeRef;
1188  final int fieldCount = rex.getType().getFieldCount();
1189  RexNode rexNode = rexBuilder.makeFieldAccess(rex, fieldCount - 1);
1190  rexNode = rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, rexNode);
1191 
1192  // Then append the IS NOT NULL(leftKeysForIn).
1193  //
1194  // RexRangeRef contains the following fields:
1195  // leftKeysForIn,
1196  // rightKeysForIn (the original sub-query select list),
1197  // nullIndicator
1198  //
1199  // The first two lists contain the same number of fields.
1200  final int k = (fieldCount - 1) / 2;
1201  for (int i = 0; i < k; i++) {
1202  rexNode = rexBuilder.makeCall(SqlStdOperatorTable.AND,
1203  rexNode,
1204  rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
1205  rexBuilder.makeFieldAccess(rex, i)));
1206  }
1207  return rexNode;
1208 
1209  case TRUE_FALSE_UNKNOWN:
1210  case UNKNOWN_AS_TRUE:
1211  // select e.deptno,
1212  // case
1213  // when ct.c = 0 then false
1214  // when dt.i is not null then true
1215  // when e.deptno is null then null
1216  // when ct.ck < ct.c then null
1217  // else false
1218  // end
1219  // from e
1220  // cross join (select count(*) as c, count(deptno) as ck from v) as ct
1221  // left join (select distinct deptno, true as i from v) as dt
1222  // on e.deptno = dt.deptno
1223  final Join join = (Join) root;
1224  final Project left = (Project) join.getLeft();
1225  final RelNode leftLeft = ((Join) left.getInput()).getLeft();
1226  final int leftLeftCount = leftLeft.getRowType().getFieldCount();
1227  final RelDataType longType = typeFactory.createSqlType(SqlTypeName.BIGINT);
1228  final RexNode cRef = rexBuilder.makeInputRef(root, leftLeftCount);
1229  final RexNode ckRef = rexBuilder.makeInputRef(root, leftLeftCount + 1);
1230  final RexNode iRef =
1231  rexBuilder.makeInputRef(root, root.getRowType().getFieldCount() - 1);
1232 
1233  final RexLiteral zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO, longType);
1234  final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
1235  final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
1236  final RexNode unknownLiteral = rexBuilder.makeNullLiteral(trueLiteral.getType());
1237 
1238  final ImmutableList.Builder<RexNode> args = ImmutableList.builder();
1239  args.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, cRef, zero),
1240  falseLiteral,
1241  rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, iRef),
1242  trueLiteral);
1243  final JoinInfo joinInfo = join.analyzeCondition();
1244  for (int leftKey : joinInfo.leftKeys) {
1245  final RexNode kRef = rexBuilder.makeInputRef(root, leftKey);
1246  args.add(
1247  rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, kRef), unknownLiteral);
1248  }
1249  args.add(rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ckRef, cRef),
1250  unknownLiteral,
1251  falseLiteral);
1252 
1253  return rexBuilder.makeCall(SqlStdOperatorTable.CASE, args.build());
1254 
1255  default:
1256  throw new AssertionError(logic);
1257  }
1258  }
1259 
1260  private static boolean containsNullLiteral(SqlNodeList valueList) {
1261  for (SqlNode node : valueList.getList()) {
1262  if (node instanceof SqlLiteral) {
1263  SqlLiteral lit = (SqlLiteral) node;
1264  if (lit.getValue() == null) {
1265  return true;
1266  }
1267  }
1268  }
1269  return false;
1270  }
1271 
1283  SubQuery subQuery, Blackboard bb, RelNode converted, boolean isExists) {
1284  SqlCall call = (SqlBasicCall) subQuery.node;
1285  if (subQueryConverter.canConvertSubQuery()
1286  && isSubQueryNonCorrelated(converted, bb)) {
1287  // First check if the sub-query has already been converted
1288  // because it's a nested sub-query. If so, don't re-evaluate
1289  // it again.
1290  RexNode constExpr = mapConvertedNonCorrSubqs.get(call);
1291  if (constExpr == null) {
1292  constExpr = subQueryConverter.convertSubQuery(
1293  call, this, isExists, config.isExplain());
1294  }
1295  if (constExpr != null) {
1296  subQuery.expr = constExpr;
1297  mapConvertedNonCorrSubqs.put(call, constExpr);
1298  return true;
1299  }
1300  }
1301  return false;
1302  }
1303 
1312  public RelNode convertToSingleValueSubq(SqlNode query, RelNode plan) {
1313  // Check whether query is guaranteed to produce a single value.
1314  if (query instanceof SqlSelect) {
1315  SqlSelect select = (SqlSelect) query;
1316  SqlNodeList selectList = select.getSelectList();
1317  SqlNodeList groupList = select.getGroup();
1318 
1319  if ((selectList.size() == 1) && ((groupList == null) || (groupList.size() == 0))) {
1320  SqlNode selectExpr = selectList.get(0);
1321  if (selectExpr instanceof SqlCall) {
1322  SqlCall selectExprCall = (SqlCall) selectExpr;
1323  if (Util.isSingleValue(selectExprCall)) {
1324  return plan;
1325  }
1326  }
1327 
1328  // If there is a limit with 0 or 1,
1329  // it is ensured to produce a single value
1330  if (select.getFetch() != null && select.getFetch() instanceof SqlNumericLiteral) {
1331  SqlNumericLiteral limitNum = (SqlNumericLiteral) select.getFetch();
1332  if (((BigDecimal) limitNum.getValue()).intValue() < 2) {
1333  return plan;
1334  }
1335  }
1336  }
1337  } else if (query instanceof SqlCall) {
1338  // If the query is (values ...),
1339  // it is necessary to look into the operands to determine
1340  // whether SingleValueAgg is necessary
1341  SqlCall exprCall = (SqlCall) query;
1342  if (exprCall.getOperator() instanceof SqlValuesOperator
1343  && Util.isSingleValue(exprCall)) {
1344  return plan;
1345  }
1346  }
1347 
1348  // If not, project SingleValueAgg
1349  return RelOptUtil.createSingleValueAggRel(cluster, plan);
1350  }
1351 
1360  private RexNode convertInToOr(final Blackboard bb,
1361  final List<RexNode> leftKeys,
1362  SqlNodeList valuesList,
1363  SqlInOperator op) {
1364  final List<RexNode> comparisons = new ArrayList<>();
1365  for (SqlNode rightVals : valuesList) {
1366  RexNode rexComparison;
1367  final SqlOperator comparisonOp;
1368  if (op instanceof SqlQuantifyOperator) {
1369  comparisonOp = RelOptUtil.op(
1370  ((SqlQuantifyOperator) op).comparisonKind, SqlStdOperatorTable.EQUALS);
1371  } else {
1372  comparisonOp = SqlStdOperatorTable.EQUALS;
1373  }
1374  if (leftKeys.size() == 1) {
1375  rexComparison = rexBuilder.makeCall(comparisonOp,
1376  leftKeys.get(0),
1377  ensureSqlType(
1378  leftKeys.get(0).getType(), bb.convertExpression(rightVals)));
1379  } else {
1380  assert rightVals instanceof SqlCall;
1381  final SqlBasicCall call = (SqlBasicCall) rightVals;
1382  assert (call.getOperator() instanceof SqlRowOperator)
1383  && call.operandCount() == leftKeys.size();
1384  rexComparison = RexUtil.composeConjunction(rexBuilder,
1385  Iterables.transform(Pair.zip(leftKeys, call.getOperandList()),
1386  pair
1387  -> rexBuilder.makeCall(comparisonOp,
1388  pair.left,
1389  ensureSqlType(pair.left.getType(),
1390  bb.convertExpression(pair.right)))));
1391  }
1392  comparisons.add(rexComparison);
1393  }
1394 
1395  switch (op.kind) {
1396  case ALL:
1397  return RexUtil.composeConjunction(rexBuilder, comparisons, true);
1398  case NOT_IN:
1399  return rexBuilder.makeCall(SqlStdOperatorTable.NOT,
1400  RexUtil.composeDisjunction(rexBuilder, comparisons, true));
1401  case IN:
1402  case SOME:
1403  return RexUtil.composeDisjunction(rexBuilder, comparisons, true);
1404  default:
1405  throw new AssertionError();
1406  }
1407  }
1408 
1414  private RexNode ensureSqlType(RelDataType type, RexNode node) {
1415  if (type.getSqlTypeName() == node.getType().getSqlTypeName()
1416  || (type.getSqlTypeName() == SqlTypeName.VARCHAR
1417  && node.getType().getSqlTypeName() == SqlTypeName.CHAR)) {
1418  return node;
1419  }
1420  return rexBuilder.ensureType(type, node, true);
1421  }
1422 
1433  @Deprecated // to be removed before 2.0
1434  protected int getInSubqueryThreshold() {
1435  return config.getInSubQueryThreshold();
1436  }
1437 
1454  private RelOptUtil.Exists convertExists(SqlNode seek,
1455  RelOptUtil.SubQueryType subQueryType,
1456  RelOptUtil.Logic logic,
1457  boolean notIn,
1458  RelDataType targetDataType) {
1459  final SqlValidatorScope seekScope = (seek instanceof SqlSelect)
1460  ? validator.getSelectScope((SqlSelect) seek)
1461  : null;
1462  final Blackboard seekBb = createBlackboard(seekScope, null, false);
1463  RelNode seekRel = convertQueryOrInList(seekBb, seek, targetDataType);
1464 
1465  return RelOptUtil.createExistsPlan(seekRel, subQueryType, logic, notIn, relBuilder);
1466  }
1467 
1468  private RelNode convertQueryOrInList(
1469  Blackboard bb, SqlNode seek, RelDataType targetRowType) {
1470  // NOTE: Once we start accepting single-row queries as row constructors,
1471  // there will be an ambiguity here for a case like X IN ((SELECT Y FROM
1472  // Z)). The SQL standard resolves the ambiguity by saying that a lone
1473  // select should be interpreted as a table expression, not a row
1474  // expression. The semantic difference is that a table expression can
1475  // return multiple rows.
1476  if (seek instanceof SqlNodeList) {
1477  return convertRowValues(
1478  bb, seek, ((SqlNodeList) seek).getList(), false, targetRowType);
1479  } else {
1480  return convertQueryRecursive(seek, false, null).project();
1481  }
1482  }
1483 
1484  private RelNode convertRowValues(Blackboard bb,
1485  SqlNode rowList,
1486  Collection<SqlNode> rows,
1487  boolean allowLiteralsOnly,
1488  RelDataType targetRowType) {
1489  // NOTE jvs 30-Apr-2006: We combine all rows consisting entirely of
1490  // literals into a single LogicalValues; this gives the optimizer a smaller
1491  // input tree. For everything else (computed expressions, row
1492  // sub-queries), we union each row in as a projection on top of a
1493  // LogicalOneRow.
1494 
1495  final ImmutableList.Builder<ImmutableList<RexLiteral>> tupleList =
1496  ImmutableList.builder();
1497  final RelDataType rowType;
1498  if (targetRowType != null) {
1499  rowType = targetRowType;
1500  } else {
1501  rowType = SqlTypeUtil.promoteToRowType(
1502  typeFactory, validator.getValidatedNodeType(rowList), null);
1503  }
1504 
1505  final List<RelNode> unionInputs = new ArrayList<>();
1506  for (SqlNode node : rows) {
1507  SqlBasicCall call;
1508  if (isRowConstructor(node)) {
1509  call = (SqlBasicCall) node;
1510  ImmutableList.Builder<RexLiteral> tuple = ImmutableList.builder();
1511  for (Ord<SqlNode> operand : Ord.zip(call.operands)) {
1512  RexLiteral rexLiteral =
1513  convertLiteralInValuesList(operand.e, bb, rowType, operand.i);
1514  if ((rexLiteral == null) && allowLiteralsOnly) {
1515  return null;
1516  }
1517  if ((rexLiteral == null) || !config.isCreateValuesRel()) {
1518  // fallback to convertRowConstructor
1519  tuple = null;
1520  break;
1521  }
1522  tuple.add(rexLiteral);
1523  }
1524  if (tuple != null) {
1525  tupleList.add(tuple.build());
1526  continue;
1527  }
1528  } else {
1529  RexLiteral rexLiteral = convertLiteralInValuesList(node, bb, rowType, 0);
1530  if ((rexLiteral != null) && config.isCreateValuesRel()) {
1531  tupleList.add(ImmutableList.of(rexLiteral));
1532  continue;
1533  } else {
1534  if ((rexLiteral == null) && allowLiteralsOnly) {
1535  return null;
1536  }
1537  }
1538 
1539  // convert "1" to "row(1)"
1540  call = (SqlBasicCall) SqlStdOperatorTable.ROW.createCall(SqlParserPos.ZERO, node);
1541  }
1542  unionInputs.add(convertRowConstructor(bb, call));
1543  }
1544  LogicalValues values = LogicalValues.create(cluster, rowType, tupleList.build());
1545  RelNode resultRel;
1546  if (unionInputs.isEmpty()) {
1547  resultRel = values;
1548  } else {
1549  if (!values.getTuples().isEmpty()) {
1550  unionInputs.add(values);
1551  }
1552  resultRel = LogicalUnion.create(unionInputs, true);
1553  }
1554  leaves.add(resultRel);
1555  return resultRel;
1556  }
1557 
1558  private RexLiteral convertLiteralInValuesList(
1559  SqlNode sqlNode, Blackboard bb, RelDataType rowType, int iField) {
1560  if (!(sqlNode instanceof SqlLiteral)) {
1561  return null;
1562  }
1563  RelDataTypeField field = rowType.getFieldList().get(iField);
1564  RelDataType type = field.getType();
1565  if (type.isStruct()) {
1566  // null literals for weird stuff like UDT's need
1567  // special handling during type flattening, so
1568  // don't use LogicalValues for those
1569  return null;
1570  }
1571 
1572  RexNode literalExpr = exprConverter.convertLiteral(bb, (SqlLiteral) sqlNode);
1573 
1574  if (!(literalExpr instanceof RexLiteral)) {
1575  assert literalExpr.isA(SqlKind.CAST);
1576  RexNode child = ((RexCall) literalExpr).getOperands().get(0);
1577  assert RexLiteral.isNullLiteral(child);
1578 
1579  // NOTE jvs 22-Nov-2006: we preserve type info
1580  // in LogicalValues digest, so it's OK to lose it here
1581  return (RexLiteral) child;
1582  }
1583 
1584  RexLiteral literal = (RexLiteral) literalExpr;
1585 
1586  Comparable value = literal.getValue();
1587 
1588  if (SqlTypeUtil.isExactNumeric(type) && SqlTypeUtil.hasScale(type)) {
1589  BigDecimal roundedValue =
1590  NumberUtil.rescaleBigDecimal((BigDecimal) value, type.getScale());
1591  return rexBuilder.makeExactLiteral(roundedValue, type);
1592  }
1593 
1594  if ((value instanceof NlsString) && (type.getSqlTypeName() == SqlTypeName.CHAR)) {
1595  // pad fixed character type
1596  NlsString unpadded = (NlsString) value;
1597  return rexBuilder.makeCharLiteral(
1598  new NlsString(Spaces.padRight(unpadded.getValue(), type.getPrecision()),
1599  unpadded.getCharsetName(),
1600  unpadded.getCollation()));
1601  }
1602  return literal;
1603  }
1604 
1605  private boolean isRowConstructor(SqlNode node) {
1606  if (!(node.getKind() == SqlKind.ROW)) {
1607  return false;
1608  }
1609  SqlCall call = (SqlCall) node;
1610  return call.getOperator().getName().equalsIgnoreCase("row");
1611  }
1612 
1627  private void findSubQueries(Blackboard bb,
1628  SqlNode node,
1629  RelOptUtil.Logic logic,
1630  boolean registerOnlyScalarSubQueries) {
1631  final SqlKind kind = node.getKind();
1632  switch (kind) {
1633  case EXISTS:
1634  case SELECT:
1635  case MULTISET_QUERY_CONSTRUCTOR:
1636  case MULTISET_VALUE_CONSTRUCTOR:
1637  case ARRAY_QUERY_CONSTRUCTOR:
1638  case CURSOR:
1639  case SCALAR_QUERY:
1640  if (!registerOnlyScalarSubQueries || (kind == SqlKind.SCALAR_QUERY)) {
1641  bb.registerSubQuery(node, RelOptUtil.Logic.TRUE_FALSE);
1642  }
1643  return;
1644  case IN:
1645  break;
1646  case NOT_IN:
1647  case NOT:
1648  logic = logic.negate();
1649  break;
1650  }
1651  if (node instanceof SqlCall) {
1652  switch (kind) {
1653  // Do no change logic for AND, IN and NOT IN expressions;
1654  // but do change logic for OR, NOT and others;
1655  // EXISTS was handled already.
1656  case AND:
1657  case IN:
1658  case NOT_IN:
1659  break;
1660  default:
1661  logic = RelOptUtil.Logic.TRUE_FALSE_UNKNOWN;
1662  break;
1663  }
1664  for (SqlNode operand : ((SqlCall) node).getOperandList()) {
1665  if (operand != null) {
1666  // In the case of an IN expression, locate scalar
1667  // sub-queries so we can convert them to constants
1668  findSubQueries(bb,
1669  operand,
1670  logic,
1671  kind == SqlKind.IN || kind == SqlKind.NOT_IN || kind == SqlKind.SOME
1672  || kind == SqlKind.ALL || registerOnlyScalarSubQueries);
1673  }
1674  }
1675  } else if (node instanceof SqlNodeList) {
1676  for (SqlNode child : (SqlNodeList) node) {
1677  findSubQueries(bb,
1678  child,
1679  logic,
1680  kind == SqlKind.IN || kind == SqlKind.NOT_IN || kind == SqlKind.SOME
1681  || kind == SqlKind.ALL || registerOnlyScalarSubQueries);
1682  }
1683  }
1684 
1685  // Now that we've located any scalar sub-queries inside the IN
1686  // expression, register the IN expression itself. We need to
1687  // register the scalar sub-queries first so they can be converted
1688  // before the IN expression is converted.
1689  switch (kind) {
1690  case IN:
1691  case NOT_IN:
1692  case SOME:
1693  case ALL:
1694  switch (logic) {
1695  case TRUE_FALSE_UNKNOWN:
1696  if (validator.getValidatedNodeType(node).isNullable()) {
1697  break;
1698  } else if (true) {
1699  break;
1700  }
1701  // fall through
1702  case UNKNOWN_AS_FALSE:
1703  logic = RelOptUtil.Logic.TRUE;
1704  }
1705  bb.registerSubQuery(node, logic);
1706  break;
1707  }
1708  }
1709 
1716  public RexNode convertExpression(SqlNode node) {
1717  Map<String, RelDataType> nameToTypeMap = Collections.emptyMap();
1718  final ParameterScope scope =
1719  new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
1720  final Blackboard bb = createBlackboard(scope, null, false);
1721  return bb.convertExpression(node);
1722  }
1723 
1735  public RexNode convertExpression(SqlNode node, Map<String, RexNode> nameToNodeMap) {
1736  final Map<String, RelDataType> nameToTypeMap = new HashMap<>();
1737  for (Map.Entry<String, RexNode> entry : nameToNodeMap.entrySet()) {
1738  nameToTypeMap.put(entry.getKey(), entry.getValue().getType());
1739  }
1740  final ParameterScope scope =
1741  new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
1742  final Blackboard bb = createBlackboard(scope, nameToNodeMap, false);
1743  return bb.convertExpression(node);
1744  }
1745 
1757  protected RexNode convertExtendedExpression(SqlNode node, Blackboard bb) {
1758  return null;
1759  }
1760 
1761  private RexNode convertOver(Blackboard bb, SqlNode node) {
1762  SqlCall call = (SqlCall) node;
1763  SqlCall aggCall = call.operand(0);
1764  boolean ignoreNulls = false;
1765  switch (aggCall.getKind()) {
1766  case IGNORE_NULLS:
1767  ignoreNulls = true;
1768  // fall through
1769  case RESPECT_NULLS:
1770  aggCall = aggCall.operand(0);
1771  }
1772 
1773  SqlNode windowOrRef = call.operand(1);
1774  final SqlWindow window = validator.resolveWindow(windowOrRef, bb.scope, true);
1775 
1776  // ROW_NUMBER() expects specific kind of framing.
1777  if (aggCall.getKind() == SqlKind.ROW_NUMBER) {
1778  window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
1779  window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
1780  window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));
1781  }
1782  final SqlNodeList partitionList = window.getPartitionList();
1783  final ImmutableList.Builder<RexNode> partitionKeys = ImmutableList.builder();
1784  for (SqlNode partition : partitionList) {
1785  partitionKeys.add(bb.convertExpression(partition));
1786  }
1787  RexNode lowerBound = bb.convertExpression(window.getLowerBound());
1788  RexNode upperBound = bb.convertExpression(window.getUpperBound());
1789  SqlNodeList orderList = window.getOrderList();
1790  if ((orderList.size() == 0) && !window.isRows()) {
1791  // A logical range requires an ORDER BY clause. Use the implicit
1792  // ordering of this relation. There must be one, otherwise it would
1793  // have failed validation.
1794  orderList = bb.scope.getOrderList();
1795  if (orderList == null) {
1796  throw new AssertionError("Relation should have sort key for implicit ORDER BY");
1797  }
1798  }
1799 
1800  final ImmutableList.Builder<RexFieldCollation> orderKeys = ImmutableList.builder();
1801  for (SqlNode order : orderList) {
1802  orderKeys.add(bb.convertSortExpression(order,
1803  RelFieldCollation.Direction.ASCENDING,
1804  RelFieldCollation.NullDirection.UNSPECIFIED));
1805  }
1806 
1807  try {
1808  Preconditions.checkArgument(bb.window == null, "already in window agg mode");
1809  bb.window = window;
1810  RexNode rexAgg = exprConverter.convertCall(bb, aggCall);
1811  rexAgg = rexBuilder.ensureType(validator.getValidatedNodeType(call), rexAgg, false);
1812 
1813  // Walk over the tree and apply 'over' to all agg functions. This is
1814  // necessary because the returned expression is not necessarily a call
1815  // to an agg function. For example, AVG(x) becomes SUM(x) / COUNT(x).
1816 
1817  final SqlLiteral q = aggCall.getFunctionQuantifier();
1818  final boolean isDistinct = q != null && q.getValue() == SqlSelectKeyword.DISTINCT;
1819 
1820  final RexShuttle visitor = new HistogramShuttle(partitionKeys.build(),
1821  orderKeys.build(),
1822  RexWindowBound.create(window.getLowerBound(), lowerBound),
1823  RexWindowBound.create(window.getUpperBound(), upperBound),
1824  window,
1825  isDistinct,
1826  ignoreNulls);
1827  RexNode overNode = rexAgg.accept(visitor);
1828 
1829  return overNode;
1830  } finally {
1831  bb.window = null;
1832  }
1833  }
1834 
1852  protected void convertFrom(Blackboard bb, SqlNode from) {
1853  if (from == null) {
1854  bb.setRoot(LogicalValues.createOneRow(cluster), false);
1855  return;
1856  }
1857 
1858  final SqlCall call;
1859  final SqlNode[] operands;
1860  switch (from.getKind()) {
1861  case MATCH_RECOGNIZE:
1862  convertMatchRecognize(bb, (SqlCall) from);
1863  return;
1864 
1865  case AS:
1866  call = (SqlCall) from;
1867  convertFrom(bb, call.operand(0));
1868  if (call.operandCount() > 2
1869  && (bb.root instanceof Values || bb.root instanceof Uncollect)) {
1870  final List<String> fieldNames = new ArrayList<>();
1871  for (SqlNode node : Util.skip(call.getOperandList(), 2)) {
1872  fieldNames.add(((SqlIdentifier) node).getSimple());
1873  }
1874  bb.setRoot(relBuilder.push(bb.root).rename(fieldNames).build(), true);
1875  }
1876  return;
1877 
1878  case WITH_ITEM:
1879  convertFrom(bb, ((SqlWithItem) from).query);
1880  return;
1881 
1882  case WITH:
1883  convertFrom(bb, ((SqlWith) from).body);
1884  return;
1885 
1886  case TABLESAMPLE:
1887  operands = ((SqlBasicCall) from).getOperands();
1888  SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands[1]);
1889  if (sampleSpec instanceof SqlSampleSpec.SqlSubstitutionSampleSpec) {
1890  String sampleName =
1891  ((SqlSampleSpec.SqlSubstitutionSampleSpec) sampleSpec).getName();
1892  datasetStack.push(sampleName);
1893  convertFrom(bb, operands[0]);
1894  datasetStack.pop();
1895  } else if (sampleSpec instanceof SqlSampleSpec.SqlTableSampleSpec) {
1896  SqlSampleSpec.SqlTableSampleSpec tableSampleSpec =
1897  (SqlSampleSpec.SqlTableSampleSpec) sampleSpec;
1898  convertFrom(bb, operands[0]);
1899  RelOptSamplingParameters params =
1900  new RelOptSamplingParameters(tableSampleSpec.isBernoulli(),
1901  tableSampleSpec.getSamplePercentage(),
1902  tableSampleSpec.isRepeatable(),
1903  tableSampleSpec.getRepeatableSeed());
1904  bb.setRoot(new Sample(cluster, bb.root, params), false);
1905  } else {
1906  throw new AssertionError("unknown TABLESAMPLE type: " + sampleSpec);
1907  }
1908  return;
1909 
1910  case IDENTIFIER:
1911  convertIdentifier(bb, (SqlIdentifier) from, null);
1912  return;
1913 
1914  case EXTEND:
1915  call = (SqlCall) from;
1916  SqlIdentifier id = (SqlIdentifier) call.getOperandList().get(0);
1917  SqlNodeList extendedColumns = (SqlNodeList) call.getOperandList().get(1);
1918  convertIdentifier(bb, id, extendedColumns);
1919  return;
1920 
1921  case SNAPSHOT:
1922  snapshotTemporalTable(bb, (SqlCall) from);
1923  return;
1924 
1925  case JOIN:
1926  final SqlJoin join = (SqlJoin) from;
1927  final SqlValidatorScope scope = validator.getJoinScope(from);
1928  final Blackboard fromBlackboard = createBlackboard(scope, null, false);
1929  SqlNode left = join.getLeft();
1930  SqlNode right = join.getRight();
1931  final boolean isNatural = join.isNatural();
1932  final JoinType joinType = join.getJoinType();
1933  final SqlValidatorScope leftScope = Util.first(
1934  validator.getJoinScope(left), ((DelegatingScope) bb.scope).getParent());
1935  final Blackboard leftBlackboard = createBlackboard(leftScope, null, false);
1936  final SqlValidatorScope rightScope = Util.first(
1937  validator.getJoinScope(right), ((DelegatingScope) bb.scope).getParent());
1938  final Blackboard rightBlackboard = createBlackboard(rightScope, null, false);
1939  convertFrom(leftBlackboard, left);
1940  RelNode leftRel = leftBlackboard.root;
1941  convertFrom(rightBlackboard, right);
1942  RelNode rightRel = rightBlackboard.root;
1943  JoinRelType convertedJoinType = convertJoinType(joinType);
1944  RexNode conditionExp;
1945  final SqlValidatorNamespace leftNamespace = validator.getNamespace(left);
1946  final SqlValidatorNamespace rightNamespace = validator.getNamespace(right);
1947  if (isNatural) {
1948  final RelDataType leftRowType = leftNamespace.getRowType();
1949  final RelDataType rightRowType = rightNamespace.getRowType();
1950  final List<String> columnList = SqlValidatorUtil.deriveNaturalJoinColumnList(
1951  catalogReader.nameMatcher(), leftRowType, rightRowType);
1952  conditionExp = convertUsing(leftNamespace, rightNamespace, columnList);
1953  } else {
1954  conditionExp = convertJoinCondition(fromBlackboard,
1955  leftNamespace,
1956  rightNamespace,
1957  join.getCondition(),
1958  join.getConditionType(),
1959  leftRel,
1960  rightRel);
1961  }
1962 
1963  final RelNode joinRel = createJoin(
1964  fromBlackboard, leftRel, rightRel, conditionExp, convertedJoinType);
1965  bb.setRoot(joinRel, false);
1966  return;
1967 
1968  case SELECT:
1969  case INTERSECT:
1970  case EXCEPT:
1971  case UNION:
1972  final RelNode rel = convertQueryRecursive(from, false, null).project();
1973  bb.setRoot(rel, true);
1974  return;
1975 
1976  case VALUES:
1977  convertValuesImpl(bb, (SqlCall) from, null);
1978  return;
1979 
1980  case UNNEST:
1981  call = (SqlCall) from;
1982  final List<SqlNode> nodes = call.getOperandList();
1983  final SqlUnnestOperator operator = (SqlUnnestOperator) call.getOperator();
1984  for (SqlNode node : nodes) {
1985  replaceSubQueries(bb, node, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
1986  }
1987  final List<RexNode> exprs = new ArrayList<>();
1988  final List<String> fieldNames = new ArrayList<>();
1989  for (Ord<SqlNode> node : Ord.zip(nodes)) {
1990  exprs.add(bb.convertExpression(node.e));
1991  fieldNames.add(validator.deriveAlias(node.e, node.i));
1992  }
1993  RelNode child = (null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster);
1994  relBuilder.push(child).projectNamed(exprs, fieldNames, false);
1995 
1996  Uncollect uncollect = new Uncollect(cluster,
1997  cluster.traitSetOf(Convention.NONE),
1998  relBuilder.build(),
1999  operator.withOrdinality);
2000  bb.setRoot(uncollect, true);
2001  return;
2002 
2003  case COLLECTION_TABLE:
2004  call = (SqlCall) from;
2005 
2006  // Dig out real call; TABLE() wrapper is just syntactic.
2007  assert call.getOperandList().size() == 1;
2008  final SqlCall call2 = call.operand(0);
2009  convertCollectionTable(bb, call2);
2010  return;
2011 
2012  default:
2013  throw new AssertionError("not a join operator " + from);
2014  }
2015  }
2016 
2017  protected void convertMatchRecognize(Blackboard bb, SqlCall call) {
2018  final SqlMatchRecognize matchRecognize = (SqlMatchRecognize) call;
2019  final SqlValidatorNamespace ns = validator.getNamespace(matchRecognize);
2020  final SqlValidatorScope scope = validator.getMatchRecognizeScope(matchRecognize);
2021 
2022  final Blackboard matchBb = createBlackboard(scope, null, false);
2023  final RelDataType rowType = ns.getRowType();
2024  // convert inner query, could be a table name or a derived table
2025  SqlNode expr = matchRecognize.getTableRef();
2026  convertFrom(matchBb, expr);
2027  final RelNode input = matchBb.root;
2028 
2029  // PARTITION BY
2030  final SqlNodeList partitionList = matchRecognize.getPartitionList();
2031  final List<RexNode> partitionKeys = new ArrayList<>();
2032  for (SqlNode partition : partitionList) {
2033  RexNode e = matchBb.convertExpression(partition);
2034  partitionKeys.add(e);
2035  }
2036 
2037  // ORDER BY
2038  final SqlNodeList orderList = matchRecognize.getOrderList();
2039  final List<RelFieldCollation> orderKeys = new ArrayList<>();
2040  for (SqlNode order : orderList) {
2041  final RelFieldCollation.Direction direction;
2042  switch (order.getKind()) {
2043  case DESCENDING:
2044  direction = RelFieldCollation.Direction.DESCENDING;
2045  order = ((SqlCall) order).operand(0);
2046  break;
2047  case NULLS_FIRST:
2048  case NULLS_LAST:
2049  throw new AssertionError();
2050  default:
2051  direction = RelFieldCollation.Direction.ASCENDING;
2052  break;
2053  }
2054  final RelFieldCollation.NullDirection nullDirection =
2055  validator.getDefaultNullCollation().last(desc(direction))
2056  ? RelFieldCollation.NullDirection.LAST
2057  : RelFieldCollation.NullDirection.FIRST;
2058  RexNode e = matchBb.convertExpression(order);
2059  orderKeys.add(new RelFieldCollation(
2060  ((RexInputRef) e).getIndex(), direction, nullDirection));
2061  }
2062  final RelCollation orders = cluster.traitSet().canonize(RelCollations.of(orderKeys));
2063 
2064  // convert pattern
2065  final Set<String> patternVarsSet = new HashSet<>();
2066  SqlNode pattern = matchRecognize.getPattern();
2067  final SqlBasicVisitor<RexNode> patternVarVisitor = new SqlBasicVisitor<RexNode>() {
2068  @Override
2069  public RexNode visit(SqlCall call) {
2070  List<SqlNode> operands = call.getOperandList();
2071  List<RexNode> newOperands = new ArrayList<>();
2072  for (SqlNode node : operands) {
2073  newOperands.add(node.accept(this));
2074  }
2075  return rexBuilder.makeCall(
2076  validator.getUnknownType(), call.getOperator(), newOperands);
2077  }
2078 
2079  @Override
2080  public RexNode visit(SqlIdentifier id) {
2081  assert id.isSimple();
2082  patternVarsSet.add(id.getSimple());
2083  return rexBuilder.makeLiteral(id.getSimple());
2084  }
2085 
2086  @Override
2087  public RexNode visit(SqlLiteral literal) {
2088  if (literal instanceof SqlNumericLiteral) {
2089  return rexBuilder.makeExactLiteral(BigDecimal.valueOf(literal.intValue(true)));
2090  } else {
2091  return rexBuilder.makeLiteral(literal.booleanValue());
2092  }
2093  }
2094  };
2095  final RexNode patternNode = pattern.accept(patternVarVisitor);
2096 
2097  SqlLiteral interval = matchRecognize.getInterval();
2098  RexNode intervalNode = null;
2099  if (interval != null) {
2100  intervalNode = matchBb.convertLiteral(interval);
2101  }
2102 
2103  // convert subset
2104  final SqlNodeList subsets = matchRecognize.getSubsetList();
2105  final Map<String, TreeSet<String>> subsetMap = new HashMap<>();
2106  for (SqlNode node : subsets) {
2107  List<SqlNode> operands = ((SqlCall) node).getOperandList();
2108  SqlIdentifier left = (SqlIdentifier) operands.get(0);
2109  patternVarsSet.add(left.getSimple());
2110  SqlNodeList rights = (SqlNodeList) operands.get(1);
2111  final TreeSet<String> list = new TreeSet<>();
2112  for (SqlNode right : rights) {
2113  assert right instanceof SqlIdentifier;
2114  list.add(((SqlIdentifier) right).getSimple());
2115  }
2116  subsetMap.put(left.getSimple(), list);
2117  }
2118 
2119  SqlNode afterMatch = matchRecognize.getAfter();
2120  if (afterMatch == null) {
2121  afterMatch =
2122  SqlMatchRecognize.AfterOption.SKIP_TO_NEXT_ROW.symbol(SqlParserPos.ZERO);
2123  }
2124 
2125  final RexNode after;
2126  if (afterMatch instanceof SqlCall) {
2127  List<SqlNode> operands = ((SqlCall) afterMatch).getOperandList();
2128  SqlOperator operator = ((SqlCall) afterMatch).getOperator();
2129  assert operands.size() == 1;
2130  SqlIdentifier id = (SqlIdentifier) operands.get(0);
2131  assert patternVarsSet.contains(id.getSimple())
2132  : id.getSimple()
2133  + " not defined in pattern";
2134  RexNode rex = rexBuilder.makeLiteral(id.getSimple());
2135  after = rexBuilder.makeCall(
2136  validator.getUnknownType(), operator, ImmutableList.of(rex));
2137  } else {
2138  after = matchBb.convertExpression(afterMatch);
2139  }
2140 
2141  matchBb.setPatternVarRef(true);
2142 
2143  // convert measures
2144  final ImmutableMap.Builder<String, RexNode> measureNodes = ImmutableMap.builder();
2145  for (SqlNode measure : matchRecognize.getMeasureList()) {
2146  List<SqlNode> operands = ((SqlCall) measure).getOperandList();
2147  String alias = ((SqlIdentifier) operands.get(1)).getSimple();
2148  RexNode rex = matchBb.convertExpression(operands.get(0));
2149  measureNodes.put(alias, rex);
2150  }
2151 
2152  // convert definitions
2153  final ImmutableMap.Builder<String, RexNode> definitionNodes = ImmutableMap.builder();
2154  for (SqlNode def : matchRecognize.getPatternDefList()) {
2155  replaceSubQueries(matchBb, def, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
2156  List<SqlNode> operands = ((SqlCall) def).getOperandList();
2157  String alias = ((SqlIdentifier) operands.get(1)).getSimple();
2158  RexNode rex = matchBb.convertExpression(operands.get(0));
2159  definitionNodes.put(alias, rex);
2160  }
2161 
2162  final SqlLiteral rowsPerMatch = matchRecognize.getRowsPerMatch();
2163  final boolean allRows = rowsPerMatch != null
2164  && rowsPerMatch.getValue() == SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS;
2165 
2166  matchBb.setPatternVarRef(false);
2167 
2168  final RelFactories.MatchFactory factory = RelFactories.DEFAULT_MATCH_FACTORY;
2169  final RelNode rel = factory.createMatch(input,
2170  patternNode,
2171  rowType,
2172  matchRecognize.getStrictStart().booleanValue(),
2173  matchRecognize.getStrictEnd().booleanValue(),
2174  definitionNodes.build(),
2175  measureNodes.build(),
2176  after,
2177  subsetMap,
2178  allRows,
2179  partitionKeys,
2180  orders,
2181  intervalNode);
2182  bb.setRoot(rel, false);
2183  }
2184 
2185  private void convertIdentifier(
2186  Blackboard bb, SqlIdentifier id, SqlNodeList extendedColumns) {
2187  final SqlValidatorNamespace fromNamespace = validator.getNamespace(id).resolve();
2188  if (fromNamespace.getNode() != null) {
2189  convertFrom(bb, fromNamespace.getNode());
2190  return;
2191  }
2192  final String datasetName = datasetStack.isEmpty() ? null : datasetStack.peek();
2193  final boolean[] usedDataset = {false};
2194  RelOptTable table = SqlValidatorUtil.getRelOptTable(
2195  fromNamespace, catalogReader, datasetName, usedDataset);
2196  if (extendedColumns != null && extendedColumns.size() > 0) {
2197  assert table != null;
2198  final SqlValidatorTable validatorTable = table.unwrap(SqlValidatorTable.class);
2199  final List<RelDataTypeField> extendedFields = SqlValidatorUtil.getExtendedColumns(
2200  validator.getTypeFactory(), validatorTable, extendedColumns);
2201  table = table.extend(extendedFields);
2202  }
2203  final RelNode tableRel;
2204  if (config.isConvertTableAccess()) {
2205  tableRel = toRel(table);
2206  } else {
2207  tableRel = LogicalTableScan.create(cluster, table);
2208  }
2209  bb.setRoot(tableRel, true);
2210  if (usedDataset[0]) {
2211  bb.setDataset(datasetName);
2212  }
2213  }
2214 
2215  protected void convertCollectionTable(Blackboard bb, SqlCall call) {
2216  final SqlOperator operator = call.getOperator();
2217  if (operator == SqlStdOperatorTable.TABLESAMPLE) {
2218  final String sampleName =
2219  SqlLiteral.unchain(call.operand(0)).getValueAs(String.class);
2220  datasetStack.push(sampleName);
2221  SqlCall cursorCall = call.operand(1);
2222  SqlNode query = cursorCall.operand(0);
2223  RelNode converted = convertQuery(query, false, false).rel;
2224  bb.setRoot(converted, false);
2225  datasetStack.pop();
2226  return;
2227  }
2228  replaceSubQueries(bb, call, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2229 
2230  // Expand table macro if possible. It's more efficient than
2231  // LogicalTableFunctionScan.
2232  final SqlCallBinding callBinding =
2233  new SqlCallBinding(bb.scope.getValidator(), bb.scope, call);
2234  if (operator instanceof SqlUserDefinedTableMacro) {
2235  final SqlUserDefinedTableMacro udf = (SqlUserDefinedTableMacro) operator;
2236  final TranslatableTable table = udf.getTable(typeFactory, callBinding.operands());
2237  final RelDataType rowType = table.getRowType(typeFactory);
2238  RelOptTable relOptTable =
2239  RelOptTableImpl.create(null, rowType, table, udf.getNameAsId().names);
2240  RelNode converted = toRel(relOptTable);
2241  bb.setRoot(converted, true);
2242  return;
2243  }
2244 
2245  Type elementType;
2246  if (operator instanceof SqlUserDefinedTableFunction) {
2247  SqlUserDefinedTableFunction udtf = (SqlUserDefinedTableFunction) operator;
2248  elementType = udtf.getElementType(typeFactory, callBinding.operands());
2249  } else {
2250  elementType = null;
2251  }
2252 
2253  RexNode rexCall = bb.convertExpression(call);
2254  final List<RelNode> inputs = bb.retrieveCursors();
2255  Set<RelColumnMapping> columnMappings = getColumnMappings(operator);
2256  LogicalTableFunctionScan callRel = LogicalTableFunctionScan.create(cluster,
2257  inputs,
2258  rexCall,
2259  elementType,
2260  validator.getValidatedNodeType(call),
2261  columnMappings);
2262  bb.setRoot(callRel, true);
2263  afterTableFunction(bb, call, callRel);
2264  }
2265 
2267  SqlCall call,
2268  LogicalTableFunctionScan callRel) {}
2269 
2270  private void snapshotTemporalTable(Blackboard bb, SqlCall call) {
2271  final SqlSnapshot snapshot = (SqlSnapshot) call;
2272  final RexNode period = bb.convertExpression(snapshot.getPeriod());
2273 
2274  // convert inner query, could be a table name or a derived table
2275  SqlNode expr = snapshot.getTableRef();
2276  convertFrom(bb, expr);
2277  final TableScan scan = (TableScan) bb.root;
2278 
2279  final RelNode snapshotRel = relBuilder.push(scan).snapshot(period).build();
2280 
2281  bb.setRoot(snapshotRel, false);
2282  }
2283 
2284  private Set<RelColumnMapping> getColumnMappings(SqlOperator op) {
2285  SqlReturnTypeInference rti = op.getReturnTypeInference();
2286  if (rti == null) {
2287  return null;
2288  }
2289  if (rti instanceof TableFunctionReturnTypeInference) {
2290  TableFunctionReturnTypeInference tfrti = (TableFunctionReturnTypeInference) rti;
2291  return tfrti.getColumnMappings();
2292  } else {
2293  return null;
2294  }
2295  }
2296 
2303  private static class RexAccessShuttle extends RexShuttle {
2304  private final RexBuilder builder;
2305  private final RexCorrelVariable rexCorrel;
2306  private final BitSet varCols = new BitSet();
2307 
2308  RexAccessShuttle(RexBuilder builder, RexCorrelVariable rexCorrel) {
2309  this.builder = builder;
2310  this.rexCorrel = rexCorrel;
2311  }
2312 
2313  @Override
2314  public RexNode visitInputRef(RexInputRef input) {
2315  int i = input.getIndex() - rexCorrel.getType().getFieldCount();
2316  if (i < 0) {
2317  varCols.set(input.getIndex());
2318  return builder.makeFieldAccess(rexCorrel, input.getIndex());
2319  }
2320  return builder.makeInputRef(input.getType(), i);
2321  }
2322  }
2323 
2324  protected RelNode createJoin(Blackboard bb,
2325  RelNode leftRel,
2326  RelNode rightRel,
2327  RexNode joinCond,
2328  JoinRelType joinType) {
2329  assert joinCond != null;
2330 
2331  final CorrelationUse p = getCorrelationUse(bb, rightRel);
2332  if (p != null) {
2333  RelNode innerRel = p.r;
2334  ImmutableBitSet requiredCols = p.requiredColumns;
2335 
2336  if (!joinCond.isAlwaysTrue()) {
2337  final RelFactories.FilterFactory factory = RelFactories.DEFAULT_FILTER_FACTORY;
2338  final RexCorrelVariable rexCorrel =
2339  (RexCorrelVariable) rexBuilder.makeCorrel(leftRel.getRowType(), p.id);
2340  final RexAccessShuttle shuttle = new RexAccessShuttle(rexBuilder, rexCorrel);
2341 
2342  // Replace outer RexInputRef with RexFieldAccess,
2343  // and push lateral join predicate into inner child
2344  final RexNode newCond = joinCond.accept(shuttle);
2345  innerRel = factory.createFilter(p.r, newCond);
2346  requiredCols =
2347  ImmutableBitSet.fromBitSet(shuttle.varCols).union(p.requiredColumns);
2348  }
2349 
2350  LogicalCorrelate corr =
2351  LogicalCorrelate.create(leftRel, innerRel, p.id, requiredCols, joinType);
2352  return corr;
2353  }
2354 
2355  final Join originalJoin = (Join) RelFactories.DEFAULT_JOIN_FACTORY.createJoin(
2356  leftRel, rightRel, joinCond, ImmutableSet.of(), joinType, false);
2357 
2358  return RelOptUtil.pushDownJoinConditions(originalJoin, relBuilder);
2359  }
2360 
2361  private CorrelationUse getCorrelationUse(Blackboard bb, final RelNode r0) {
2362  final Set<CorrelationId> correlatedVariables = RelOptUtil.getVariablesUsed(r0);
2363  if (correlatedVariables.isEmpty()) {
2364  return null;
2365  }
2366  final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
2367  final List<CorrelationId> correlNames = new ArrayList<>();
2368 
2369  // All correlations must refer the same namespace since correlation
2370  // produces exactly one correlation source.
2371  // The same source might be referenced by different variables since
2372  // DeferredLookups are not de-duplicated at create time.
2373  SqlValidatorNamespace prevNs = null;
2374 
2375  for (CorrelationId correlName : correlatedVariables) {
2376  DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
2377  RexFieldAccess fieldAccess = lookup.getFieldAccess(correlName);
2378  String originalRelName = lookup.getOriginalRelName();
2379  String originalFieldName = fieldAccess.getField().getName();
2380 
2381  final SqlNameMatcher nameMatcher =
2382  bb.getValidator().getCatalogReader().nameMatcher();
2383  final SqlValidatorScope.ResolvedImpl resolved =
2384  new SqlValidatorScope.ResolvedImpl();
2385  lookup.bb.scope.resolve(
2386  ImmutableList.of(originalRelName), nameMatcher, false, resolved);
2387  assert resolved.count() == 1;
2388  final SqlValidatorScope.Resolve resolve = resolved.only();
2389  final SqlValidatorNamespace foundNs = resolve.namespace;
2390  final RelDataType rowType = resolve.rowType();
2391  final int childNamespaceIndex = resolve.path.steps().get(0).i;
2392  final SqlValidatorScope ancestorScope = resolve.scope;
2393  boolean correlInCurrentScope = bb.scope.isWithin(ancestorScope);
2394 
2395  if (!correlInCurrentScope) {
2396  continue;
2397  }
2398 
2399  if (prevNs == null) {
2400  prevNs = foundNs;
2401  } else {
2402  assert prevNs
2403  == foundNs : "All correlation variables should resolve"
2404  + " to the same namespace."
2405  + " Prev ns="
2406  + prevNs
2407  + ", new ns="
2408  + foundNs;
2409  }
2410 
2411  int namespaceOffset = 0;
2412  if (childNamespaceIndex > 0) {
2413  // If not the first child, need to figure out the width
2414  // of output types from all the preceding namespaces
2415  assert ancestorScope instanceof ListScope;
2416  List<SqlValidatorNamespace> children = ((ListScope) ancestorScope).getChildren();
2417 
2418  for (int i = 0; i < childNamespaceIndex; i++) {
2419  SqlValidatorNamespace child = children.get(i);
2420  namespaceOffset += child.getRowType().getFieldCount();
2421  }
2422  }
2423 
2424  RexFieldAccess topLevelFieldAccess = fieldAccess;
2425  while (topLevelFieldAccess.getReferenceExpr() instanceof RexFieldAccess) {
2426  topLevelFieldAccess = (RexFieldAccess) topLevelFieldAccess.getReferenceExpr();
2427  }
2428  final RelDataTypeField field = rowType.getFieldList().get(
2429  topLevelFieldAccess.getField().getIndex() - namespaceOffset);
2430  int pos = namespaceOffset + field.getIndex();
2431 
2432  assert field.getType() == topLevelFieldAccess.getField().getType();
2433 
2434  assert pos != -1;
2435 
2436  if (bb.mapRootRelToFieldProjection.containsKey(bb.root)) {
2437  // bb.root is an aggregate and only projects group by
2438  // keys.
2439  Map<Integer, Integer> exprProjection =
2440  bb.mapRootRelToFieldProjection.get(bb.root);
2441 
2442  // sub-query can reference group by keys projected from
2443  // the root of the outer relation.
2444  if (exprProjection.containsKey(pos)) {
2445  pos = exprProjection.get(pos);
2446  } else {
2447  // correl not grouped
2448  throw new AssertionError("Identifier '" + originalRelName + "."
2449  + originalFieldName + "' is not a group expr");
2450  }
2451  }
2452 
2453  requiredColumns.set(pos);
2454  correlNames.add(correlName);
2455  }
2456 
2457  if (correlNames.isEmpty()) {
2458  // None of the correlating variables originated in this scope.
2459  return null;
2460  }
2461 
2462  RelNode r = r0;
2463  if (correlNames.size() > 1) {
2464  // The same table was referenced more than once.
2465  // So we deduplicate.
2466  r = DeduplicateCorrelateVariables.go(
2467  rexBuilder, correlNames.get(0), Util.skip(correlNames), r0);
2468  // Add new node to leaves.
2469  leaves.add(r);
2470  }
2471  return new CorrelationUse(correlNames.get(0), requiredColumns.build(), r);
2472  }
2473 
2485  private boolean isSubQueryNonCorrelated(RelNode subq, Blackboard bb) {
2486  Set<CorrelationId> correlatedVariables = RelOptUtil.getVariablesUsed(subq);
2487  for (CorrelationId correlName : correlatedVariables) {
2488  DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
2489  String originalRelName = lookup.getOriginalRelName();
2490 
2491  final SqlNameMatcher nameMatcher =
2492  lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
2493  final SqlValidatorScope.ResolvedImpl resolved =
2494  new SqlValidatorScope.ResolvedImpl();
2495  lookup.bb.scope.resolve(
2496  ImmutableList.of(originalRelName), nameMatcher, false, resolved);
2497 
2498  SqlValidatorScope ancestorScope = resolved.only().scope;
2499 
2500  // If the correlated reference is in a scope that's "above" the
2501  // sub-query, then this is a correlated sub-query.
2502  SqlValidatorScope parentScope = bb.scope;
2503  do {
2504  if (ancestorScope == parentScope) {
2505  return false;
2506  }
2507  if (parentScope instanceof DelegatingScope) {
2508  parentScope = ((DelegatingScope) parentScope).getParent();
2509  } else {
2510  break;
2511  }
2512  } while (parentScope != null);
2513  }
2514  return true;
2515  }
2516 
2522  protected List<RelDataTypeField> getSystemFields() {
2523  return Collections.emptyList();
2524  }
2525 
2526  private RexNode convertJoinCondition(Blackboard bb,
2527  SqlValidatorNamespace leftNamespace,
2528  SqlValidatorNamespace rightNamespace,
2529  SqlNode condition,
2530  JoinConditionType conditionType,
2531  RelNode leftRel,
2532  RelNode rightRel) {
2533  if (condition == null) {
2534  return rexBuilder.makeLiteral(true);
2535  }
2536  bb.setRoot(ImmutableList.of(leftRel, rightRel));
2537  replaceSubQueries(bb, condition, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
2538  switch (conditionType) {
2539  case ON:
2540  bb.setRoot(ImmutableList.of(leftRel, rightRel));
2541  return bb.convertExpression(condition);
2542  case USING:
2543  final SqlNodeList list = (SqlNodeList) condition;
2544  final List<String> nameList = new ArrayList<>();
2545  for (SqlNode columnName : list) {
2546  final SqlIdentifier id = (SqlIdentifier) columnName;
2547  String name = id.getSimple();
2548  nameList.add(name);
2549  }
2550  return convertUsing(leftNamespace, rightNamespace, nameList);
2551  default:
2552  throw Util.unexpected(conditionType);
2553  }
2554  }
2555 
2567  private RexNode convertUsing(SqlValidatorNamespace leftNamespace,
2568  SqlValidatorNamespace rightNamespace,
2569  List<String> nameList) {
2570  final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
2571  final List<RexNode> list = new ArrayList<>();
2572  for (String name : nameList) {
2573  List<RexNode> operands = new ArrayList<>();
2574  int offset = 0;
2575  for (SqlValidatorNamespace n : ImmutableList.of(leftNamespace, rightNamespace)) {
2576  final RelDataType rowType = n.getRowType();
2577  final RelDataTypeField field = nameMatcher.field(rowType, name);
2578  operands.add(rexBuilder.makeInputRef(field.getType(), offset + field.getIndex()));
2579  offset += rowType.getFieldList().size();
2580  }
2581  list.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, operands));
2582  }
2583  return RexUtil.composeConjunction(rexBuilder, list);
2584  }
2585 
2586  private static JoinRelType convertJoinType(JoinType joinType) {
2587  switch (joinType) {
2588  case COMMA:
2589  case INNER:
2590  case CROSS:
2591  return JoinRelType.INNER;
2592  case FULL:
2593  return JoinRelType.FULL;
2594  case LEFT:
2595  return JoinRelType.LEFT;
2596  case RIGHT:
2597  return JoinRelType.RIGHT;
2598  default:
2599  throw Util.unexpected(joinType);
2600  }
2601  }
2602 
2615  protected void convertAgg(
2616  Blackboard bb, SqlSelect select, List<SqlNode> orderExprList) {
2617  assert bb.root != null : "precondition: child != null";
2618  SqlNodeList groupList = select.getGroup();
2619  SqlNodeList selectList = select.getSelectList();
2620  SqlNode having = select.getHaving();
2621 
2622  final AggConverter aggConverter = new AggConverter(bb, select);
2623  createAggImpl(bb, aggConverter, selectList, groupList, having, orderExprList);
2624  }
2625 
2626  protected final void createAggImpl(Blackboard bb,
2627  final AggConverter aggConverter,
2628  SqlNodeList selectList,
2629  SqlNodeList groupList,
2630  SqlNode having,
2631  List<SqlNode> orderExprList) {
2632  // Find aggregate functions in SELECT and HAVING clause
2633  final AggregateFinder aggregateFinder = new AggregateFinder();
2634  selectList.accept(aggregateFinder);
2635  if (having != null) {
2636  having.accept(aggregateFinder);
2637  }
2638 
2639  // first replace the sub-queries inside the aggregates
2640  // because they will provide input rows to the aggregates.
2641  replaceSubQueries(bb, aggregateFinder.list, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2642 
2643  // also replace sub-queries inside filters in the aggregates
2645  bb, aggregateFinder.filterList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2646 
2647  // also replace sub-queries inside ordering spec in the aggregates
2648  replaceSubQueries(bb, aggregateFinder.orderList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2649 
2650  // If group-by clause is missing, pretend that it has zero elements.
2651  if (groupList == null) {
2652  groupList = SqlNodeList.EMPTY;
2653  }
2654 
2655  replaceSubQueries(bb, groupList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2656 
2657  // register the group exprs
2658 
2659  // build a map to remember the projections from the top scope to the
2660  // output of the current root.
2661  //
2662  // Calcite allows expressions, not just column references in
2663  // group by list. This is not SQL 2003 compliant, but hey.
2664 
2665  final AggregatingSelectScope scope = aggConverter.aggregatingSelectScope;
2666  final AggregatingSelectScope.Resolved r = scope.resolved.get();
2667  for (SqlNode groupExpr : r.groupExprList) {
2668  aggConverter.addGroupExpr(groupExpr);
2669  }
2670 
2671  final RexNode havingExpr;
2672  final List<Pair<RexNode, String>> projects = new ArrayList<>();
2673 
2674  try {
2675  Preconditions.checkArgument(bb.agg == null, "already in agg mode");
2676  bb.agg = aggConverter;
2677 
2678  // convert the select and having expressions, so that the
2679  // agg converter knows which aggregations are required
2680 
2681  selectList.accept(aggConverter);
2682  // Assert we don't have dangling items left in the stack
2683  assert !aggConverter.inOver;
2684  for (SqlNode expr : orderExprList) {
2685  expr.accept(aggConverter);
2686  assert !aggConverter.inOver;
2687  }
2688  if (having != null) {
2689  having.accept(aggConverter);
2690  assert !aggConverter.inOver;
2691  }
2692 
2693  // compute inputs to the aggregator
2694  List<Pair<RexNode, String>> preExprs = aggConverter.getPreExprs();
2695 
2696  if (preExprs.size() == 0) {
2697  // Special case for COUNT(*), where we can end up with no inputs
2698  // at all. The rest of the system doesn't like 0-tuples, so we
2699  // select a dummy constant here.
2700  final RexNode zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO);
2701  preExprs = ImmutableList.of(Pair.of(zero, (String) null));
2702  }
2703 
2704  final RelNode inputRel = bb.root;
2705 
2706  // Project the expressions required by agg and having.
2707  bb.setRoot(relBuilder.push(inputRel)
2708  .projectNamed(Pair.left(preExprs), Pair.right(preExprs), false)
2709  .build(),
2710  false);
2711  bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
2712 
2713  // REVIEW jvs 31-Oct-2007: doesn't the declaration of
2714  // monotonicity here assume sort-based aggregation at
2715  // the physical level?
2716 
2717  // Tell bb which of group columns are sorted.
2718  bb.columnMonotonicities.clear();
2719  for (SqlNode groupItem : groupList) {
2720  bb.columnMonotonicities.add(bb.scope.getMonotonicity(groupItem));
2721  }
2722 
2723  // Add the aggregator
2724  bb.setRoot(createAggregate(bb, r.groupSet, r.groupSets, aggConverter.getAggCalls()),
2725  false);
2726 
2727  bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
2728 
2729  // Replace sub-queries in having here and modify having to use
2730  // the replaced expressions
2731  if (having != null) {
2732  SqlNode newHaving = pushDownNotForIn(bb.scope, having);
2733  replaceSubQueries(bb, newHaving, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
2734  havingExpr = bb.convertExpression(newHaving);
2735  } else {
2736  havingExpr = relBuilder.literal(true);
2737  }
2738 
2739  // Now convert the other sub-queries in the select list.
2740  // This needs to be done separately from the sub-query inside
2741  // any aggregate in the select list, and after the aggregate rel
2742  // is allocated.
2743  replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
2744 
2745  // Now sub-queries in the entire select list have been converted.
2746  // Convert the select expressions to get the final list to be
2747  // projected.
2748  int k = 0;
2749 
2750  // For select expressions, use the field names previously assigned
2751  // by the validator. If we derive afresh, we might generate names
2752  // like "EXPR$2" that don't match the names generated by the
2753  // validator. This is especially the case when there are system
2754  // fields; system fields appear in the relnode's rowtype but do not
2755  // (yet) appear in the validator type.
2756  final SelectScope selectScope = SqlValidatorUtil.getEnclosingSelectScope(bb.scope);
2757  assert selectScope != null;
2758  final SqlValidatorNamespace selectNamespace =
2759  validator.getNamespace(selectScope.getNode());
2760  final List<String> names = selectNamespace.getRowType().getFieldNames();
2761  int sysFieldCount = selectList.size() - names.size();
2762  for (SqlNode expr : selectList) {
2763  projects.add(Pair.of(bb.convertExpression(expr),
2764  k < sysFieldCount ? validator.deriveAlias(expr, k++)
2765  : names.get(k++ - sysFieldCount)));
2766  }
2767 
2768  for (SqlNode expr : orderExprList) {
2769  projects.add(
2770  Pair.of(bb.convertExpression(expr), validator.deriveAlias(expr, k++)));
2771  }
2772  } finally {
2773  bb.agg = null;
2774  }
2775 
2776  // implement HAVING (we have already checked that it is non-trivial)
2777  relBuilder.push(bb.root);
2778  if (havingExpr != null) {
2779  relBuilder.filter(havingExpr);
2780  }
2781 
2782  // implement the SELECT list
2783  relBuilder.project(Pair.left(projects), Pair.right(projects))
2784  .rename(Pair.right(projects));
2785  bb.setRoot(relBuilder.build(), false);
2786 
2787  // Tell bb which of group columns are sorted.
2788  bb.columnMonotonicities.clear();
2789  for (SqlNode selectItem : selectList) {
2790  bb.columnMonotonicities.add(bb.scope.getMonotonicity(selectItem));
2791  }
2792  }
2793 
2812  protected RelNode createAggregate(Blackboard bb,
2813  ImmutableBitSet groupSet,
2814  ImmutableList<ImmutableBitSet> groupSets,
2815  List<AggregateCall> aggCalls) {
2816  return LogicalAggregate.create(bb.root, groupSet, groupSets, aggCalls);
2817  }
2818 
2819  public RexDynamicParam convertDynamicParam(final SqlDynamicParam dynamicParam) {
2820  // REVIEW jvs 8-Jan-2005: dynamic params may be encountered out of
2821  // order. Should probably cross-check with the count from the parser
2822  // at the end and make sure they all got filled in. Why doesn't List
2823  // have a resize() method?!? Make this a utility.
2824  while (dynamicParam.getIndex() >= dynamicParamSqlNodes.size()) {
2825  dynamicParamSqlNodes.add(null);
2826  }
2827 
2828  dynamicParamSqlNodes.set(dynamicParam.getIndex(), dynamicParam);
2829  return rexBuilder.makeDynamicParam(
2830  getDynamicParamType(dynamicParam.getIndex()), dynamicParam.getIndex());
2831  }
2832 
2847  protected void gatherOrderExprs(Blackboard bb,
2848  SqlSelect select,
2849  SqlNodeList orderList,
2850  List<SqlNode> extraOrderExprs,
2851  List<RelFieldCollation> collationList) {
2852  // TODO: add validation rules to SqlValidator also
2853  assert bb.root != null : "precondition: child != null";
2854  assert select != null;
2855  if (orderList == null) {
2856  return;
2857  }
2858 
2859  if (!bb.top) {
2860  SqlNode offset = select.getOffset();
2861  if ((offset == null
2862  || (offset instanceof SqlLiteral
2863  && ((SqlLiteral) offset)
2864  .bigDecimalValue()
2865  .equals(BigDecimal.ZERO)))
2866  && select.getFetch() == null) {
2867  return;
2868  }
2869  }
2870 
2871  for (SqlNode orderItem : orderList) {
2872  collationList.add(convertOrderItem(select,
2873  orderItem,
2874  extraOrderExprs,
2875  RelFieldCollation.Direction.ASCENDING,
2876  RelFieldCollation.NullDirection.UNSPECIFIED));
2877  }
2878  }
2879 
2880  protected RelFieldCollation convertOrderItem(SqlSelect select,
2881  SqlNode orderItem,
2882  List<SqlNode> extraExprs,
2883  RelFieldCollation.Direction direction,
2884  RelFieldCollation.NullDirection nullDirection) {
2885  assert select != null;
2886  // Handle DESC keyword, e.g. 'select a, b from t order by a desc'.
2887  switch (orderItem.getKind()) {
2888  case DESCENDING:
2889  return convertOrderItem(select,
2890  ((SqlCall) orderItem).operand(0),
2891  extraExprs,
2892  RelFieldCollation.Direction.DESCENDING,
2893  nullDirection);
2894  case NULLS_FIRST:
2895  return convertOrderItem(select,
2896  ((SqlCall) orderItem).operand(0),
2897  extraExprs,
2898  direction,
2899  RelFieldCollation.NullDirection.FIRST);
2900  case NULLS_LAST:
2901  return convertOrderItem(select,
2902  ((SqlCall) orderItem).operand(0),
2903  extraExprs,
2904  direction,
2905  RelFieldCollation.NullDirection.LAST);
2906  }
2907 
2908  SqlNode converted = validator.expandOrderExpr(select, orderItem);
2909 
2910  switch (nullDirection) {
2911  case UNSPECIFIED:
2912  nullDirection = validator.getDefaultNullCollation().last(desc(direction))
2913  ? RelFieldCollation.NullDirection.LAST
2914  : RelFieldCollation.NullDirection.FIRST;
2915  }
2916 
2917  // Scan the select list and order exprs for an identical expression.
2918  final SelectScope selectScope = validator.getRawSelectScope(select);
2919  int ordinal = -1;
2920  for (SqlNode selectItem : selectScope.getExpandedSelectList()) {
2921  ++ordinal;
2922  if (converted.equalsDeep(stripAs(selectItem), Litmus.IGNORE)) {
2923  return new RelFieldCollation(ordinal, direction, nullDirection);
2924  }
2925  }
2926 
2927  for (SqlNode extraExpr : extraExprs) {
2928  ++ordinal;
2929  if (converted.equalsDeep(extraExpr, Litmus.IGNORE)) {
2930  return new RelFieldCollation(ordinal, direction, nullDirection);
2931  }
2932  }
2933 
2934  // TODO: handle collation sequence
2935  // TODO: flag expressions as non-standard
2936 
2937  extraExprs.add(converted);
2938  return new RelFieldCollation(ordinal + 1, direction, nullDirection);
2939  }
2940 
2941  private static boolean desc(RelFieldCollation.Direction direction) {
2942  switch (direction) {
2943  case DESCENDING:
2944  case STRICTLY_DESCENDING:
2945  return true;
2946  default:
2947  return false;
2948  }
2949  }
2950 
2951  @Deprecated // to be removed before 2.0
2952  protected boolean enableDecorrelation() {
2953  // disable sub-query decorrelation when needed.
2954  // e.g. if outer joins are not supported.
2955  return config.isDecorrelationEnabled();
2956  }
2957 
2958  protected RelNode decorrelateQuery(RelNode rootRel) {
2959  return RelDecorrelator.decorrelateQuery(rootRel, relBuilder);
2960  }
2961 
2967  @Deprecated // to be removed before 2.0
2968  public boolean isTrimUnusedFields() {
2969  return config.isTrimUnusedFields();
2970  }
2971 
2981  protected RelRoot convertQueryRecursive(
2982  SqlNode query, boolean top, RelDataType targetRowType) {
2983  final SqlKind kind = query.getKind();
2984  switch (kind) {
2985  case SELECT:
2986  return RelRoot.of(convertSelect((SqlSelect) query, top), kind);
2987  case INSERT:
2988  return RelRoot.of(convertInsert((SqlInsert) query), kind);
2989  case DELETE:
2990  return RelRoot.of(convertDelete((SqlDelete) query), kind);
2991  case UPDATE:
2992  return RelRoot.of(convertUpdate((SqlUpdate) query), kind);
2993  case MERGE:
2994  return RelRoot.of(convertMerge((SqlMerge) query), kind);
2995  case UNION:
2996  case INTERSECT:
2997  case EXCEPT:
2998  return RelRoot.of(convertSetOp((SqlCall) query), kind);
2999  case WITH:
3000  return convertWith((SqlWith) query, top);
3001  case VALUES:
3002  return RelRoot.of(convertValues((SqlCall) query, targetRowType), kind);
3003  default:
3004  throw new AssertionError("not a query: " + query);
3005  }
3006  }
3007 
3015  protected RelNode convertSetOp(SqlCall call) {
3016  final RelNode left = convertQueryRecursive(call.operand(0), false, null).project();
3017  final RelNode right = convertQueryRecursive(call.operand(1), false, null).project();
3018  switch (call.getKind()) {
3019  case UNION:
3020  return LogicalUnion.create(ImmutableList.of(left, right), all(call));
3021 
3022  case INTERSECT:
3023  return LogicalIntersect.create(ImmutableList.of(left, right), all(call));
3024 
3025  case EXCEPT:
3026  return LogicalMinus.create(ImmutableList.of(left, right), all(call));
3027 
3028  default:
3029  throw Util.unexpected(call.getKind());
3030  }
3031  }
3032 
3033  private boolean all(SqlCall call) {
3034  return ((SqlSetOperator) call.getOperator()).isAll();
3035  }
3036 
3037  protected RelNode convertInsert(SqlInsert call) {
3038  RelOptTable targetTable = getTargetTable(call);
3039 
3040  final RelDataType targetRowType = validator.getValidatedNodeType(call);
3041  assert targetRowType != null;
3042  RelNode sourceRel =
3043  convertQueryRecursive(call.getSource(), false, targetRowType).project();
3044  RelNode massagedRel = convertColumnList(call, sourceRel);
3045 
3046  return createModify(targetTable, massagedRel);
3047  }
3048 
3050  private RelNode createModify(RelOptTable targetTable, RelNode source) {
3051  final ModifiableTable modifiableTable = targetTable.unwrap(ModifiableTable.class);
3052  if (modifiableTable != null && modifiableTable == targetTable.unwrap(Table.class)) {
3053  return modifiableTable.toModificationRel(cluster,
3054  targetTable,
3055  catalogReader,
3056  source,
3057  LogicalTableModify.Operation.INSERT,
3058  null,
3059  null,
3060  false);
3061  }
3062  final ModifiableView modifiableView = targetTable.unwrap(ModifiableView.class);
3063  if (modifiableView != null) {
3064  final Table delegateTable = modifiableView.getTable();
3065  final RelDataType delegateRowType = delegateTable.getRowType(typeFactory);
3066  final RelOptTable delegateRelOptTable = RelOptTableImpl.create(
3067  null, delegateRowType, delegateTable, modifiableView.getTablePath());
3068  final RelNode newSource =
3069  createSource(targetTable, source, modifiableView, delegateRowType);
3070  return createModify(delegateRelOptTable, newSource);
3071  }
3072  return LogicalTableModify.create(targetTable,
3073  catalogReader,
3074  source,
3075  LogicalTableModify.Operation.INSERT,
3076  null,
3077  null,
3078  false);
3079  }
3080 
3092  private RelNode createSource(RelOptTable targetTable,
3093  RelNode source,
3094  ModifiableView modifiableView,
3095  RelDataType delegateRowType) {
3096  final ImmutableIntList mapping = modifiableView.getColumnMapping();
3097  assert mapping.size() == targetTable.getRowType().getFieldCount();
3098 
3099  // For columns represented in the mapping, the expression is just a field
3100  // reference.
3101  final Map<Integer, RexNode> projectMap = new HashMap<>();
3102  final List<RexNode> filters = new ArrayList<>();
3103  for (int i = 0; i < mapping.size(); i++) {
3104  int target = mapping.get(i);
3105  if (target >= 0) {
3106  projectMap.put(target, RexInputRef.of(i, source.getRowType()));
3107  }
3108  }
3109 
3110  // For columns that are not in the mapping, and have a constraint of the
3111  // form "column = value", the expression is the literal "value".
3112  //
3113  // If a column has multiple constraints, the extra ones will become a
3114  // filter.
3115  final RexNode constraint = modifiableView.getConstraint(rexBuilder, delegateRowType);
3116  RelOptUtil.inferViewPredicates(projectMap, filters, constraint);
3117  final List<Pair<RexNode, String>> projects = new ArrayList<>();
3118  for (RelDataTypeField field : delegateRowType.getFieldList()) {
3119  RexNode node = projectMap.get(field.getIndex());
3120  if (node == null) {
3121  node = rexBuilder.makeNullLiteral(field.getType());
3122  }
3123  projects.add(Pair.of(
3124  rexBuilder.ensureType(field.getType(), node, false), field.getName()));
3125  }
3126 
3127  return relBuilder.push(source)
3128  .projectNamed(Pair.left(projects), Pair.right(projects), false)
3129  .filter(filters)
3130  .build();
3131  }
3132 
3133  private RelOptTable.ToRelContext createToRelContext() {
3134  return ViewExpanders.toRelContext(viewExpander, cluster);
3135  }
3136 
3137  public RelNode toRel(final RelOptTable table) {
3138  final RelNode scan = table.toRel(createToRelContext());
3139 
3140  final InitializerExpressionFactory ief =
3141  Util.first(table.unwrap(InitializerExpressionFactory.class),
3142  NullInitializerExpressionFactory.INSTANCE);
3143 
3144  // Lazily create a blackboard that contains all non-generated columns.
3145  final Supplier<Blackboard> bb = () -> {
3146  RexNode sourceRef = rexBuilder.makeRangeReference(scan);
3147  return createInsertBlackboard(table, sourceRef, table.getRowType().getFieldNames());
3148  };
3149 
3150  int virtualCount = 0;
3151  final List<RexNode> list = new ArrayList<>();
3152  for (RelDataTypeField f : table.getRowType().getFieldList()) {
3153  final ColumnStrategy strategy = ief.generationStrategy(table, f.getIndex());
3154  switch (strategy) {
3155  case VIRTUAL:
3156  list.add(ief.newColumnDefaultValue(table, f.getIndex(), bb.get()));
3157  ++virtualCount;
3158  break;
3159  default:
3160  list.add(rexBuilder.makeInputRef(
3161  scan, RelOptTableImpl.realOrdinal(table, f.getIndex())));
3162  }
3163  }
3164  if (virtualCount > 0) {
3165  relBuilder.push(scan);
3166  relBuilder.project(list);
3167  return relBuilder.build();
3168  }
3169  return scan;
3170  }
3171 
3172  protected RelOptTable getTargetTable(SqlNode call) {
3173  final SqlValidatorNamespace targetNs = validator.getNamespace(call);
3174  if (targetNs.isWrapperFor(SqlValidatorImpl.DmlNamespace.class)) {
3175  final SqlValidatorImpl.DmlNamespace dmlNamespace =
3176  targetNs.unwrap(SqlValidatorImpl.DmlNamespace.class);
3177  return SqlValidatorUtil.getRelOptTable(dmlNamespace, catalogReader, null, null);
3178  }
3179  final SqlValidatorNamespace resolvedNamespace = targetNs.resolve();
3180  return SqlValidatorUtil.getRelOptTable(resolvedNamespace, catalogReader, null, null);
3181  }
3182 
3198  protected RelNode convertColumnList(final SqlInsert call, RelNode source) {
3199  RelDataType sourceRowType = source.getRowType();
3200  final RexNode sourceRef = rexBuilder.makeRangeReference(sourceRowType, 0, false);
3201  final List<String> targetColumnNames = new ArrayList<>();
3202  final List<RexNode> columnExprs = new ArrayList<>();
3203  collectInsertTargets(call, sourceRef, targetColumnNames, columnExprs);
3204 
3205  final RelOptTable targetTable = getTargetTable(call);
3206  final RelDataType targetRowType = RelOptTableImpl.realRowType(targetTable);
3207  final List<RelDataTypeField> targetFields = targetRowType.getFieldList();
3208  final List<RexNode> sourceExps =
3209  new ArrayList<>(Collections.nCopies(targetFields.size(), null));
3210  final List<String> fieldNames =
3211  new ArrayList<>(Collections.nCopies(targetFields.size(), null));
3212 
3213  final InitializerExpressionFactory initializerFactory =
3214  getInitializerFactory(validator.getNamespace(call).getTable());
3215 
3216  // Walk the name list and place the associated value in the
3217  // expression list according to the ordinal value returned from
3218  // the table construct, leaving nulls in the list for columns
3219  // that are not referenced.
3220  final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
3221  for (Pair<String, RexNode> p : Pair.zip(targetColumnNames, columnExprs)) {
3222  RelDataTypeField field = nameMatcher.field(targetRowType, p.left);
3223  assert field != null : "column " + p.left + " not found";
3224  sourceExps.set(field.getIndex(), p.right);
3225  }
3226 
3227  // Lazily create a blackboard that contains all non-generated columns.
3228  final Supplier<Blackboard> bb =
3229  () -> createInsertBlackboard(targetTable, sourceRef, targetColumnNames);
3230 
3231  // Walk the expression list and get default values for any columns
3232  // that were not supplied in the statement. Get field names too.
3233  for (int i = 0; i < targetFields.size(); ++i) {
3234  final RelDataTypeField field = targetFields.get(i);
3235  final String fieldName = field.getName();
3236  fieldNames.set(i, fieldName);
3237  if (sourceExps.get(i) == null || sourceExps.get(i).getKind() == SqlKind.DEFAULT) {
3238  sourceExps.set(
3239  i, initializerFactory.newColumnDefaultValue(targetTable, i, bb.get()));
3240 
3241  // bare nulls are dangerous in the wrong hands
3242  sourceExps.set(i, castNullLiteralIfNeeded(sourceExps.get(i), field.getType()));
3243  }
3244  }
3245 
3246  return relBuilder.push(source).projectNamed(sourceExps, fieldNames, false).build();
3247  }
3248 
3254  RelOptTable targetTable, RexNode sourceRef, List<String> targetColumnNames) {
3255  final Map<String, RexNode> nameToNodeMap = new HashMap<>();
3256  int j = 0;
3257 
3258  // Assign expressions for non-generated columns.
3259  final List<ColumnStrategy> strategies = targetTable.getColumnStrategies();
3260  final List<String> targetFields = targetTable.getRowType().getFieldNames();
3261  for (String targetColumnName : targetColumnNames) {
3262  final int i = targetFields.indexOf(targetColumnName);
3263  switch (strategies.get(i)) {
3264  case STORED:
3265  case VIRTUAL:
3266  break;
3267  default:
3268  nameToNodeMap.put(targetColumnName, rexBuilder.makeFieldAccess(sourceRef, j++));
3269  }
3270  }
3271  return createBlackboard(null, nameToNodeMap, false);
3272  }
3273 
3274  private InitializerExpressionFactory getInitializerFactory(
3275  SqlValidatorTable validatorTable) {
3276  // We might unwrap a null instead of a InitializerExpressionFactory.
3277  final Table table = unwrap(validatorTable, Table.class);
3278  if (table != null) {
3279  InitializerExpressionFactory f = unwrap(table, InitializerExpressionFactory.class);
3280  if (f != null) {
3281  return f;
3282  }
3283  }
3284  return NullInitializerExpressionFactory.INSTANCE;
3285  }
3286 
3287  private static <T> T unwrap(Object o, Class<T> clazz) {
3288  if (o instanceof Wrapper) {
3289  return ((Wrapper) o).unwrap(clazz);
3290  }
3291  return null;
3292  }
3293 
3294  private RexNode castNullLiteralIfNeeded(RexNode node, RelDataType type) {
3295  if (!RexLiteral.isNullLiteral(node)) {
3296  return node;
3297  }
3298  return rexBuilder.makeCast(type, node);
3299  }
3300 
3311  protected void collectInsertTargets(SqlInsert call,
3312  final RexNode sourceRef,
3313  final List<String> targetColumnNames,
3314  List<RexNode> columnExprs) {
3315  final RelOptTable targetTable = getTargetTable(call);
3316  final RelDataType tableRowType = targetTable.getRowType();
3317  SqlNodeList targetColumnList = call.getTargetColumnList();
3318  if (targetColumnList == null) {
3319  if (validator.getConformance().isInsertSubsetColumnsAllowed()) {
3320  final RelDataType targetRowType =
3321  typeFactory.createStructType(tableRowType.getFieldList().subList(
3322  0, sourceRef.getType().getFieldCount()));
3323  targetColumnNames.addAll(targetRowType.getFieldNames());
3324  } else {
3325  targetColumnNames.addAll(tableRowType.getFieldNames());
3326  }
3327  } else {
3328  for (int i = 0; i < targetColumnList.size(); i++) {
3329  SqlIdentifier id = (SqlIdentifier) targetColumnList.get(i);
3330  RelDataTypeField field = SqlValidatorUtil.getTargetField(
3331  tableRowType, typeFactory, id, catalogReader, targetTable);
3332  assert field != null : "column " + id.toString() + " not found";
3333  targetColumnNames.add(field.getName());
3334  }
3335  }
3336 
3337  final Blackboard bb =
3338  createInsertBlackboard(targetTable, sourceRef, targetColumnNames);
3339 
3340  // Next, assign expressions for generated columns.
3341  final List<ColumnStrategy> strategies = targetTable.getColumnStrategies();
3342  for (String columnName : targetColumnNames) {
3343  final int i = tableRowType.getFieldNames().indexOf(columnName);
3344  final RexNode expr;
3345  switch (strategies.get(i)) {
3346  case STORED:
3347  final InitializerExpressionFactory f =
3348  Util.first(targetTable.unwrap(InitializerExpressionFactory.class),
3349  NullInitializerExpressionFactory.INSTANCE);
3350  expr = f.newColumnDefaultValue(targetTable, i, bb);
3351  break;
3352  case VIRTUAL:
3353  expr = null;
3354  break;
3355  default:
3356  expr = bb.nameToNodeMap.get(columnName);
3357  }
3358  columnExprs.add(expr);
3359  }
3360 
3361  // Remove virtual columns from the list.
3362  for (int i = 0; i < targetColumnNames.size(); i++) {
3363  if (columnExprs.get(i) == null) {
3364  columnExprs.remove(i);
3365  targetColumnNames.remove(i);
3366  --i;
3367  }
3368  }
3369  }
3370 
3371  private RelNode convertDelete(SqlDelete call) {
3372  RelOptTable targetTable = getTargetTable(call);
3373  RelNode sourceRel = convertSelect(call.getSourceSelect(), false);
3374  return LogicalTableModify.create(targetTable,
3375  catalogReader,
3376  sourceRel,
3377  LogicalTableModify.Operation.DELETE,
3378  null,
3379  null,
3380  false);
3381  }
3382 
3383  private RelNode convertUpdate(SqlUpdate call) {
3384  final SqlValidatorScope scope = validator.getWhereScope(call.getSourceSelect());
3385  Blackboard bb = createBlackboard(scope, null, false);
3386 
3387  Builder<RexNode> rexNodeSourceExpressionListBuilder = ImmutableList.builder();
3388  for (SqlNode n : call.getSourceExpressionList()) {
3389  replaceSubQueries(bb, n, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
3390  RexNode rn = bb.convertExpression(n);
3391  rexNodeSourceExpressionListBuilder.add(rn);
3392  }
3393 
3394  RelOptTable targetTable = getTargetTable(call);
3395 
3396  // convert update column list from SqlIdentifier to String
3397  final List<String> targetColumnNameList = new ArrayList<>();
3398  final RelDataType targetRowType = targetTable.getRowType();
3399  for (SqlNode node : call.getTargetColumnList()) {
3400  SqlIdentifier id = (SqlIdentifier) node;
3401  RelDataTypeField field = SqlValidatorUtil.getTargetField(
3402  targetRowType, typeFactory, id, catalogReader, targetTable);
3403  assert field != null : "column " + id.toString() + " not found";
3404  targetColumnNameList.add(field.getName());
3405  }
3406 
3407  convertSelectImpl(bb, call.getSourceSelect());
3408  RelNode sourceRel = bb.root;
3409 
3410  return LogicalTableModify.create(targetTable,
3411  catalogReader,
3412  sourceRel,
3413  LogicalTableModify.Operation.UPDATE,
3414  targetColumnNameList,
3415  rexNodeSourceExpressionListBuilder.build(),
3416  false);
3417  }
3418 
3419  private RelNode convertMerge(SqlMerge call) {
3420  RelOptTable targetTable = getTargetTable(call);
3421 
3422  // convert update column list from SqlIdentifier to String
3423  final List<String> targetColumnNameList = new ArrayList<>();
3424  final RelDataType targetRowType = targetTable.getRowType();
3425  SqlUpdate updateCall = call.getUpdateCall();
3426  if (updateCall != null) {
3427  for (SqlNode targetColumn : updateCall.getTargetColumnList()) {
3428  SqlIdentifier id = (SqlIdentifier) targetColumn;
3429  RelDataTypeField field = SqlValidatorUtil.getTargetField(
3430  targetRowType, typeFactory, id, catalogReader, targetTable);
3431  assert field != null : "column " + id.toString() + " not found";
3432  targetColumnNameList.add(field.getName());
3433  }
3434  }
3435 
3436  // replace the projection of the source select with a
3437  // projection that contains the following:
3438  // 1) the expressions corresponding to the new insert row (if there is
3439  // an insert)
3440  // 2) all columns from the target table (if there is an update)
3441  // 3) the set expressions in the update call (if there is an update)
3442 
3443  // first, convert the merge's source select to construct the columns
3444  // from the target table and the set expressions in the update call
3445  RelNode mergeSourceRel = convertSelect(call.getSourceSelect(), false);
3446 
3447  // then, convert the insert statement so we can get the insert
3448  // values expressions
3449  SqlInsert insertCall = call.getInsertCall();
3450  int nLevel1Exprs = 0;
3451  List<RexNode> level1InsertExprs = null;
3452  List<RexNode> level2InsertExprs = null;
3453  if (insertCall != null) {
3454  RelNode insertRel = convertInsert(insertCall);
3455 
3456  // if there are 2 level of projections in the insert source, combine
3457  // them into a single project; level1 refers to the topmost project;
3458  // the level1 projection contains references to the level2
3459  // expressions, except in the case where no target expression was
3460  // provided, in which case, the expression is the default value for
3461  // the column; or if the expressions directly map to the source
3462  // table
3463  level1InsertExprs = ((LogicalProject) insertRel.getInput(0)).getProjects();
3464  if (insertRel.getInput(0).getInput(0) instanceof LogicalProject) {
3465  level2InsertExprs =
3466  ((LogicalProject) insertRel.getInput(0).getInput(0)).getProjects();
3467  }
3468  nLevel1Exprs = level1InsertExprs.size();
3469  }
3470 
3471  LogicalJoin join = (LogicalJoin) mergeSourceRel.getInput(0);
3472  int nSourceFields = join.getLeft().getRowType().getFieldCount();
3473  final List<RexNode> projects = new ArrayList<>();
3474  for (int level1Idx = 0; level1Idx < nLevel1Exprs; level1Idx++) {
3475  if ((level2InsertExprs != null)
3476  && (level1InsertExprs.get(level1Idx) instanceof RexInputRef)) {
3477  int level2Idx = ((RexInputRef) level1InsertExprs.get(level1Idx)).getIndex();
3478  projects.add(level2InsertExprs.get(level2Idx));
3479  } else {
3480  projects.add(level1InsertExprs.get(level1Idx));
3481  }
3482  }
3483  if (updateCall != null) {
3484  final LogicalProject project = (LogicalProject) mergeSourceRel;
3485  projects.addAll(Util.skip(project.getProjects(), nSourceFields));
3486  }
3487 
3488  relBuilder.push(join).project(projects);
3489 
3490  return LogicalTableModify.create(targetTable,
3491  catalogReader,
3492  relBuilder.build(),
3493  LogicalTableModify.Operation.MERGE,
3494  targetColumnNameList,
3495  null,
3496  false);
3497  }
3498 
3503  private RexNode convertIdentifier(Blackboard bb, SqlIdentifier identifier) {
3504  // first check for reserved identifiers like CURRENT_USER
3505  final SqlCall call = bb.getValidator().makeNullaryCall(identifier);
3506  if (call != null) {
3507  return bb.convertExpression(call);
3508  }
3509 
3510  String pv = null;
3511  if (bb.isPatternVarRef && identifier.names.size() > 1) {
3512  pv = identifier.names.get(0);
3513  }
3514 
3515  final SqlQualified qualified;
3516  if (bb.scope != null) {
3517  qualified = bb.scope.fullyQualify(identifier);
3518  } else {
3519  qualified = SqlQualified.create(null, 1, null, identifier);
3520  }
3521  final Pair<RexNode, Map<String, Integer>> e0 = bb.lookupExp(qualified);
3522  RexNode e = e0.left;
3523  for (String name : qualified.suffix()) {
3524  if (e == e0.left && e0.right != null) {
3525  int i = e0.right.get(name);
3526  e = rexBuilder.makeFieldAccess(e, i);
3527  } else {
3528  final boolean caseSensitive = true; // name already fully-qualified
3529  if (identifier.isStar() && bb.scope instanceof MatchRecognizeScope) {
3530  e = rexBuilder.makeFieldAccess(e, 0);
3531  } else {
3532  e = rexBuilder.makeFieldAccess(e, name, caseSensitive);
3533  }
3534  }
3535  }
3536  if (e instanceof RexInputRef) {
3537  // adjust the type to account for nulls introduced by outer joins
3538  e = adjustInputRef(bb, (RexInputRef) e);
3539  if (pv != null) {
3540  e = RexPatternFieldRef.of(pv, (RexInputRef) e);
3541  }
3542  }
3543 
3544  if (e0.left instanceof RexCorrelVariable) {
3545  assert e instanceof RexFieldAccess;
3546  final RexNode prev = bb.mapCorrelateToRex.put(
3547  ((RexCorrelVariable) e0.left).id, (RexFieldAccess) e);
3548  assert prev == null;
3549  }
3550  return e;
3551  }
3552 
3562  protected RexNode adjustInputRef(Blackboard bb, RexInputRef inputRef) {
3563  RelDataTypeField field = bb.getRootField(inputRef);
3564  if (field != null) {
3565  return rexBuilder.makeInputRef(field.getType(), inputRef.getIndex());
3566  }
3567  return inputRef;
3568  }
3569 
3577  private RelNode convertRowConstructor(Blackboard bb, SqlCall rowConstructor) {
3578  Preconditions.checkArgument(isRowConstructor(rowConstructor));
3579  final List<SqlNode> operands = rowConstructor.getOperandList();
3580  return convertMultisets(operands, bb);
3581  }
3582 
3583  private RelNode convertCursor(Blackboard bb, SubQuery subQuery) {
3584  final SqlCall cursorCall = (SqlCall) subQuery.node;
3585  assert cursorCall.operandCount() == 1;
3586  SqlNode query = cursorCall.operand(0);
3587  RelNode converted = convertQuery(query, false, false).rel;
3588  int iCursor = bb.cursors.size();
3589  bb.cursors.add(converted);
3590  subQuery.expr = new RexInputRef(iCursor, converted.getRowType());
3591  return converted;
3592  }
3593 
3594  private RelNode convertMultisets(final List<SqlNode> operands, Blackboard bb) {
3595  // NOTE: Wael 2/04/05: this implementation is not the most efficient in
3596  // terms of planning since it generates XOs that can be reduced.
3597  final List<Object> joinList = new ArrayList<>();
3598  List<SqlNode> lastList = new ArrayList<>();
3599  for (int i = 0; i < operands.size(); i++) {
3600  SqlNode operand = operands.get(i);
3601  if (!(operand instanceof SqlCall)) {
3602  lastList.add(operand);
3603  continue;
3604  }
3605 
3606  final SqlCall call = (SqlCall) operand;
3607  final RelNode input;
3608  switch (call.getKind()) {
3609  case MULTISET_VALUE_CONSTRUCTOR:
3610  case ARRAY_VALUE_CONSTRUCTOR:
3611  final SqlNodeList list =
3612  new SqlNodeList(call.getOperandList(), call.getParserPosition());
3613  CollectNamespace nss = (CollectNamespace) validator.getNamespace(call);
3614  Blackboard usedBb;
3615  if (null != nss) {
3616  usedBb = createBlackboard(nss.getScope(), null, false);
3617  } else {
3618  usedBb = createBlackboard(new ListScope(bb.scope) {
3619  public SqlNode getNode() {
3620  return call;
3621  }
3622  }, null, false);
3623  }
3624  RelDataType multisetType = validator.getValidatedNodeType(call);
3625  ((SqlValidatorImpl) validator)
3626  .setValidatedNodeType(list, multisetType.getComponentType());
3627  input = convertQueryOrInList(usedBb, list, null);
3628  break;
3629  case MULTISET_QUERY_CONSTRUCTOR:
3630  case ARRAY_QUERY_CONSTRUCTOR:
3631  final RelRoot root = convertQuery(call.operand(0), false, true);
3632  input = root.rel;
3633  break;
3634  default:
3635  lastList.add(operand);
3636  continue;
3637  }
3638 
3639  if (lastList.size() > 0) {
3640  joinList.add(lastList);
3641  }
3642  lastList = new ArrayList<>();
3643  Collect collect = new Collect(cluster,
3644  cluster.traitSetOf(Convention.NONE),
3645  input,
3646  validator.deriveAlias(call, i));
3647  joinList.add(collect);
3648  }
3649 
3650  if (joinList.size() == 0) {
3651  joinList.add(lastList);
3652  }
3653 
3654  for (int i = 0; i < joinList.size(); i++) {
3655  Object o = joinList.get(i);
3656  if (o instanceof List) {
3657  @SuppressWarnings("unchecked")
3658  List<SqlNode> projectList = (List<SqlNode>) o;
3659  final List<RexNode> selectList = new ArrayList<>();
3660  final List<String> fieldNameList = new ArrayList<>();
3661  for (int j = 0; j < projectList.size(); j++) {
3662  SqlNode operand = projectList.get(j);
3663  selectList.add(bb.convertExpression(operand));
3664 
3665  // REVIEW angel 5-June-2005: Use deriveAliasFromOrdinal
3666  // instead of deriveAlias to match field names from
3667  // SqlRowOperator. Otherwise, get error Type
3668  // 'RecordType(INTEGER EMPNO)' has no field 'EXPR$0' when
3669  // doing select * from unnest( select multiset[empno]
3670  // from sales.emps);
3671 
3672  fieldNameList.add(SqlUtil.deriveAliasFromOrdinal(j));
3673  }
3674 
3675  relBuilder.push(LogicalValues.createOneRow(cluster))
3676  .projectNamed(selectList, fieldNameList, true);
3677 
3678  joinList.set(i, relBuilder.build());
3679  }
3680  }
3681 
3682  RelNode ret = (RelNode) joinList.get(0);
3683  for (int i = 1; i < joinList.size(); i++) {
3684  RelNode relNode = (RelNode) joinList.get(i);
3685  ret = RelFactories.DEFAULT_JOIN_FACTORY.createJoin(ret,
3686  relNode,
3687  rexBuilder.makeLiteral(true),
3688  ImmutableSet.of(),
3689  JoinRelType.INNER,
3690  false);
3691  }
3692  return ret;
3693  }
3694 
3695  private void convertSelectList(
3696  Blackboard bb, SqlSelect select, List<SqlNode> orderList) {
3697  SqlNodeList selectList = select.getSelectList();
3698  selectList = validator.expandStar(selectList, select, false);
3699 
3700  replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
3701 
3702  List<String> fieldNames = new ArrayList<>();
3703  final List<RexNode> exprs = new ArrayList<>();
3704  final Collection<String> aliases = new TreeSet<>();
3705 
3706  // Project any system fields. (Must be done before regular select items,
3707  // because offsets may be affected.)
3708  final List<SqlMonotonicity> columnMonotonicityList = new ArrayList<>();
3709  extraSelectItems(bb, select, exprs, fieldNames, aliases, columnMonotonicityList);
3710 
3711  // Project select clause.
3712  int i = -1;
3713  for (SqlNode expr : selectList) {
3714  ++i;
3715  exprs.add(bb.convertExpression(expr));
3716  fieldNames.add(deriveAlias(expr, aliases, i));
3717  }
3718 
3719  // Project extra fields for sorting.
3720  for (SqlNode expr : orderList) {
3721  ++i;
3722  SqlNode expr2 = validator.expandOrderExpr(select, expr);
3723  exprs.add(bb.convertExpression(expr2));
3724  fieldNames.add(deriveAlias(expr, aliases, i));
3725  }
3726 
3727  fieldNames = SqlValidatorUtil.uniquify(
3728  fieldNames, catalogReader.nameMatcher().isCaseSensitive());
3729 
3730  relBuilder.push(bb.root).projectNamed(exprs, fieldNames, true);
3731  bb.setRoot(relBuilder.build(), false);
3732 
3733  assert bb.columnMonotonicities.isEmpty();
3734  bb.columnMonotonicities.addAll(columnMonotonicityList);
3735  for (SqlNode selectItem : selectList) {
3736  bb.columnMonotonicities.add(selectItem.getMonotonicity(bb.scope));
3737  }
3738  }
3739 
3753  protected void extraSelectItems(Blackboard bb,
3754  SqlSelect select,
3755  List<RexNode> exprList,
3756  List<String> nameList,
3757  Collection<String> aliasList,
3758  List<SqlMonotonicity> columnMonotonicityList) {}
3759 
3761  final SqlNode node, Collection<String> aliases, final int ordinal) {
3762  String alias = validator.deriveAlias(node, ordinal);
3763  if ((alias == null) || aliases.contains(alias)) {
3764  String aliasBase = (alias == null) ? "EXPR$" : alias;
3765  for (int j = 0;; j++) {
3766  alias = aliasBase + j;
3767  if (!aliases.contains(alias)) {
3768  break;
3769  }
3770  }
3771  }
3772  aliases.add(alias);
3773  return alias;
3774  }
3775 
3779  public RelRoot convertWith(SqlWith with, boolean top) {
3780  return convertQuery(with.body, false, top);
3781  }
3782 
3786  public RelNode convertValues(SqlCall values, RelDataType targetRowType) {
3787  final SqlValidatorScope scope = validator.getOverScope(values);
3788  assert scope != null;
3789  final Blackboard bb = createBlackboard(scope, null, false);
3790  convertValuesImpl(bb, values, targetRowType);
3791  return bb.root;
3792  }
3793 
3802  private void convertValuesImpl(
3803  Blackboard bb, SqlCall values, RelDataType targetRowType) {
3804  // Attempt direct conversion to LogicalValues; if that fails, deal with
3805  // fancy stuff like sub-queries below.
3806  RelNode valuesRel =
3807  convertRowValues(bb, values, values.getOperandList(), true, targetRowType);
3808  if (valuesRel != null) {
3809  bb.setRoot(valuesRel, true);
3810  return;
3811  }
3812 
3813  final List<RelNode> unionRels = new ArrayList<>();
3814  for (SqlNode rowConstructor1 : values.getOperandList()) {
3815  SqlCall rowConstructor = (SqlCall) rowConstructor1;
3816  Blackboard tmpBb = createBlackboard(bb.scope, null, false);
3817  replaceSubQueries(tmpBb, rowConstructor, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
3818  final List<Pair<RexNode, String>> exps = new ArrayList<>();
3819  for (Ord<SqlNode> operand : Ord.zip(rowConstructor.getOperandList())) {
3820  exps.add(Pair.of(tmpBb.convertExpression(operand.e),
3821  validator.deriveAlias(operand.e, operand.i)));
3822  }
3823  RelNode in =
3824  (null == tmpBb.root) ? LogicalValues.createOneRow(cluster) : tmpBb.root;
3825  unionRels.add(
3826  relBuilder.push(in).project(Pair.left(exps), Pair.right(exps)).build());
3827  }
3828 
3829  if (unionRels.size() == 0) {
3830  throw new AssertionError("empty values clause");
3831  } else if (unionRels.size() == 1) {
3832  bb.setRoot(unionRels.get(0), true);
3833  } else {
3834  bb.setRoot(LogicalUnion.create(unionRels, true), true);
3835  }
3836  }
3837 
3838  //~ Inner Classes ----------------------------------------------------------
3839 
3843  protected class Blackboard
3844  implements SqlRexContext, SqlVisitor<RexNode>, InitializerContext {
3849  public final SqlValidatorScope scope;
3850  private final Map<String, RexNode> nameToNodeMap;
3851  public RelNode root;
3852  private List<RelNode> inputs;
3853  private final Map<CorrelationId, RexFieldAccess> mapCorrelateToRex = new HashMap<>();
3854 
3855  private boolean isPatternVarRef = false;
3856 
3857  final List<RelNode> cursors = new ArrayList<>();
3858 
3863  private final Set<SubQuery> subQueryList = new LinkedHashSet<>();
3864 
3869 
3874  SqlWindow window;
3875 
3881  private final Map<RelNode, Map<Integer, Integer>> mapRootRelToFieldProjection =
3882  new HashMap<>();
3883 
3884  private final List<SqlMonotonicity> columnMonotonicities = new ArrayList<>();
3885 
3886  private final List<RelDataTypeField> systemFieldList = new ArrayList<>();
3887  final boolean top;
3888 
3889  private final InitializerExpressionFactory initializerExpressionFactory =
3890  new NullInitializerExpressionFactory();
3891 
3903  protected Blackboard(
3904  SqlValidatorScope scope, Map<String, RexNode> nameToNodeMap, boolean top) {
3905  this.scope = scope;
3906  this.nameToNodeMap = nameToNodeMap;
3907  this.top = top;
3908  }
3909 
3910  public void setPatternVarRef(boolean isVarRef) {
3911  this.isPatternVarRef = isVarRef;
3912  }
3913 
3914  public RexNode register(RelNode rel, JoinRelType joinType) {
3915  return register(rel, joinType, null);
3916  }
3917 
3928  public RexNode register(RelNode rel, JoinRelType joinType, List<RexNode> leftKeys) {
3929  assert joinType != null;
3930  if (root == null) {
3931  assert leftKeys == null;
3932  setRoot(rel, false);
3933  return rexBuilder.makeRangeReference(root.getRowType(), 0, false);
3934  }
3935 
3936  final RexNode joinCond;
3937  final int origLeftInputCount = root.getRowType().getFieldCount();
3938  if (leftKeys != null) {
3939  List<RexNode> newLeftInputExprs = new ArrayList<>();
3940  for (int i = 0; i < origLeftInputCount; i++) {
3941  newLeftInputExprs.add(rexBuilder.makeInputRef(root, i));
3942  }
3943 
3944  final List<Integer> leftJoinKeys = new ArrayList<>();
3945  for (RexNode leftKey : leftKeys) {
3946  int index = newLeftInputExprs.indexOf(leftKey);
3947  if (index < 0 || joinType == JoinRelType.LEFT) {
3948  index = newLeftInputExprs.size();
3949  newLeftInputExprs.add(leftKey);
3950  }
3951  leftJoinKeys.add(index);
3952  }
3953 
3954  RelNode newLeftInput = relBuilder.push(root).project(newLeftInputExprs).build();
3955 
3956  // maintain the group by mapping in the new LogicalProject
3957  if (mapRootRelToFieldProjection.containsKey(root)) {
3958  mapRootRelToFieldProjection.put(
3959  newLeftInput, mapRootRelToFieldProjection.get(root));
3960  }
3961 
3962  setRoot(newLeftInput, false);
3963 
3964  // right fields appear after the LHS fields.
3965  final int rightOffset = root.getRowType().getFieldCount()
3966  - newLeftInput.getRowType().getFieldCount();
3967  final List<Integer> rightKeys =
3968  Util.range(rightOffset, rightOffset + leftKeys.size());
3969 
3970  joinCond = RelOptUtil.createEquiJoinCondition(
3971  newLeftInput, leftJoinKeys, rel, rightKeys, rexBuilder);
3972  } else {
3973  joinCond = rexBuilder.makeLiteral(true);
3974  }
3975 
3976  int leftFieldCount = root.getRowType().getFieldCount();
3977  final RelNode join = createJoin(this, root, rel, joinCond, joinType);
3978 
3979  setRoot(join, false);
3980 
3981  if (leftKeys != null && joinType == JoinRelType.LEFT) {
3982  final int leftKeyCount = leftKeys.size();
3983  int rightFieldLength = rel.getRowType().getFieldCount();
3984  assert leftKeyCount == rightFieldLength - 1;
3985 
3986  final int rexRangeRefLength = leftKeyCount + rightFieldLength;
3987  RelDataType returnType = typeFactory.createStructType(
3988  new AbstractList<Map.Entry<String, RelDataType>>() {
3989  public Map.Entry<String, RelDataType> get(int index) {
3990  return join.getRowType().getFieldList().get(
3991  origLeftInputCount + index);
3992  }
3993 
3994  public int size() {
3995  return rexRangeRefLength;
3996  }
3997  });
3998 
3999  return rexBuilder.makeRangeReference(returnType, origLeftInputCount, false);
4000  } else {
4001  return rexBuilder.makeRangeReference(
4002  rel.getRowType(), leftFieldCount, joinType.generatesNullsOnRight());
4003  }
4004  }
4005 
4018  public void setRoot(RelNode root, boolean leaf) {
4019  setRoot(Collections.singletonList(root), root, root instanceof LogicalJoin);
4020  if (leaf) {
4021  leaves.add(root);
4022  }
4023  this.columnMonotonicities.clear();
4024  }
4025 
4026  private void setRoot(List<RelNode> inputs, RelNode root, boolean hasSystemFields) {
4027  this.inputs = inputs;
4028  this.root = root;
4029  this.systemFieldList.clear();
4030  if (hasSystemFields) {
4031  this.systemFieldList.addAll(getSystemFields());
4032  }
4033  }
4034 
4045  public void setDataset(String datasetName) {}
4046 
4047  void setRoot(List<RelNode> inputs) {
4048  setRoot(inputs, null, false);
4049  }
4050 
4058  Pair<RexNode, Map<String, Integer>> lookupExp(SqlQualified qualified) {
4059  if (nameToNodeMap != null && qualified.prefixLength == 1) {
4060  RexNode node = nameToNodeMap.get(qualified.identifier.names.get(0));
4061  if (node == null) {
4062  throw new AssertionError("Unknown identifier '" + qualified.identifier
4063  + "' encountered while expanding expression");
4064  }
4065  return Pair.of(node, null);
4066  }
4067  final SqlNameMatcher nameMatcher =
4068  scope.getValidator().getCatalogReader().nameMatcher();
4069  final SqlValidatorScope.ResolvedImpl resolved =
4070  new SqlValidatorScope.ResolvedImpl();
4071  scope.resolve(qualified.prefix(), nameMatcher, false, resolved);
4072  if (!(resolved.count() == 1)) {
4073  return null;
4074  }
4075  final SqlValidatorScope.Resolve resolve = resolved.only();
4076  final RelDataType rowType = resolve.rowType();
4077 
4078  // Found in current query's from list. Find which from item.
4079  // We assume that the order of the from clause items has been
4080  // preserved.
4081  final SqlValidatorScope ancestorScope = resolve.scope;
4082  boolean isParent = ancestorScope != scope;
4083  if ((inputs != null) && !isParent) {
4084  final LookupContext rels =
4085  new LookupContext(this, inputs, systemFieldList.size());
4086  final RexNode node = lookup(resolve.path.steps().get(0).i, rels);
4087  if (node == null) {
4088  return null;
4089  } else {
4090  final Map<String, Integer> fieldOffsets = new HashMap<>();
4091  for (RelDataTypeField f : resolve.rowType().getFieldList()) {
4092  if (!fieldOffsets.containsKey(f.getName())) {
4093  fieldOffsets.put(f.getName(), f.getIndex());
4094  }
4095  }
4096  final Map<String, Integer> map = ImmutableMap.copyOf(fieldOffsets);
4097  return Pair.of(node, map);
4098  }
4099  } else {
4100  // We're referencing a relational expression which has not been
4101  // converted yet. This occurs when from items are correlated,
4102  // e.g. "select from emp as emp join emp.getDepts() as dept".
4103  // Create a temporary expression.
4104  DeferredLookup lookup =
4105  new DeferredLookup(this, qualified.identifier.names.get(0));
4106  final CorrelationId correlId = cluster.createCorrel();
4107  mapCorrelToDeferred.put(correlId, lookup);
4108  if (resolve.path.steps().get(0).i < 0) {
4109  return Pair.of(rexBuilder.makeCorrel(rowType, correlId), null);
4110  } else {
4111  final RelDataTypeFactory.Builder builder = typeFactory.builder();
4112  final ListScope ancestorScope1 = (ListScope) resolve.scope;
4113  final ImmutableMap.Builder<String, Integer> fields = ImmutableMap.builder();
4114  int i = 0;
4115  int offset = 0;
4116  for (SqlValidatorNamespace c : ancestorScope1.getChildren()) {
4117  builder.addAll(c.getRowType().getFieldList());
4118  if (i == resolve.path.steps().get(0).i) {
4119  for (RelDataTypeField field : c.getRowType().getFieldList()) {
4120  fields.put(field.getName(), field.getIndex() + offset);
4121  }
4122  }
4123  ++i;
4124  offset += c.getRowType().getFieldCount();
4125  }
4126  final RexNode c = rexBuilder.makeCorrel(builder.uniquify().build(), correlId);
4127  return Pair.of(c, fields.build());
4128  }
4129  }
4130  }
4131 
4136  RexNode lookup(int offset, LookupContext lookupContext) {
4137  Pair<RelNode, Integer> pair = lookupContext.findRel(offset);
4138  return rexBuilder.makeRangeReference(pair.left.getRowType(), pair.right, false);
4139  }
4140 
4141  RelDataTypeField getRootField(RexInputRef inputRef) {
4142  if (inputs == null) {
4143  return null;
4144  }
4145  int fieldOffset = inputRef.getIndex();
4146  for (RelNode input : inputs) {
4147  RelDataType rowType = input.getRowType();
4148  if (rowType == null) {
4149  // TODO: remove this once leastRestrictive
4150  // is correctly implemented
4151  return null;
4152  }
4153  if (fieldOffset < rowType.getFieldCount()) {
4154  return rowType.getFieldList().get(fieldOffset);
4155  }
4156  fieldOffset -= rowType.getFieldCount();
4157  }
4158  throw new AssertionError();
4159  }
4160 
4161  public void flatten(List<RelNode> rels,
4162  int systemFieldCount,
4163  int[] start,
4164  List<Pair<RelNode, Integer>> relOffsetList) {
4165  for (RelNode rel : rels) {
4166  if (leaves.contains(rel) || rel instanceof LogicalMatch) {
4167  relOffsetList.add(Pair.of(rel, start[0]));
4168  start[0] += rel.getRowType().getFieldCount();
4169  } else {
4170  if (rel instanceof LogicalJoin || rel instanceof LogicalAggregate) {
4171  start[0] += systemFieldCount;
4172  }
4173  flatten(rel.getInputs(), systemFieldCount, start, relOffsetList);
4174  }
4175  }
4176  }
4177 
4178  void registerSubQuery(SqlNode node, RelOptUtil.Logic logic) {
4179  for (SubQuery subQuery : subQueryList) {
4180  if (node.equalsDeep(subQuery.node, Litmus.IGNORE)) {
4181  return;
4182  }
4183  }
4184  subQueryList.add(new SubQuery(node, logic));
4185  }
4186 
4187  SubQuery getSubQuery(SqlNode expr) {
4188  for (SubQuery subQuery : subQueryList) {
4189  if (expr.equalsDeep(subQuery.node, Litmus.IGNORE)) {
4190  return subQuery;
4191  }
4192  }
4193 
4194  return null;
4195  }
4196 
4197  ImmutableList<RelNode> retrieveCursors() {
4198  try {
4199  return ImmutableList.copyOf(cursors);
4200  } finally {
4201  cursors.clear();
4202  }
4203  }
4204 
4205  public RexNode convertExpression(SqlNode expr) {
4206  // If we're in aggregation mode and this is an expression in the
4207  // GROUP BY clause, return a reference to the field.
4208  if (agg != null) {
4209  final SqlNode expandedGroupExpr = validator.expand(expr, scope);
4210  final int ref = agg.lookupGroupExpr(expandedGroupExpr);
4211  if (ref >= 0) {
4212  return rexBuilder.makeInputRef(root, ref);
4213  }
4214  if (expr instanceof SqlCall) {
4215  final RexNode rex = agg.lookupAggregates((SqlCall) expr);
4216  if (rex != null) {
4217  return rex;
4218  }
4219  }
4220  }
4221 
4222  // Allow the derived class chance to override the standard
4223  // behavior for special kinds of expressions.
4224  RexNode rex = convertExtendedExpression(expr, this);
4225  if (rex != null) {
4226  return rex;
4227  }
4228 
4229  // Sub-queries and OVER expressions are not like ordinary
4230  // expressions.
4231  final SqlKind kind = expr.getKind();
4232  final SubQuery subQuery;
4233  if (!config.isExpand()) {
4234  final SqlCall call;
4235  final SqlNode query;
4236  final RelRoot root;
4237  switch (kind) {
4238  case IN:
4239  case NOT_IN:
4240  case SOME:
4241  case ALL:
4242  call = (SqlCall) expr;
4243  query = call.operand(1);
4244  if (!(query instanceof SqlNodeList)) {
4245  root = convertQueryRecursive(query, false, null);
4246  final SqlNode operand = call.operand(0);
4247  List<SqlNode> nodes;
4248  switch (operand.getKind()) {
4249  case ROW:
4250  nodes = ((SqlCall) operand).getOperandList();
4251  break;
4252  default:
4253  nodes = ImmutableList.of(operand);
4254  }
4255  final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
4256  for (SqlNode node : nodes) {
4257  builder.add(convertExpression(node));
4258  }
4259  final ImmutableList<RexNode> list = builder.build();
4260  switch (kind) {
4261  case IN:
4262  return RexSubQuery.in(root.rel, list);
4263  case NOT_IN:
4264  return rexBuilder.makeCall(
4265  SqlStdOperatorTable.NOT, RexSubQuery.in(root.rel, list));
4266  case SOME:
4267  return RexSubQuery.some(
4268  root.rel, list, (SqlQuantifyOperator) call.getOperator());
4269  case ALL:
4270  return rexBuilder.makeCall(SqlStdOperatorTable.NOT,
4271  RexSubQuery.some(root.rel,
4272  list,
4273  negate((SqlQuantifyOperator) call.getOperator())));
4274  default:
4275  throw new AssertionError(kind);
4276  }
4277  }
4278  break;
4279 
4280  case EXISTS:
4281  call = (SqlCall) expr;
4282  query = Iterables.getOnlyElement(call.getOperandList());
4283  root = convertQueryRecursive(query, false, null);
4284  RelNode rel = root.rel;
4285  while (rel instanceof Project
4286  || rel instanceof Sort && ((Sort) rel).fetch == null
4287  && ((Sort) rel).offset == null) {
4288  rel = ((SingleRel) rel).getInput();
4289  }
4290  return RexSubQuery.exists(rel);
4291 
4292  case SCALAR_QUERY:
4293  call = (SqlCall) expr;
4294  query = Iterables.getOnlyElement(call.getOperandList());
4295  root = convertQueryRecursive(query, false, null);
4296  return RexSubQuery.scalar(root.rel);
4297  }
4298  }
4299 
4300  switch (kind) {
4301  case SOME:
4302  case ALL:
4303  if (config.isExpand()) {
4304  throw new RuntimeException(kind + " is only supported if expand = false");
4305  }
4306  // fall through
4307  case CURSOR:
4308  case IN:
4309  case NOT_IN:
4310  subQuery = Objects.requireNonNull(getSubQuery(expr));
4311  rex = Objects.requireNonNull(subQuery.expr);
4312  return StandardConvertletTable.castToValidatedType(
4313  expr, rex, validator, rexBuilder);
4314 
4315  case SELECT:
4316  case EXISTS:
4317  case SCALAR_QUERY:
4318  subQuery = getSubQuery(expr);
4319  assert subQuery != null;
4320  rex = subQuery.expr;
4321  assert rex != null : "rex != null";
4322 
4323  if (((kind == SqlKind.SCALAR_QUERY) || (kind == SqlKind.EXISTS))
4324  && isConvertedSubq(rex)) {
4325  // scalar sub-query or EXISTS has been converted to a
4326  // constant
4327  return rex;
4328  }
4329 
4330  // The indicator column is the last field of the sub-query.
4331  RexNode fieldAccess =
4332  rexBuilder.makeFieldAccess(rex, rex.getType().getFieldCount() - 1);
4333 
4334  // The indicator column will be nullable if it comes from
4335  // the null-generating side of the join. For EXISTS, add an
4336  // "IS TRUE" check so that the result is "BOOLEAN NOT NULL".
4337  if (fieldAccess.getType().isNullable() && kind == SqlKind.EXISTS) {
4338  fieldAccess =
4339  rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, fieldAccess);
4340  }
4341  return fieldAccess;
4342 
4343  case OVER:
4344  return convertOver(this, expr);
4345 
4346  default:
4347  // fall through
4348  }
4349 
4350  // Apply standard conversions.
4351  rex = expr.accept(this);
4352  return Objects.requireNonNull(rex);
4353  }
4354 
4359  public RexFieldCollation convertSortExpression(SqlNode expr,
4360  RelFieldCollation.Direction direction,
4361  RelFieldCollation.NullDirection nullDirection) {
4362  switch (expr.getKind()) {
4363  case DESCENDING:
4364  return convertSortExpression(((SqlCall) expr).operand(0),
4365  RelFieldCollation.Direction.DESCENDING,
4366  nullDirection);
4367  case NULLS_LAST:
4368  return convertSortExpression(((SqlCall) expr).operand(0),
4369  direction,
4370  RelFieldCollation.NullDirection.LAST);
4371  case NULLS_FIRST:
4372  return convertSortExpression(((SqlCall) expr).operand(0),
4373  direction,
4374  RelFieldCollation.NullDirection.FIRST);
4375  default:
4376  final Set<SqlKind> flags = EnumSet.noneOf(SqlKind.class);
4377  switch (direction) {
4378  case DESCENDING:
4379  flags.add(SqlKind.DESCENDING);
4380  }
4381  switch (nullDirection) {
4382  case UNSPECIFIED:
4383  final RelFieldCollation.NullDirection nullDefaultDirection =
4384  validator.getDefaultNullCollation().last(desc(direction))
4385  ? RelFieldCollation.NullDirection.LAST
4386  : RelFieldCollation.NullDirection.FIRST;
4387  if (nullDefaultDirection != direction.defaultNullDirection()) {
4388  SqlKind nullDirectionSqlKind =
4389  validator.getDefaultNullCollation().last(desc(direction))
4390  ? SqlKind.NULLS_LAST
4391  : SqlKind.NULLS_FIRST;
4392  flags.add(nullDirectionSqlKind);
4393  }
4394  break;
4395  case FIRST:
4396  flags.add(SqlKind.NULLS_FIRST);
4397  break;
4398  case LAST:
4399  flags.add(SqlKind.NULLS_LAST);
4400  break;
4401  }
4402  return new RexFieldCollation(convertExpression(expr), flags);
4403  }
4404  }
4405 
4414  private boolean isConvertedSubq(RexNode rex) {
4415  if ((rex instanceof RexLiteral) || (rex instanceof RexDynamicParam)) {
4416  return true;
4417  }
4418  if (rex instanceof RexCall) {
4419  RexCall call = (RexCall) rex;
4420  if (call.getOperator() == SqlStdOperatorTable.CAST) {
4421  RexNode operand = call.getOperands().get(0);
4422  if (operand instanceof RexLiteral) {
4423  return true;
4424  }
4425  }
4426  }
4427  return false;
4428  }
4429 
4430  public int getGroupCount() {
4431  if (agg != null) {
4432  return agg.groupExprs.size();
4433  }
4434  if (window != null) {
4435  return window.isAlwaysNonEmpty() ? 1 : 0;
4436  }
4437  return -1;
4438  }
4439 
4440  public RexBuilder getRexBuilder() {
4441  return rexBuilder;
4442  }
4443 
4444  public RexRangeRef getSubQueryExpr(SqlCall call) {
4445  final SubQuery subQuery = getSubQuery(call);
4446  assert subQuery != null;
4447  return (RexRangeRef) subQuery.expr;
4448  }
4449 
4450  public RelDataTypeFactory getTypeFactory() {
4451  return typeFactory;
4452  }
4453 
4454  public InitializerExpressionFactory getInitializerExpressionFactory() {
4455  return initializerExpressionFactory;
4456  }
4457 
4458  public SqlValidator getValidator() {
4459  return validator;
4460  }
4461 
4462  public RexNode convertLiteral(SqlLiteral literal) {
4463  return exprConverter.convertLiteral(this, literal);
4464  }
4465 
4466  public RexNode convertInterval(SqlIntervalQualifier intervalQualifier) {
4467  return exprConverter.convertInterval(this, intervalQualifier);
4468  }
4469 
4470  public RexNode visit(SqlLiteral literal) {
4471  return exprConverter.convertLiteral(this, literal);
4472  }
4473 
4474  public RexNode visit(SqlCall call) {
4475  if (agg != null) {
4476  final SqlOperator op = call.getOperator();
4477  if (window == null
4478  && (op.isAggregator() || op.getKind() == SqlKind.FILTER
4479  || op.getKind() == SqlKind.WITHIN_GROUP)) {
4480  return agg.lookupAggregates(call);
4481  }
4482  }
4483  return exprConverter.convertCall(
4484  this, new SqlCallBinding(validator, scope, call).permutedCall());
4485  }
4486 
4487  public RexNode visit(SqlNodeList nodeList) {
4488  throw new UnsupportedOperationException();
4489  }
4490 
4491  public RexNode visit(SqlIdentifier id) {
4492  return convertIdentifier(this, id);
4493  }
4494 
4495  public RexNode visit(SqlDataTypeSpec type) {
4496  throw new UnsupportedOperationException();
4497  }
4498 
4499  public RexNode visit(SqlDynamicParam param) {
4500  return convertDynamicParam(param);
4501  }
4502 
4503  public RexNode visit(SqlIntervalQualifier intervalQualifier) {
4504  return convertInterval(intervalQualifier);
4505  }
4506 
4507  public List<SqlMonotonicity> getColumnMonotonicities() {
4508  return columnMonotonicities;
4509  }
4510  }
4511 
4512  private SqlQuantifyOperator negate(SqlQuantifyOperator operator) {
4513  assert operator.kind == SqlKind.ALL;
4514  return SqlStdOperatorTable.some(operator.comparisonKind.negateNullSafe());
4515  }
4516 
4518  private static class DeferredLookup {
4521 
4522  DeferredLookup(Blackboard bb, String originalRelName) {
4523  this.bb = bb;
4524  this.originalRelName = originalRelName;
4525  }
4526 
4527  public RexFieldAccess getFieldAccess(CorrelationId name) {
4528  return (RexFieldAccess) bb.mapCorrelateToRex.get(name);
4529  }
4530 
4532  return originalRelName;
4533  }
4534  }
4535 
4539  private class NoOpSubQueryConverter implements SubQueryConverter {
4540  public boolean canConvertSubQuery() {
4541  return false;
4542  }
4543 
4544  public RexNode convertSubQuery(SqlCall subQuery,
4545  SqlToRelConverter parentConverter,
4546  boolean isExists,
4547  boolean isExplain) {
4548  throw new IllegalArgumentException();
4549  }
4550  }
4551 
4571  protected class AggConverter implements SqlVisitor<Void> {
4572  private final Blackboard bb;
4573  public final AggregatingSelectScope aggregatingSelectScope;
4574 
4575  private final Map<String, String> nameMap = new HashMap<>();
4576 
4580  private final SqlNodeList groupExprs = new SqlNodeList(SqlParserPos.ZERO);
4581 
4585  private final Map<SqlNode, Ord<AuxiliaryConverter>> auxiliaryGroupExprs =
4586  new HashMap<>();
4587 
4595  private final List<Pair<RexNode, String>> convertedInputExprs = new ArrayList<>();
4596 
4603  private final List<AggregateCall> aggCalls = new ArrayList<>();
4604  private final Map<SqlNode, RexNode> aggMapping = new HashMap<>();
4605  private final Map<AggregateCall, RexNode> aggCallMapping = new HashMap<>();
4606 
4608  private boolean inOver = false;
4609 
4619  public AggConverter(Blackboard bb, SqlSelect select) {
4620  this.bb = bb;
4621  this.aggregatingSelectScope =
4622  (AggregatingSelectScope) bb.getValidator().getSelectScope(select);
4623 
4624  // Collect all expressions used in the select list so that aggregate
4625  // calls can be named correctly.
4626  final SqlNodeList selectList = select.getSelectList();
4627  for (int i = 0; i < selectList.size(); i++) {
4628  SqlNode selectItem = selectList.get(i);
4629  String name = null;
4630  if (SqlUtil.isCallTo(selectItem, SqlStdOperatorTable.AS)) {
4631  final SqlCall call = (SqlCall) selectItem;
4632  selectItem = call.operand(0);
4633  name = call.operand(1).toString();
4634  }
4635  if (name == null) {
4636  name = validator.deriveAlias(selectItem, i);
4637  }
4638  nameMap.put(selectItem.toString(), name);
4639  }
4640  }
4641 
4642  public int addGroupExpr(SqlNode expr) {
4643  int ref = lookupGroupExpr(expr);
4644  if (ref >= 0) {
4645  return ref;
4646  }
4647  final int index = groupExprs.size();
4648  groupExprs.add(expr);
4649  String name = nameMap.get(expr.toString());
4650  RexNode convExpr = bb.convertExpression(expr);
4651  addExpr(convExpr, name);
4652 
4653  if (expr instanceof SqlCall) {
4654  SqlCall call = (SqlCall) expr;
4655  for (Pair<SqlNode, AuxiliaryConverter> p :
4656  SqlStdOperatorTable.convertGroupToAuxiliaryCalls(call)) {
4657  addAuxiliaryGroupExpr(p.left, index, p.right);
4658  }
4659  }
4660 
4661  return index;
4662  }
4663 
4664  void addAuxiliaryGroupExpr(SqlNode node, int index, AuxiliaryConverter converter) {
4665  for (SqlNode node2 : auxiliaryGroupExprs.keySet()) {
4666  if (node2.equalsDeep(node, Litmus.IGNORE)) {
4667  return;
4668  }
4669  }
4670  auxiliaryGroupExprs.put(node, Ord.of(index, converter));
4671  }
4672 
4679  private void addExpr(RexNode expr, String name) {
4680  if ((name == null) && (expr instanceof RexInputRef)) {
4681  final int i = ((RexInputRef) expr).getIndex();
4682  name = bb.root.getRowType().getFieldList().get(i).getName();
4683  }
4684  if (Pair.right(convertedInputExprs).contains(name)) {
4685  // In case like 'SELECT ... GROUP BY x, y, x', don't add
4686  // name 'x' twice.
4687  name = null;
4688  }
4689  convertedInputExprs.add(Pair.of(expr, name));
4690  }
4691 
4692  public Void visit(SqlIdentifier id) {
4693  return null;
4694  }
4695 
4696  public Void visit(SqlNodeList nodeList) {
4697  for (int i = 0; i < nodeList.size(); i++) {
4698  nodeList.get(i).accept(this);
4699  }
4700  return null;
4701  }
4702 
4703  public Void visit(SqlLiteral lit) {
4704  return null;
4705  }
4706 
4707  public Void visit(SqlDataTypeSpec type) {
4708  return null;
4709  }
4710 
4711  public Void visit(SqlDynamicParam param) {
4712  return null;
4713  }
4714 
4715  public Void visit(SqlIntervalQualifier intervalQualifier) {
4716  return null;
4717  }
4718 
4719  public Void visit(SqlCall call) {
4720  switch (call.getKind()) {
4721  case FILTER:
4722  case WITHIN_GROUP:
4723  translateAgg(call);
4724  return null;
4725  case SELECT:
4726  // rchen 2006-10-17:
4727  // for now do not detect aggregates in sub-queries.
4728  return null;
4729  }
4730  final boolean prevInOver = inOver;
4731  // Ignore window aggregates and ranking functions (associated with OVER
4732  // operator). However, do not ignore nested window aggregates.
4733  if (call.getOperator().getKind() == SqlKind.OVER) {
4734  // Track aggregate nesting levels only within an OVER operator.
4735  List<SqlNode> operandList = call.getOperandList();
4736  assert operandList.size() == 2;
4737 
4738  // Ignore the top level window aggregates and ranking functions
4739  // positioned as the first operand of a OVER operator
4740  inOver = true;
4741  operandList.get(0).accept(this);
4742 
4743  // Normal translation for the second operand of a OVER operator
4744  inOver = false;
4745  operandList.get(1).accept(this);
4746  return null;
4747  }
4748 
4749  // Do not translate the top level window aggregate. Only do so for
4750  // nested aggregates, if present
4751  if (call.getOperator().isAggregator()) {
4752  if (inOver) {
4753  // Add the parent aggregate level before visiting its children
4754  inOver = false;
4755  } else {
4756  // We're beyond the one ignored level
4757  translateAgg(call);
4758  return null;
4759  }
4760  }
4761  for (SqlNode operand : call.getOperandList()) {
4762  // Operands are occasionally null, e.g. switched CASE arg 0.
4763  if (operand != null) {
4764  operand.accept(this);
4765  }
4766  }
4767  // Remove the parent aggregate level after visiting its children
4768  inOver = prevInOver;
4769  return null;
4770  }
4771 
4772  private void translateAgg(SqlCall call) {
4773  translateAgg(call, null, null, false, call);
4774  }
4775 
4776  private void translateAgg(SqlCall call,
4777  SqlNode filter,
4778  SqlNodeList orderList,
4779  boolean ignoreNulls,
4780  SqlCall outerCall) {
4781  assert bb.agg == this;
4782  assert outerCall != null;
4783  switch (call.getKind()) {
4784  case FILTER:
4785  assert filter == null;
4786  translateAgg(
4787  call.operand(0), call.operand(1), orderList, ignoreNulls, outerCall);
4788  return;
4789  case WITHIN_GROUP:
4790  assert orderList == null;
4791  translateAgg(call.operand(0), filter, call.operand(1), ignoreNulls, outerCall);
4792  return;
4793  case IGNORE_NULLS:
4794  ignoreNulls = true;
4795  // fall through
4796  case RESPECT_NULLS:
4797  translateAgg(call.operand(0), filter, orderList, ignoreNulls, outerCall);
4798  return;
4799  }
4800  final List<Integer> args = new ArrayList<>();
4801  int filterArg = -1;
4802  final List<RelDataType> argTypes = call.getOperator() instanceof SqlCountAggFunction
4803  ? new ArrayList<>(call.getOperandList().size())
4804  : null;
4805  try {
4806  // switch out of agg mode
4807  bb.agg = null;
4808  for (SqlNode operand : call.getOperandList()) {
4809  // special case for COUNT(*): delete the *
4810  if (operand instanceof SqlIdentifier) {
4811  SqlIdentifier id = (SqlIdentifier) operand;
4812  if (id.isStar()) {
4813  assert call.operandCount() == 1;
4814  assert args.isEmpty();
4815  break;
4816  }
4817  }
4818  RexNode convertedExpr = bb.convertExpression(operand);
4819  assert convertedExpr != null;
4820  if (argTypes != null) {
4821  argTypes.add(convertedExpr.getType());
4822  }
4823  args.add(lookupOrCreateGroupExpr(convertedExpr));
4824  }
4825 
4826  if (filter != null) {
4827  RexNode convertedExpr = bb.convertExpression(filter);
4828  assert convertedExpr != null;
4829  if (convertedExpr.getType().isNullable()) {
4830  convertedExpr =
4831  rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, convertedExpr);
4832  }
4833  filterArg = lookupOrCreateGroupExpr(convertedExpr);
4834  }
4835  } finally {
4836  // switch back into agg mode
4837  bb.agg = this;
4838  }
4839 
4840  SqlAggFunction aggFunction = (SqlAggFunction) call.getOperator();
4841  final RelDataType type = validator.deriveType(bb.scope, call);
4842  boolean distinct = false;
4843  SqlLiteral quantifier = call.getFunctionQuantifier();
4844  if ((null != quantifier) && (quantifier.getValue() == SqlSelectKeyword.DISTINCT)) {
4845  distinct = true;
4846  }
4847  boolean approximate = false;
4848  if (aggFunction == SqlStdOperatorTable.APPROX_COUNT_DISTINCT) {
4849  aggFunction = SqlStdOperatorTable.COUNT;
4850  distinct = true;
4851  approximate = true;
4852  }
4853  final RelCollation collation;
4854  if (orderList == null || orderList.size() == 0) {
4855  collation = RelCollations.EMPTY;
4856  } else {
4857  collation = RelCollations.of(
4858  orderList.getList()
4859  .stream()
4860  .map(order
4861  -> bb.convertSortExpression(order,
4862  RelFieldCollation.Direction.ASCENDING,
4863  RelFieldCollation.NullDirection.UNSPECIFIED))
4864  .map(fieldCollation
4865  -> new RelFieldCollation(
4866  lookupOrCreateGroupExpr(fieldCollation.left),
4867  fieldCollation.getDirection(),
4868  fieldCollation.getNullDirection()))
4869  .collect(Collectors.toList()));
4870  }
4871  final AggregateCall aggCall = AggregateCall.create(aggFunction,
4872  distinct,
4873  approximate,
4874  ignoreNulls,
4875  args,
4876  filterArg,
4877  collation,
4878  type,
4879  nameMap.get(outerCall.toString()));
4880  final AggregatingSelectScope.Resolved r = aggregatingSelectScope.resolved.get();
4881  RexNode rex = rexBuilder.addAggCall(
4882  aggCall, groupExprs.size(), aggCalls, aggCallMapping, argTypes);
4883  aggMapping.put(outerCall, rex);
4884  }
4885 
4886  private int lookupOrCreateGroupExpr(RexNode expr) {
4887  int index = 0;
4888  for (RexNode convertedInputExpr : Pair.left(convertedInputExprs)) {
4889  if (expr.equals(convertedInputExpr)) {
4890  return index;
4891  }
4892  ++index;
4893  }
4894 
4895  // not found -- add it
4896  addExpr(expr, null);
4897  return index;
4898  }
4899 
4905  public int lookupGroupExpr(SqlNode expr) {
4906  for (int i = 0; i < groupExprs.size(); i++) {
4907  SqlNode groupExpr = groupExprs.get(i);
4908  if (expr.equalsDeep(groupExpr, Litmus.IGNORE)) {
4909  return i;
4910  }
4911  }
4912  return -1;
4913  }
4914 
4915  public RexNode lookupAggregates(SqlCall call) {
4916  // assert call.getOperator().isAggregator();
4917  assert bb.agg == this;
4918 
4919  for (Map.Entry<SqlNode, Ord<AuxiliaryConverter>> e :
4920  auxiliaryGroupExprs.entrySet()) {
4921  if (call.equalsDeep(e.getKey(), Litmus.IGNORE)) {
4922  AuxiliaryConverter converter = e.getValue().e;
4923  final int groupOrdinal = e.getValue().i;
4924  return converter.convert(rexBuilder,
4925  convertedInputExprs.get(groupOrdinal).left,
4926  rexBuilder.makeInputRef(bb.root, groupOrdinal));
4927  }
4928  }
4929 
4930  return aggMapping.get(call);
4931  }
4932 
4933  public List<Pair<RexNode, String>> getPreExprs() {
4934  return convertedInputExprs;
4935  }
4936 
4937  public List<AggregateCall> getAggCalls() {
4938  return aggCalls;
4939  }
4940 
4941  public RelDataTypeFactory getTypeFactory() {
4942  return typeFactory;
4943  }
4944  }
4945 
4949  private static class LookupContext {
4950  private final List<Pair<RelNode, Integer>> relOffsetList = new ArrayList<>();
4951 
4959  LookupContext(Blackboard bb, List<RelNode> rels, int systemFieldCount) {
4960  bb.flatten(rels, systemFieldCount, new int[] {0}, relOffsetList);
4961  }
4962 
4975  Pair<RelNode, Integer> findRel(int offset) {
4976  return relOffsetList.get(offset);
4977  }
4978  }
4979 
5007  private class HistogramShuttle extends RexShuttle {
5012  static final boolean ENABLE_HISTOGRAM_AGG = false;
5013 
5014  private final List<RexNode> partitionKeys;
5015  private final ImmutableList<RexFieldCollation> orderKeys;
5016  private final RexWindowBound lowerBound;
5017  private final RexWindowBound upperBound;
5018  private final SqlWindow window;
5019  private final boolean distinct;
5020  private final boolean ignoreNulls;
5021 
5022  HistogramShuttle(List<RexNode> partitionKeys,
5023  ImmutableList<RexFieldCollation> orderKeys,
5024  RexWindowBound lowerBound,
5025  RexWindowBound upperBound,
5026  SqlWindow window,
5027  boolean distinct,
5028  boolean ignoreNulls) {
5029  this.partitionKeys = partitionKeys;
5030  this.orderKeys = orderKeys;
5031  this.lowerBound = lowerBound;
5032  this.upperBound = upperBound;
5033  this.window = window;
5034  this.distinct = distinct;
5035  this.ignoreNulls = ignoreNulls;
5036  }
5037 
5038  public RexNode visitCall(RexCall call) {
5039  final SqlOperator op = call.getOperator();
5040  if (!(op instanceof SqlAggFunction)) {
5041  return super.visitCall(call);
5042  }
5043  final SqlAggFunction aggOp = (SqlAggFunction) op;
5044  final RelDataType type = call.getType();
5045  List<RexNode> exprs = call.getOperands();
5046 
5047  SqlFunction histogramOp = !ENABLE_HISTOGRAM_AGG ? null : getHistogramOp(aggOp);
5048 
5049  if (histogramOp != null) {
5050  final RelDataType histogramType = computeHistogramType(type);
5051 
5052  // For DECIMAL, since it's already represented as a bigint we
5053  // want to do a reinterpretCast instead of a cast to avoid
5054  // losing any precision.
5055  boolean reinterpretCast = type.getSqlTypeName() == SqlTypeName.DECIMAL;
5056 
5057  // Replace original expression with CAST of not one
5058  // of the supported types
5059  if (histogramType != type) {
5060  exprs = new ArrayList<>(exprs);
5061  exprs.set(0,
5062  reinterpretCast ? rexBuilder.makeReinterpretCast(
5063  histogramType, exprs.get(0), rexBuilder.makeLiteral(false))
5064  : rexBuilder.makeCast(histogramType, exprs.get(0)));
5065  }
5066 
5067  RexCallBinding bind = new RexCallBinding(rexBuilder.getTypeFactory(),
5068  SqlStdOperatorTable.HISTOGRAM_AGG,
5069  exprs,
5070  ImmutableList.of());
5071 
5072  RexNode over = rexBuilder.makeOver(
5073  SqlStdOperatorTable.HISTOGRAM_AGG.inferReturnType(bind),
5074  SqlStdOperatorTable.HISTOGRAM_AGG,
5075  exprs,
5076  partitionKeys,
5077  orderKeys,
5078  lowerBound,
5079  upperBound,
5080  window.isRows(),
5081  window.isAllowPartial(),
5082  false,
5083  distinct,
5084  ignoreNulls);
5085 
5086  RexNode histogramCall =
5087  rexBuilder.makeCall(histogramType, histogramOp, ImmutableList.of(over));
5088 
5089  // If needed, post Cast result back to original
5090  // type.
5091  if (histogramType != type) {
5092  if (reinterpretCast) {
5093  histogramCall = rexBuilder.makeReinterpretCast(
5094  type, histogramCall, rexBuilder.makeLiteral(false));
5095  } else {
5096  histogramCall = rexBuilder.makeCast(type, histogramCall);
5097  }
5098  }
5099 
5100  return histogramCall;
5101  } else {
5102  boolean needSum0 = aggOp == SqlStdOperatorTable.SUM && type.isNullable();
5103  SqlAggFunction aggOpToUse = needSum0 ? SqlStdOperatorTable.SUM0 : aggOp;
5104  return rexBuilder.makeOver(type,
5105  aggOpToUse,
5106  exprs,
5107  partitionKeys,
5108  orderKeys,
5109  lowerBound,
5110  upperBound,
5111  window.isRows(),
5112  window.isAllowPartial(),
5113  needSum0,
5114  distinct,
5115  ignoreNulls);
5116  }
5117  }
5118 
5130  SqlFunction getHistogramOp(SqlAggFunction aggFunction) {
5131  if (aggFunction == SqlStdOperatorTable.MIN) {
5132  return SqlStdOperatorTable.HISTOGRAM_MIN;
5133  } else if (aggFunction == SqlStdOperatorTable.MAX) {
5134  return SqlStdOperatorTable.HISTOGRAM_MAX;
5135  } else if (aggFunction == SqlStdOperatorTable.FIRST_VALUE) {
5136  return SqlStdOperatorTable.HISTOGRAM_FIRST_VALUE;
5137  } else if (aggFunction == SqlStdOperatorTable.LAST_VALUE) {
5138  return SqlStdOperatorTable.HISTOGRAM_LAST_VALUE;
5139  } else {
5140  return null;
5141  }
5142  }
5143 
5148  private RelDataType computeHistogramType(RelDataType type) {
5149  if (SqlTypeUtil.isExactNumeric(type)
5150  && type.getSqlTypeName() != SqlTypeName.BIGINT) {
5151  return typeFactory.createSqlType(SqlTypeName.BIGINT);
5152  } else if (SqlTypeUtil.isApproximateNumeric(type)
5153  && type.getSqlTypeName() != SqlTypeName.DOUBLE) {
5154  return typeFactory.createSqlType(SqlTypeName.DOUBLE);
5155  } else {
5156  return type;
5157  }
5158  }
5159  }
5160 
5165  private static class SubQuery {
5166  final SqlNode node;
5167  final RelOptUtil.Logic logic;
5168  RexNode expr;
5169 
5170  private SubQuery(SqlNode node, RelOptUtil.Logic logic) {
5171  this.node = node;
5172  this.logic = logic;
5173  }
5174  }
5175 
5179  private static class AggregateFinder extends SqlBasicVisitor<Void> {
5180  final SqlNodeList list = new SqlNodeList(SqlParserPos.ZERO);
5181  final SqlNodeList filterList = new SqlNodeList(SqlParserPos.ZERO);
5182  final SqlNodeList orderList = new SqlNodeList(SqlParserPos.ZERO);
5183 
5184  @Override
5185  public Void visit(SqlCall call) {
5186  // ignore window aggregates and ranking functions (associated with OVER operator)
5187  if (call.getOperator().getKind() == SqlKind.OVER) {
5188  return null;
5189  }
5190 
5191  if (call.getOperator().getKind() == SqlKind.FILTER) {
5192  // the WHERE in a FILTER must be tracked too so we can call replaceSubQueries on
5193  // it. see https://issues.apache.org/jira/browse/CALCITE-1910
5194  final SqlNode aggCall = call.getOperandList().get(0);
5195  final SqlNode whereCall = call.getOperandList().get(1);
5196  list.add(aggCall);
5197  filterList.add(whereCall);
5198  return null;
5199  }
5200 
5201  if (call.getOperator().getKind() == SqlKind.WITHIN_GROUP) {
5202  // the WHERE in a WITHIN_GROUP must be tracked too so we can call
5203  // replaceSubQueries on it. see https://issues.apache.org/jira/browse/CALCITE-1910
5204  final SqlNode aggCall = call.getOperandList().get(0);
5205  final SqlNodeList orderList = (SqlNodeList) call.getOperandList().get(1);
5206  list.add(aggCall);
5207  orderList.getList().forEach(this.orderList::add);
5208  return null;
5209  }
5210 
5211  if (call.getOperator().isAggregator()) {
5212  list.add(call);
5213  return null;
5214  }
5215 
5216  // Don't traverse into sub-queries, even if they contain aggregate
5217  // functions.
5218  if (call instanceof SqlSelect) {
5219  return null;
5220  }
5221 
5222  return call.getOperator().acceptCall(this, call);
5223  }
5224  }
5225 
5230  private static class CorrelationUse {
5231  private final CorrelationId id;
5232  private final ImmutableBitSet requiredColumns;
5234  private final RelNode r;
5235 
5236  CorrelationUse(CorrelationId id, ImmutableBitSet requiredColumns, RelNode r) {
5237  this.id = id;
5238  this.requiredColumns = requiredColumns;
5239  this.r = r;
5240  }
5241  }
5242 
5244  public static ConfigBuilder configBuilder() {
5245  return new ConfigBuilder();
5246  }
5247 
5255  public interface Config {
5257  Config DEFAULT = configBuilder().build();
5258 
5267  boolean isConvertTableAccess();
5268 
5274  boolean isDecorrelationEnabled();
5275 
5280  boolean isTrimUnusedFields();
5281 
5287  boolean isCreateValuesRel();
5288 
5293  boolean isExplain();
5294 
5300  boolean isExpand();
5301 
5312  int getInSubQueryThreshold();
5313 
5318  RelBuilderFactory getRelBuilderFactory();
5319  }
5320 
5322  public static class ConfigBuilder {
5323  private boolean convertTableAccess = true;
5324  private boolean decorrelationEnabled = true;
5325  private boolean trimUnusedFields = false;
5326  private boolean createValuesRel = true;
5327  private boolean explain;
5328  private boolean expand = true;
5329  private int inSubQueryThreshold = DEFAULT_IN_SUB_QUERY_THRESHOLD;
5330  private RelBuilderFactory relBuilderFactory = RelFactories.LOGICAL_BUILDER;
5331 
5332  private ConfigBuilder() {}
5333 
5336  this.convertTableAccess = config.isConvertTableAccess();
5337  this.decorrelationEnabled = config.isDecorrelationEnabled();
5338  this.trimUnusedFields = config.isTrimUnusedFields();
5339  this.createValuesRel = config.isCreateValuesRel();
5340  this.explain = config.isExplain();
5341  this.expand = config.isExpand();
5342  this.inSubQueryThreshold = config.getInSubQueryThreshold();
5343  this.relBuilderFactory = config.getRelBuilderFactory();
5344  return this;
5345  }
5346 
5347  public ConfigBuilder withConvertTableAccess(boolean convertTableAccess) {
5348  this.convertTableAccess = convertTableAccess;
5349  return this;
5350  }
5351 
5352  public ConfigBuilder withDecorrelationEnabled(boolean enabled) {
5353  this.decorrelationEnabled = enabled;
5354  return this;
5355  }
5356 
5357  public ConfigBuilder withTrimUnusedFields(boolean trimUnusedFields) {
5358  this.trimUnusedFields = trimUnusedFields;
5359  return this;
5360  }
5361 
5362  public ConfigBuilder withCreateValuesRel(boolean createValuesRel) {
5363  this.createValuesRel = createValuesRel;
5364  return this;
5365  }
5366 
5367  public ConfigBuilder withExplain(boolean explain) {
5368  this.explain = explain;
5369  return this;
5370  }
5371 
5372  public ConfigBuilder withExpand(boolean expand) {
5373  this.expand = expand;
5374  return this;
5375  }
5376 
5377  @Deprecated // to be removed before 2.0
5378  public ConfigBuilder withInSubqueryThreshold(int inSubQueryThreshold) {
5379  return withInSubQueryThreshold(inSubQueryThreshold);
5380  }
5381 
5382  public ConfigBuilder withInSubQueryThreshold(int inSubQueryThreshold) {
5383  this.inSubQueryThreshold = inSubQueryThreshold;
5384  return this;
5385  }
5386 
5387  public ConfigBuilder withRelBuilderFactory(RelBuilderFactory relBuilderFactory) {
5388  this.relBuilderFactory = relBuilderFactory;
5389  return this;
5390  }
5391 
5393  public Config build() {
5394  return new ConfigImpl(convertTableAccess,
5395  decorrelationEnabled,
5396  trimUnusedFields,
5397  createValuesRel,
5398  explain,
5399  expand,
5400  inSubQueryThreshold,
5401  relBuilderFactory);
5402  }
5403  }
5404 
5409  private static class ConfigImpl implements Config {
5410  private final boolean convertTableAccess;
5411  private final boolean decorrelationEnabled;
5412  private final boolean trimUnusedFields;
5413  private final boolean createValuesRel;
5414  private final boolean explain;
5415  private final boolean expand;
5416  private final int inSubQueryThreshold;
5417  private final RelBuilderFactory relBuilderFactory;
5418 
5419  private ConfigImpl(boolean convertTableAccess,
5420  boolean decorrelationEnabled,
5421  boolean trimUnusedFields,
5422  boolean createValuesRel,
5423  boolean explain,
5424  boolean expand,
5425  int inSubQueryThreshold,
5426  RelBuilderFactory relBuilderFactory) {
5427  this.convertTableAccess = convertTableAccess;
5428  this.decorrelationEnabled = decorrelationEnabled;
5429  this.trimUnusedFields = trimUnusedFields;
5430  this.createValuesRel = createValuesRel;
5431  this.explain = explain;
5432  this.expand = expand;
5433  this.inSubQueryThreshold = inSubQueryThreshold;
5434  this.relBuilderFactory = relBuilderFactory;
5435  }
5436 
5437  public boolean isConvertTableAccess() {
5438  return convertTableAccess;
5439  }
5440 
5441  public boolean isDecorrelationEnabled() {
5442  return decorrelationEnabled;
5443  }
5444 
5445  public boolean isTrimUnusedFields() {
5446  return trimUnusedFields;
5447  }
5448 
5449  public boolean isCreateValuesRel() {
5450  return createValuesRel;
5451  }
5452 
5453  public boolean isExplain() {
5454  return explain;
5455  }
5456 
5457  public boolean isExpand() {
5458  return expand;
5459  }
5460 
5461  public int getInSubQueryThreshold() {
5462  return inSubQueryThreshold;
5463  }
5464 
5465  public RelBuilderFactory getRelBuilderFactory() {
5466  return relBuilderFactory;
5467  }
5468  }
5469 }
5470 
5471 // End SqlToRelConverter.java
RelRoot convertWith(SqlWith with, boolean top)
void snapshotTemporalTable(Blackboard bb, SqlCall call)
SqlQuantifyOperator negate(SqlQuantifyOperator operator)
JoinType
Definition: sqldefs.h:98
void setDynamicParamCountInExplain(int explainParamCount)
static SqlNode pushDownNotForIn(SqlValidatorScope scope, SqlNode sqlNode)
HistogramShuttle(List< RexNode > partitionKeys, ImmutableList< RexFieldCollation > orderKeys, RexWindowBound lowerBound, RexWindowBound upperBound, SqlWindow window, boolean distinct, boolean ignoreNulls)
void extraSelectItems(Blackboard bb, SqlSelect select, List< RexNode > exprList, List< String > nameList, Collection< String > aliasList, List< SqlMonotonicity > columnMonotonicityList)
void addAuxiliaryGroupExpr(SqlNode node, int index, AuxiliaryConverter converter)
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)
ConfigBuilder withCreateValuesRel(boolean createValuesRel)
RexNode translateIn(RelOptUtil.Logic logic, RelNode root, final RexNode rex)
void c(const std::string &query_string, const ExecutorDeviceType device_type)
RelNode convertCursor(Blackboard bb, SubQuery subQuery)
const std::vector< std::shared_ptr< TestColumnDescriptor > > ALL
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)
RexFieldCollation convertSortExpression(SqlNode expr, RelFieldCollation.Direction direction, RelFieldCollation.NullDirection nullDirection)
Void visit(SqlIntervalQualifier intervalQualifier)
void afterTableFunction(SqlToRelConverter.Blackboard bb, SqlCall call, LogicalTableFunctionScan callRel)
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)
ConfigBuilder withRelBuilderFactory(RelBuilderFactory relBuilderFactory)
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
void flatten(List< RelNode > rels, int systemFieldCount, int[] start, List< Pair< RelNode, Integer >> relOffsetList)
final Map< SqlNode, RexNode > mapConvertedNonCorrSubqs
RexLiteral convertLiteralInValuesList(SqlNode sqlNode, Blackboard bb, RelDataType rowType, int iField)
RexNode lookup(int offset, LookupContext lookupContext)
ConfigBuilder withInSubqueryThreshold(int inSubQueryThreshold)
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)
void convertIdentifier(Blackboard bb, SqlIdentifier id, SqlNodeList extendedColumns)
LookupContext(Blackboard bb, List< RelNode > rels, int systemFieldCount)
ConfigBuilder withInSubQueryThreshold(int inSubQueryThreshold)
ConfigBuilder withTrimUnusedFields(boolean trimUnusedFields)
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)
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)
static SqlNode reg(SqlValidatorScope scope, SqlNode e)
RexNode visit(SqlIntervalQualifier intervalQualifier)
boolean convertNonCorrelatedSubQuery(SubQuery subQuery, Blackboard bb, RelNode converted, boolean isExists)
void findSubQueries(Blackboard bb, SqlNode node, RelOptUtil.Logic logic, boolean registerOnlyScalarSubQueries)
ConfigImpl(boolean convertTableAccess, boolean decorrelationEnabled, boolean trimUnusedFields, boolean createValuesRel, boolean explain, boolean expand, int inSubQueryThreshold, RelBuilderFactory relBuilderFactory)
Pair< RexNode, Map< String, Integer > > lookupExp(SqlQualified qualified)
boolean isSubQueryNonCorrelated(RelNode subq, Blackboard bb)
RexNode convertInterval(SqlIntervalQualifier intervalQualifier)
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)