danny0405 commented on a change in pull request #1374: [CALCITE-3138]
RelStructuredTypeFlattener doesn't restructure ROW type fields
URL: https://github.com/apache/calcite/pull/1374#discussion_r314715318
##########
File path:
core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
##########
@@ -587,86 +561,103 @@ private void flattenProjections(RewriteRexShuttle
shuttle,
List<Pair<RexNode, String>> flattenedExps) {
for (int i = 0; i < exps.size(); ++i) {
RexNode exp = exps.get(i);
- String fieldName =
- (fieldNames == null || fieldNames.get(i) == null)
- ? ("$" + i)
- : fieldNames.get(i);
- if (!prefix.equals("")) {
- fieldName = prefix + "$" + fieldName;
- }
+ String fieldName = extractName(fieldNames, prefix, i);
flattenProjection(shuttle, exp, fieldName, flattenedExps);
}
}
+ private String extractName(List<String> fieldNames, String prefix, int i) {
+ String fieldName = (fieldNames == null || fieldNames.get(i) == null)
+ ? ("$" + i)
+ : fieldNames.get(i);
+ if (!prefix.equals("")) {
+ fieldName = prefix + "$" + fieldName;
+ }
+ return fieldName;
+ }
+
private void flattenProjection(RewriteRexShuttle shuttle,
RexNode exp,
String fieldName,
List<Pair<RexNode, String>> flattenedExps) {
if (exp.getType().isStruct()) {
if (exp instanceof RexInputRef) {
- RexInputRef inputRef = (RexInputRef) exp;
-
- // expand to range
- RelDataType flattenedType =
- SqlTypeUtil.flattenRecordType(
- rexBuilder.getTypeFactory(),
- exp.getType(),
- null);
- List<RelDataTypeField> fieldList = flattenedType.getFieldList();
- int n = fieldList.size();
- for (int j = 0; j < n; ++j) {
- final Ord<RelDataType> newField =
- getNewFieldForOldInput(inputRef.getIndex(), j);
- flattenedExps.add(
- Pair.of(new RexInputRef(newField.i, newField.e),
- fieldName));
+ final int oldOrdinal = ((RexInputRef) exp).getIndex();
+ final int flattenFieldsCount = postFlattenSize(exp.getType());
+ for (int innerOrdinal = 0; innerOrdinal < flattenFieldsCount;
innerOrdinal++) {
+ Ord<RelDataType> newField = getNewFieldForOldInput(oldOrdinal,
innerOrdinal);
+ RexInputRef newRef = new RexInputRef(newField.i, newField.e);
+ flattenedExps.add(Pair.of(newRef, fieldName));
}
} else if (isConstructor(exp) || exp.isA(SqlKind.CAST)) {
// REVIEW jvs 27-Feb-2005: for cast, see corresponding note
// in RewriteRexShuttle
RexCall call = (RexCall) exp;
- if (exp.isA(SqlKind.NEW_SPECIFICATION)) {
- // For object constructors, prepend a FALSE null
- // indicator.
- flattenedExps.add(
- Pair.of(rexBuilder.makeLiteral(false),
- fieldName));
- } else if (exp.isA(SqlKind.CAST)) {
- if (RexLiteral.isNullLiteral(
- ((RexCall) exp).operands.get(0))) {
- // Translate CAST(NULL AS UDT) into
- // the correct number of null fields.
- flattenNullLiteral(
- exp.getType(),
- flattenedExps);
- return;
- }
+ if (exp.isA(SqlKind.CAST)
+ && RexLiteral.isNullLiteral(call.operands.get(0))) {
+ // Translate CAST(NULL AS UDT) into
+ // the correct number of null fields.
+ flattenNullLiteral(exp.getType(), flattenedExps);
+ return;
}
- flattenProjections(new RewriteRexShuttle(),
+ flattenProjections(shuttle,
call.getOperands(),
Collections.nCopies(call.getOperands().size(), null),
fieldName,
flattenedExps);
} else if (exp instanceof RexCall) {
// NOTE jvs 10-Feb-2005: This is a lame hack to keep special
// functions which return row types working.
-
- int j = 0;
RexNode newExp = exp;
- List<RexNode> oldOperands = ((RexCall) exp).getOperands();
- if (oldOperands.get(0) instanceof RexInputRef) {
- final RexInputRef inputRef = (RexInputRef) oldOperands.get(0);
- final Ord<RelDataType> newField =
- getNewFieldForOldInput(inputRef.getIndex());
- newExp = rexBuilder.makeCall(exp.getType(),
- ((RexCall) exp).getOperator(),
- ImmutableList.of(rexBuilder.makeInputRef(newField.e, newField.i),
- oldOperands.get(1)));
- }
- for (RelDataTypeField field : newExp.getType().getFieldList()) {
- flattenedExps.add(
- Pair.of(rexBuilder.makeFieldAccess(newExp, field.getIndex()),
- fieldName + "$" + (j++)));
+ List<RexNode> operands = ((RexCall) exp).getOperands();
+ SqlOperator operator = ((RexCall) exp).getOperator();
+
+ if (operator == SqlStdOperatorTable.ITEM
+ && operands.get(0).getType().isStruct()
+ && operands.get(1).isA(SqlKind.LITERAL)
+ && SqlTypeUtil.inCharFamily(operands.get(1).getType())) {
+ String literalString = ((RexLiteral)
operands.get(1)).getValueAs(String.class);
+ RexNode firstOp = operands.get(0);
+
+ if (firstOp instanceof RexInputRef) {
+ // when performed getting field from struct exp by field name
+ // and new input is flattened it's enough to refer target field by
index.
+ // But it's possible that requested field is also of type struct,
that's
+ // why we're trying to get range from to. For primitive just one
field will be in range.
+ int from = 0;
+ for (RelDataTypeField field : firstOp.getType().getFieldList()) {
+ if (literalString.equalsIgnoreCase(field.getName())) {
+ int oldOrdinal = ((RexInputRef) firstOp).getIndex();
+ int to = from + postFlattenSize(field.getType());
+ for (int newInnerOrdinal = from; newInnerOrdinal < to;
newInnerOrdinal++) {
+ Ord<RelDataType> newField =
getNewFieldForOldInput(oldOrdinal, newInnerOrdinal);
+ RexInputRef newRef = rexBuilder.makeInputRef(newField.e,
newField.i);
+ flattenedExps.add(Pair.of(newRef, fieldName));
+ }
+ break;
+ } else {
+ from += postFlattenSize(field.getType());
+ }
+ }
+ } else if (firstOp instanceof RexCall) {
+ // to get nested struct from return type of firstOp rex call,
+ // we need to flatten firstOp and get range of expressions which
+ // corresponding to desirable nested struct flattened fields
+ List<Pair<RexNode, String>> firstOpFlattenedExps = new
ArrayList<>();
+ flattenProjection(shuttle, firstOp, fieldName,
firstOpFlattenedExps);
+ int newInnerOrdinal = getNewInnerOrdinal(firstOp, literalString);
Review comment:
It does not seem right we still passed in the `fieldName ` which is the name
of the `exp` but not the `firstOp` which does not have a explicit name.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services