docs: private void parseTableSchemaFromXML(String tableName,
                                           StmtCommonTableScanShared tableScan,
                                           VoltXMLElement voltXMLElement) {
          assert("table".equals(voltXMLElement.name));
          List<VoltXMLElement> columnSet = voltXMLElement.findChildren("columns");
          assert(columnSet.size() == 1);
          columnSet = columnSet.get(0).children;
          for (int idx = 0; idx < columnSet.size(); idx += 1) {
              VoltXMLElement columnXML = columnSet.get(idx);
              assert("column".equals(columnXML.name));
              String columnName = columnXML.attributes.get("name");
              // If valuetype is not defined, then we will get type
              // "none", about which typeFromString will complain.
              // Note that the types may be widened from the type
              // of the base query of a recursive common table.  This
              // happens if the corresponding type in the recursive
              // query is wider than that of the base case.  But
              // HSQL will have taken care of this for us, so we
              // will not see the widening here.
              VoltType valueType = VoltType.typeFromString(columnXML.getStringAttribute("valuetype", "none"));
              Integer columnIndex = columnXML.getIntAttribute("index", null);
              assert(columnIndex != null);
              // These appear to be optional.  Certainly "bytes"
              // only appears if the type is variably sized.
              Integer size = columnXML.getIntAttribute("size", 0);
              Boolean inBytes = columnXML.getBoolAttribute("bytes", null);
              // This TVE holds the metadata.
              TupleValueExpression tve = new TupleValueExpression(tableName, tableName, columnName, columnName, columnIndex);
              tve.setValueType(valueType);
              tve.setDifferentiator(idx);
              if (size == 0) {
                  if (valueType.isVariableLength()) {
                      size = valueType.defaultLengthForVariableLengthType();
                  }
                  else {
                      size = valueType.getLengthInBytesForFixedTypes();
                  }
              }
              tve.setValueSize(size);
              if (inBytes != null) {
                  tve.setInBytes(inBytes);
              }
              // There really is no aliasing going on here, so the table
              // name and column name are the same as the table alias and
              // column alias.
              SchemaColumn schemaColumn = new SchemaColumn(tableName, tableName, columnName, columnName, tve, idx);
              tableScan.addOutputColumn(schemaColumn);
          }
      }