2626import org .opensearch .sql .calcite .CalcitePlanContext ;
2727import org .opensearch .sql .calcite .utils .OpenSearchTypeFactory ;
2828import org .opensearch .sql .common .response .ResponseListener ;
29+ import org .opensearch .sql .data .model .ExprCollectionValue ;
2930import org .opensearch .sql .data .model .ExprTupleValue ;
3031import org .opensearch .sql .data .model .ExprValue ;
3132import org .opensearch .sql .data .model .ExprValueUtils ;
@@ -215,6 +216,8 @@ private List<ExprValue> convertRows(Iterable<Object[]> rows, List<RelDataTypeFie
215216 * IpFieldMapper}'s {@code valueFetcher} output).
216217 * <li>{@link BinaryType} + {@code byte[]} → base64-encoded string (matches the OpenSearch
217218 * {@code binary} field wire format).
219+ * <li>{@code ARRAY<IpType>} / {@code ARRAY<BinaryType>} + {@code List<byte[]>} → element-wise
220+ * UDT-aware conversion for {@code list(ip|binary)} aggregates.
218221 * <li>Anything else → existing {@link ExprValueUtils#fromObjectValue} path.
219222 * </ul>
220223 *
@@ -224,19 +227,55 @@ private List<ExprValue> convertRows(Iterable<Object[]> rows, List<RelDataTypeFie
224227 private static ExprValue toExprValue (Object value , RelDataType type ) {
225228 if (value instanceof byte [] bytes ) {
226229 if (type instanceof IpType ) {
227- try {
228- return ExprValueUtils .stringValue (
229- InetAddresses .toAddrString (InetAddress .getByAddress (bytes )));
230- } catch (UnknownHostException e ) {
231- throw new IllegalStateException ("invalid IP buffer length: " + bytes .length , e );
232- }
230+ return ipBytesToExprValue (bytes );
233231 } else if (type instanceof BinaryType ) {
234- return ExprValueUtils .stringValue (Base64 .getEncoder ().encodeToString (bytes ));
232+ return binaryBytesToExprValue (bytes );
233+ }
234+ }
235+ if (value instanceof List <?> list ) {
236+ RelDataType component = type .getComponentType ();
237+ if (component instanceof IpType ) {
238+ List <ExprValue > elems = new ArrayList <>(list .size ());
239+ for (Object elem : list ) {
240+ if (elem == null ) {
241+ elems .add (ExprValueUtils .nullValue ());
242+ } else if (elem instanceof byte [] eb ) {
243+ elems .add (ipBytesToExprValue (eb ));
244+ } else {
245+ elems .add (ExprValueUtils .fromObjectValue (elem ));
246+ }
247+ }
248+ return new ExprCollectionValue (elems );
249+ } else if (component instanceof BinaryType ) {
250+ List <ExprValue > elems = new ArrayList <>(list .size ());
251+ for (Object elem : list ) {
252+ if (elem == null ) {
253+ elems .add (ExprValueUtils .nullValue ());
254+ } else if (elem instanceof byte [] eb ) {
255+ elems .add (binaryBytesToExprValue (eb ));
256+ } else {
257+ elems .add (ExprValueUtils .fromObjectValue (elem ));
258+ }
259+ }
260+ return new ExprCollectionValue (elems );
235261 }
236262 }
237263 return ExprValueUtils .fromObjectValue (value );
238264 }
239265
266+ private static ExprValue ipBytesToExprValue (byte [] bytes ) {
267+ try {
268+ return ExprValueUtils .stringValue (
269+ InetAddresses .toAddrString (InetAddress .getByAddress (bytes )));
270+ } catch (UnknownHostException e ) {
271+ throw new IllegalStateException ("invalid IP buffer length: " + bytes .length , e );
272+ }
273+ }
274+
275+ private static ExprValue binaryBytesToExprValue (byte [] bytes ) {
276+ return ExprValueUtils .stringValue (Base64 .getEncoder ().encodeToString (bytes ));
277+ }
278+
240279 private Schema buildSchema (List <RelDataTypeField > fields ) {
241280 List <Schema .Column > columns = new ArrayList <>();
242281 for (RelDataTypeField field : fields ) {
0 commit comments