public VectorObjectSelector makeVectorObjectSelector()

in processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java [501:637]


  public VectorObjectSelector makeVectorObjectSelector(
      String columnName,
      ColumnSelector columnSelector,
      ReadableVectorOffset offset
  )
  {
    ColumnHolder holder = columnSelector.getColumnHolder(fieldSpec.columnName);
    if (holder == null) {
      return NilVectorSelector.create(offset);
    }
    BaseColumn column = holder.getColumn();


    if (column instanceof NestedDataComplexColumn) {
      final NestedDataComplexColumn complexColumn = (NestedDataComplexColumn) column;
      if (fieldSpec.processFromRaw) {
        // processFromRaw is true, that means JSON_QUERY, which can return partial results, otherwise this virtual column
        // is JSON_VALUE which only returns literals, so we can use the nested columns value selector
        return new RawFieldVectorObjectSelector(complexColumn.makeVectorObjectSelector(offset), fieldSpec.parts);
      }
      Set<ColumnType> types = complexColumn.getColumnTypes(fieldSpec.parts);
      ColumnType leastRestrictiveType = null;
      if (types != null) {
        for (ColumnType type : types) {
          leastRestrictiveType = ColumnType.leastRestrictiveType(leastRestrictiveType, type);
        }
      }
      if (leastRestrictiveType != null && leastRestrictiveType.isNumeric() && !Types.isNumeric(fieldSpec.expectedType)) {
        return ExpressionVectorSelectors.castValueSelectorToObject(
            offset,
            columnName,
            complexColumn.makeVectorValueSelector(fieldSpec.parts, offset),
            leastRestrictiveType,
            fieldSpec.expectedType == null ? ColumnType.STRING : fieldSpec.expectedType
        );
      }
      final VectorObjectSelector objectSelector = complexColumn.makeVectorObjectSelector(fieldSpec.parts, offset);
      if (leastRestrictiveType != null &&
          leastRestrictiveType.isArray() &&
          fieldSpec.expectedType != null &&
          !fieldSpec.expectedType.isArray()
      ) {
        final ExpressionType elementType = ExpressionType.fromColumnTypeStrict(leastRestrictiveType.getElementType());
        final ExpressionType castTo = ExpressionType.fromColumnTypeStrict(fieldSpec.expectedType);
        return makeVectorArrayToScalarObjectSelector(offset, objectSelector, elementType, castTo);
      }

      return objectSelector;
    }
    // not a nested column, but we can still do stuff if the path is the 'root', indicated by an empty path parts
    if (fieldSpec.parts.isEmpty()) {
      ColumnCapabilities capabilities = holder.getCapabilities();
      // expectedType shouldn't possibly be null if we are being asked for an object selector and the underlying column
      // is numeric, else we would have been asked for a value selector
      Preconditions.checkArgument(
          fieldSpec.expectedType != null,
          "Asked for a VectorObjectSelector on a numeric column, 'expectedType' must not be null"
      );
      if (capabilities.isNumeric()) {
        return ExpressionVectorSelectors.castValueSelectorToObject(
            offset,
            fieldSpec.columnName,
            column.makeVectorValueSelector(offset),
            capabilities.toColumnType(),
            fieldSpec.expectedType
        );
      }
      // if the underlying column is array typed, the vector object selector it spits out will homogenize stuff to
      // make all of the objects a consistent type, which is typically a good thing, but if we are doing mixed type
      // stuff and expect the output type to be scalar typed, then we should coerce things to only extract the scalars
      if (capabilities.isArray() && !fieldSpec.expectedType.isArray()) {
        final VectorObjectSelector delegate = column.makeVectorObjectSelector(offset);
        final ExpressionType elementType = ExpressionType.fromColumnTypeStrict(capabilities.getElementType());
        final ExpressionType castTo = ExpressionType.fromColumnTypeStrict(fieldSpec.expectedType);
        return makeVectorArrayToScalarObjectSelector(offset, delegate, elementType, castTo);
      }
      return column.makeVectorObjectSelector(offset);
    }

    if (fieldSpec.parts.size() == 1 && fieldSpec.parts.get(0) instanceof NestedPathArrayElement && column instanceof VariantColumn) {
      final VariantColumn<?> arrayColumn = (VariantColumn<?>) column;
      final ExpressionType elementType = ExpressionType.fromColumnTypeStrict(
          arrayColumn.getLogicalType().isArray() ? arrayColumn.getLogicalType().getElementType() : arrayColumn.getLogicalType()
      );
      final ExpressionType castTo = fieldSpec.expectedType == null
                                    ? ExpressionType.STRING
                                    : ExpressionType.fromColumnTypeStrict(fieldSpec.expectedType);
      VectorObjectSelector arraySelector = arrayColumn.makeVectorObjectSelector(offset);
      final int elementNumber = ((NestedPathArrayElement) fieldSpec.parts.get(0)).getIndex();
      if (elementNumber < 0) {
        throw new IAE("Cannot make array element selector, negative array index not supported");
      }
      return new VectorObjectSelector()
      {
        private final Object[] elements = new Object[arraySelector.getMaxVectorSize()];
        private int id = ReadableVectorInspector.NULL_ID;

        @Override
        public Object[] getObjectVector()
        {
          if (offset.getId() != id) {
            final Object[] delegate = arraySelector.getObjectVector();
            for (int i = 0; i < arraySelector.getCurrentVectorSize(); i++) {
              Object maybeArray = delegate[i];
              if (maybeArray instanceof Object[]) {
                Object[] anArray = (Object[]) maybeArray;
                if (elementNumber < anArray.length) {
                  elements[i] = ExprEval.ofType(elementType, anArray[elementNumber]).castTo(castTo).value();
                } else {
                  elements[i] = null;
                }
              } else {
                elements[i] = null;
              }
            }
            id = offset.getId();
          }
          return elements;
        }

        @Override
        public int getMaxVectorSize()
        {
          return arraySelector.getMaxVectorSize();
        }

        @Override
        public int getCurrentVectorSize()
        {
          return arraySelector.getCurrentVectorSize();
        }
      };
    }

    // we are not a nested column and are being asked for a path that will never exist, so we are nil selector
    return NilVectorSelector.create(offset);
  }