private static void parseFieldForName()

in druid/src/main/java/org/apache/calcite/adapter/druid/DruidConnectionImpl.java [318:456]


  private static void parseFieldForName(List<String> fieldNames,
      List<ColumnMetaData.Rep> fieldTypes,
      int posTimestampField, Row.RowBuilder rowBuilder, JsonParser parser, String fieldName)
      throws IOException {
    // Move to next token, which is name's value
    JsonToken token = parser.nextToken();

    boolean isTimestampColumn = fieldName.equals(DEFAULT_RESPONSE_TIMESTAMP_COLUMN);
    int i = fieldNames.indexOf(fieldName);
    ColumnMetaData.Rep type = null;
    if (i < 0) {
      if (!isTimestampColumn) {
        // Field not present
        return;
      }
    } else {
      type = fieldTypes.get(i);
    }

    if (isTimestampColumn || ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP == type) {
      final int fieldPos = posTimestampField != -1 ? posTimestampField : i;
      if (token == JsonToken.VALUE_NUMBER_INT) {
        rowBuilder.set(posTimestampField, parser.getLongValue());
        return;
      } else {
        // We don't have any way to figure out the format of time upfront since we only have
        // org.apache.calcite.avatica.ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP as type to represent
        // both timestamp and timestamp with local timezone.
        // Logic where type is inferred can be found at DruidQuery.DruidQueryNode.getPrimitive()
        // Thus need to guess via try and catch
        synchronized (UTC_TIMESTAMP_FORMAT) {
          // synchronized block to avoid race condition
          try {
            // First try to parse as Timestamp with timezone.
            rowBuilder
                .set(fieldPos, UTC_TIMESTAMP_FORMAT.parse(parser.getText()).getTime());
          } catch (ParseException e) {
            // swallow the exception and try timestamp format
            try {
              rowBuilder
                  .set(fieldPos, TIMESTAMP_FORMAT.parse(parser.getText()).getTime());
            } catch (ParseException e2) {
              // unknown format should not happen
              throw new RuntimeException(e2);
            }
          }
        }
        return;
      }
    }

    switch (token) {
    case VALUE_NUMBER_INT:
      if (type == null) {
        type = ColumnMetaData.Rep.LONG;
      }
      // fall through
    case VALUE_NUMBER_FLOAT:
      if (type == null) {
        // JSON's "float" is 64-bit floating point
        type = ColumnMetaData.Rep.DOUBLE;
      }
      switch (type) {
      case BYTE:
        rowBuilder.set(i, parser.getByteValue());
        break;
      case SHORT:
        rowBuilder.set(i, parser.getShortValue());
        break;
      case INTEGER:
        rowBuilder.set(i, parser.getIntValue());
        break;
      case LONG:
        rowBuilder.set(i, parser.getLongValue());
        break;
      case DOUBLE:
        rowBuilder.set(i, parser.getDoubleValue());
        break;
      default:
        break;
      }
      break;
    case VALUE_TRUE:
      rowBuilder.set(i, true);
      break;
    case VALUE_FALSE:
      rowBuilder.set(i, false);
      break;
    case VALUE_NULL:
      break;
    case VALUE_STRING:
    default:
      final String s = parser.getText();
      if (type != null) {
        switch (type) {
        case LONG:
        case PRIMITIVE_LONG:
        case SHORT:
        case PRIMITIVE_SHORT:
        case INTEGER:
        case PRIMITIVE_INT:
          switch (s) {
          case "Infinity":
          case "-Infinity":
          case "NaN":
            throw new RuntimeException("/ by zero");
          default:
            break;
          }
          rowBuilder.set(i, Long.valueOf(s));
          break;
        case FLOAT:
        case PRIMITIVE_FLOAT:
        case PRIMITIVE_DOUBLE:
        case NUMBER:
        case DOUBLE:
          switch (s) {
          case "Infinity":
            rowBuilder.set(i, Double.POSITIVE_INFINITY);
            return;
          case "-Infinity":
            rowBuilder.set(i, Double.NEGATIVE_INFINITY);
            return;
          case "NaN":
            rowBuilder.set(i, Double.NaN);
            return;
          default:
            break;
          }
          rowBuilder.set(i, Double.valueOf(s));
          break;
        default:
          break;
        }
      } else {
        rowBuilder.set(i, s);
      }
    }
  }