docs: public final NodeSchema getTrueOutputSchema(boolean resetBack) throws PlanningErrorException {
          AbstractPlanNode child;
          NodeSchema answer = null;
          //
          // Note: This code is translated from the C++ code in
          //       AbstractPlanNode::getOutputSchema.  It's considerably
          //       different there, but I think this has the corner
          //       cases covered correctly.
          for (child = this;
                  child != null;
                  child = (child.getChildCount() == 0) ? null : child.getChild(0)) {
              NodeSchema childSchema;
              if (child.m_hasSignificantOutputSchema) {
                  childSchema = child.getOutputSchema();
                  assert(childSchema != null);
                  answer = childSchema;
                  break;
              }
              AbstractPlanNode childProj = child.getInlinePlanNode(PlanNodeType.PROJECTION);
              if (childProj != null) {
                  AbstractPlanNode schemaSrc = null;
                  AbstractPlanNode inlineInsertNode = childProj.getInlinePlanNode(PlanNodeType.INSERT);
                  if (inlineInsertNode != null) {
                      schemaSrc = inlineInsertNode;
                  } else {
                      schemaSrc = childProj;
                  }
                  childSchema = schemaSrc.getOutputSchema();
                  if (childSchema != null) {
                      answer = childSchema;
                      break;
                  }
              }
          }
          if (child == null) {
              // We've gone to the end of the plan.  This is a
              // failure in the EE.
              assert(false);
              throw new PlanningErrorException("AbstractPlanNode with no true output schema.  Please notify VoltDB Support.");
          }
          // Trace back the chain of parents and reset the
          // output schemas of the parent.  These will all be
          // exactly the same.  Note that the source of the
          // schema may be an inline plan node.  So we need
          // to set the child's output schema to be the answer.
          // If the schema source is the child node itself, this will
          // set the the output schema to itself, so no harm
          // will be done.
          if (resetBack) {
              do {
                  if (child instanceof AbstractJoinPlanNode) {
                      // In joins with inlined aggregation, the inlined
                      // aggregate node is the one that determines the schema.
                      // (However, the enclosing join node still has its
                      // "m_hasSignificantOutputSchema" bit set.)
                      //
                      // The method resolveColumnIndexes will overwrite
                      // a join node's schema if there is aggregation.  In order
                      // to avoid undoing the work we've done here, we must
                      // also update the inlined aggregate node.
                      AggregatePlanNode aggNode = AggregatePlanNode.getInlineAggregationNode(child);
                      if (aggNode != null) {
                          aggNode.setOutputSchema(answer);
                      }
                  }
  
                  if (! child.m_hasSignificantOutputSchema) {
                      child.setOutputSchema(answer);
                  }
  
                  child = (child.getParentCount() == 0) ? null : child.getParent(0);
              } while (child != null);
          }
          return answer;
      }