OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HeavyDBRelJsonWriter.java
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.apache.calcite.rel.externalize;
18 
19 import com.google.common.collect.ImmutableList;
20 
21 import org.apache.calcite.rel.RelNode;
22 import org.apache.calcite.rel.RelWriter;
23 import org.apache.calcite.rel.core.TableScan;
24 import org.apache.calcite.rel.hint.RelHint;
25 import org.apache.calcite.rel.logical.*;
26 import org.apache.calcite.rel.type.RelDataType;
27 import org.apache.calcite.sql.SqlExplainLevel;
29 import org.apache.calcite.util.Pair;
30 
31 import java.util.*;
32 import java.util.stream.Collectors;
33 
39 public class HeavyDBRelJsonWriter implements RelWriter {
40  // ~ Instance fields ----------------------------------------------------------
41 
43  private final HeavyDBRelJson relJson;
44  private final Map<RelNode, String> relIdMap = new IdentityHashMap<RelNode, String>();
45  private final List<Object> relList;
46  private final List<Pair<String, Object>> values = new ArrayList<Pair<String, Object>>();
47  private String previousId;
48 
49  // ~ Constructors -------------------------------------------------------------
50 
53  relList = jsonBuilder.list();
55  }
56 
57  // ~ Methods ------------------------------------------------------------------
58 
59  protected void explain_(RelNode rel, List<Pair<String, Object>> values) {
60  final Map<String, Object> map = jsonBuilder.map();
61 
62  map.put("id", null); // ensure that id is the first attribute
63  map.put("relOp", relJson.classToTypeName(rel.getClass()));
64  if (rel instanceof TableScan) {
65  RelDataType row_type = ((TableScan) rel).getTable().getRowType();
66  List<String> field_names = row_type.getFieldNames();
67  map.put("fieldNames", field_names);
68  }
69  if (rel instanceof LogicalAggregate) {
70  map.put("fields", rel.getRowType().getFieldNames());
71  }
72  if (rel instanceof LogicalTableModify) {
73  // FIX-ME: What goes here?
74  }
75 
76  // handle hints
77  if (deliverHints(rel)) {
78  map.put("hints", explainHints(rel));
79  }
80 
81  for (Pair<String, Object> value : values) {
82  if (value.right instanceof RelNode) {
83  continue;
84  }
85  put(map, value.left, value.right);
86  }
87  // omit 'inputs: ["3"]' if "3" is the preceding rel
88  final List<Object> list = explainInputs(rel.getInputs());
89  if (list.size() != 1 || !list.get(0).equals(previousId)) {
90  map.put("inputs", list);
91  }
92 
93  final String id = Integer.toString(relIdMap.size());
94  relIdMap.put(rel, id);
95  map.put("id", id);
96 
97  relList.add(map);
98  previousId = id;
99  }
100 
101  private void put(Map<String, Object> map, String name, Object value) {
102  map.put(name, relJson.toJson(value));
103  }
104 
105  private List<Object> explainInputs(List<RelNode> inputs) {
106  final List<Object> list = jsonBuilder.list();
107  for (RelNode input : inputs) {
108  String id = relIdMap.get(input);
109  if (id == null) {
110  input.explain(this);
111  id = previousId;
112  }
113  list.add(id);
114  }
115  return list;
116  }
117 
118  private boolean deliverHints(RelNode rel) {
119  if (rel instanceof LogicalTableScan) {
120  LogicalTableScan node = (LogicalTableScan) rel;
121  if (!node.getHints().isEmpty()) {
122  return true;
123  } else {
124  return false;
125  }
126  } else if (rel instanceof LogicalAggregate) {
127  LogicalAggregate node = (LogicalAggregate) rel;
128  if (!node.getHints().isEmpty()) {
129  return true;
130  } else {
131  return false;
132  }
133  } else if (rel instanceof LogicalJoin) {
134  LogicalJoin node = (LogicalJoin) rel;
135  if (!node.getHints().isEmpty()) {
136  return true;
137  } else {
138  return false;
139  }
140  } else if (rel instanceof LogicalProject) {
141  LogicalProject node = (LogicalProject) rel;
142  if (!node.getHints().isEmpty()) {
143  return true;
144  } else {
145  return false;
146  }
147  } else if (rel instanceof LogicalCalc) {
148  LogicalCalc node = (LogicalCalc) rel;
149  if (!node.getHints().isEmpty()) {
150  return true;
151  } else {
152  return false;
153  }
154  }
155  return false;
156  }
157 
158  private String explainHints(RelNode rel) {
159  List<String> explained = new ArrayList<>();
160  if (rel instanceof LogicalTableScan) {
161  LogicalTableScan node = (LogicalTableScan) rel;
162  node.getHints().stream().forEach(s -> explained.add(s.toString().toLowerCase()));
163  } else if (rel instanceof LogicalAggregate) {
164  LogicalAggregate node = (LogicalAggregate) rel;
165  node.getHints().stream().forEach(s -> explained.add(s.toString().toLowerCase()));
166  } else if (rel instanceof LogicalJoin) {
167  LogicalJoin node = (LogicalJoin) rel;
168  node.getHints().stream().forEach(s -> explained.add(s.toString().toLowerCase()));
169  } else if (rel instanceof LogicalProject) {
170  LogicalProject node = (LogicalProject) rel;
171  node.getHints().stream().forEach(s -> explained.add(s.toString().toLowerCase()));
172  } else if (rel instanceof LogicalCalc) {
173  LogicalCalc node = (LogicalCalc) rel;
174  node.getHints().stream().forEach(s -> explained.add(s.toString().toLowerCase()));
175  }
176  return explained.stream().collect(Collectors.joining("|"));
177  }
178 
179  public final void explain(RelNode rel, List<Pair<String, Object>> valueList) {
180  explain_(rel, valueList);
181  }
182 
183  public SqlExplainLevel getDetailLevel() {
184  return SqlExplainLevel.ALL_ATTRIBUTES;
185  }
186 
187  public RelWriter input(String term, RelNode input) {
188  return this;
189  }
190 
191  public RelWriter item(String term, Object value) {
192  values.add(Pair.of(term, value));
193  return this;
194  }
195 
196  private List<Object> getList(List<Pair<String, Object>> values, String tag) {
197  for (Pair<String, Object> value : values) {
198  if (value.left.equals(tag)) {
199  // noinspection unchecked
200  return (List<Object>) value.right;
201  }
202  }
203  final List<Object> list = new ArrayList<Object>();
204  values.add(Pair.of(tag, (Object) list));
205  return list;
206  }
207 
208  public RelWriter itemIf(String term, Object value, boolean condition) {
209  if (condition) {
210  item(term, value);
211  }
212  return this;
213  }
214 
215  public RelWriter done(RelNode node) {
216  final List<Pair<String, Object>> valuesCopy = ImmutableList.copyOf(values);
217  values.clear();
218  explain_(node, valuesCopy);
219  return this;
220  }
221 
222  public boolean nest() {
223  return true;
224  }
225 
230  public String asString() {
231  return jsonBuilder.toJsonString(asJsonMap());
232  }
233 
234  public Map<String, Object> asJsonMap() {
235  final Map<String, Object> map = jsonBuilder.map();
236  map.put("rels", relList);
237  return map;
238  }
239 }
240 
241 // End RelJsonWriter.java
RelWriter itemIf(String term, Object value, boolean condition)
void explain_(RelNode rel, List< Pair< String, Object >> values)
final void explain(RelNode rel, List< Pair< String, Object >> valueList)
string name
Definition: setup.in.py:72
List< Object > getList(List< Pair< String, Object >> values, String tag)
void put(Map< String, Object > map, String name, Object value)