Skip to content

Commit a42ae5e

Browse files
committed
perf: avoid conversion of float[] into List<Float> in SQL engine
1 parent c8fb3e5 commit a42ae5e

File tree

2 files changed

+292
-1
lines changed

2 files changed

+292
-1
lines changed

engine/src/main/java/com/arcadedb/query/sql/parser/InputParameter.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,12 @@ protected Object toParsedTree(final Object value) {
8585
if (value instanceof String) {
8686
return value;
8787
}
88-
if (MultiValue.isMultiValue(value) && !(value instanceof byte[]) && !(value instanceof Byte[])) {
88+
// Primitive arrays and their wrapper arrays should be passed as-is to maintain performance
89+
// (especially critical for vector operations with float[] parameters)
90+
if (isPrimitiveOrWrapperArray(value)) {
91+
return value;
92+
}
93+
if (MultiValue.isMultiValue(value)) {
8994
final PCollection coll = new PCollection(-1);
9095
coll.expressions = new ArrayList<Expression>();
9196
final Iterator iterator = MultiValue.getMultiValueIterator(value);
@@ -149,6 +154,34 @@ protected Object toParsedTree(final Object value) {
149154
return this;
150155
}
151156

157+
/**
158+
* Check if value is a primitive array or wrapper array type.
159+
* These types should NOT be converted to PCollection for performance reasons.
160+
* Primitive arrays are passed directly to functions to avoid boxing overhead,
161+
* which is especially critical for vector operations with float[] parameters.
162+
*
163+
* @param value the value to check
164+
* @return true if value is a primitive or wrapper array type
165+
*/
166+
private static boolean isPrimitiveOrWrapperArray(Object value) {
167+
return value instanceof byte[] ||
168+
value instanceof Byte[] ||
169+
value instanceof short[] ||
170+
value instanceof Short[] ||
171+
value instanceof int[] ||
172+
value instanceof Integer[] ||
173+
value instanceof long[] ||
174+
value instanceof Long[] ||
175+
value instanceof float[] ||
176+
value instanceof Float[] ||
177+
value instanceof double[] ||
178+
value instanceof Double[] ||
179+
value instanceof boolean[] ||
180+
value instanceof Boolean[] ||
181+
value instanceof char[] ||
182+
value instanceof Character[];
183+
}
184+
152185
public InputParameter copy() {
153186
throw new UnsupportedOperationException();
154187
}
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
/*
2+
* Copyright © 2021-present Arcade Data Ltd ([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-FileCopyrightText: 2021-present Arcade Data Ltd ([email protected])
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package com.arcadedb.query.sql.parser;
20+
21+
import org.junit.jupiter.api.Test;
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
24+
/**
25+
* Unit tests for InputParameter to verify that primitive arrays are not converted to PCollection.
26+
* This is critical for performance, especially for vector operations with float[] parameters.
27+
*
28+
* @author Luca Garulli ([email protected])
29+
*/
30+
class InputParameterTest {
31+
32+
@Test
33+
void testFloatArrayNotConvertedToPCollection() {
34+
// Given: A float array parameter (common for vector operations)
35+
final float[] floatArray = new float[]{1.0f, 2.0f, 3.0f};
36+
final InputParameter param = new InputParameter(-1);
37+
38+
// When: Converting to parsed tree
39+
final Object result = param.toParsedTree(floatArray);
40+
41+
// Then: Should return the array as-is, not converted to PCollection
42+
assertThat(result).isInstanceOf(float[].class);
43+
assertThat(result).isSameAs(floatArray);
44+
}
45+
46+
@Test
47+
void testIntArrayNotConvertedToPCollection() {
48+
// Given: An int array parameter
49+
final int[] intArray = new int[]{1, 2, 3};
50+
final InputParameter param = new InputParameter(-1);
51+
52+
// When: Converting to parsed tree
53+
final Object result = param.toParsedTree(intArray);
54+
55+
// Then: Should return the array as-is, not converted to PCollection
56+
assertThat(result).isInstanceOf(int[].class);
57+
assertThat(result).isSameAs(intArray);
58+
}
59+
60+
@Test
61+
void testDoubleArrayNotConvertedToPCollection() {
62+
// Given: A double array parameter
63+
final double[] doubleArray = new double[]{1.0, 2.0, 3.0};
64+
final InputParameter param = new InputParameter(-1);
65+
66+
// When: Converting to parsed tree
67+
final Object result = param.toParsedTree(doubleArray);
68+
69+
// Then: Should return the array as-is, not converted to PCollection
70+
assertThat(result).isInstanceOf(double[].class);
71+
assertThat(result).isSameAs(doubleArray);
72+
}
73+
74+
@Test
75+
void testLongArrayNotConvertedToPCollection() {
76+
// Given: A long array parameter
77+
final long[] longArray = new long[]{1L, 2L, 3L};
78+
final InputParameter param = new InputParameter(-1);
79+
80+
// When: Converting to parsed tree
81+
final Object result = param.toParsedTree(longArray);
82+
83+
// Then: Should return the array as-is, not converted to PCollection
84+
assertThat(result).isInstanceOf(long[].class);
85+
assertThat(result).isSameAs(longArray);
86+
}
87+
88+
@Test
89+
void testShortArrayNotConvertedToPCollection() {
90+
// Given: A short array parameter
91+
final short[] shortArray = new short[]{1, 2, 3};
92+
final InputParameter param = new InputParameter(-1);
93+
94+
// When: Converting to parsed tree
95+
final Object result = param.toParsedTree(shortArray);
96+
97+
// Then: Should return the array as-is, not converted to PCollection
98+
assertThat(result).isInstanceOf(short[].class);
99+
assertThat(result).isSameAs(shortArray);
100+
}
101+
102+
@Test
103+
void testByteArrayNotConvertedToPCollection() {
104+
// Existing behavior should still work
105+
final byte[] byteArray = new byte[]{1, 2, 3};
106+
final InputParameter param = new InputParameter(-1);
107+
108+
// When: Converting to parsed tree
109+
final Object result = param.toParsedTree(byteArray);
110+
111+
// Then: Should return the array as-is, not converted to PCollection
112+
assertThat(result).isInstanceOf(byte[].class);
113+
assertThat(result).isSameAs(byteArray);
114+
}
115+
116+
@Test
117+
void testBooleanArrayNotConvertedToPCollection() {
118+
// Given: A boolean array parameter
119+
final boolean[] booleanArray = new boolean[]{true, false, true};
120+
final InputParameter param = new InputParameter(-1);
121+
122+
// When: Converting to parsed tree
123+
final Object result = param.toParsedTree(booleanArray);
124+
125+
// Then: Should return the array as-is, not converted to PCollection
126+
assertThat(result).isInstanceOf(boolean[].class);
127+
assertThat(result).isSameAs(booleanArray);
128+
}
129+
130+
@Test
131+
void testCharArrayNotConvertedToPCollection() {
132+
// Given: A char array parameter
133+
final char[] charArray = new char[]{'a', 'b', 'c'};
134+
final InputParameter param = new InputParameter(-1);
135+
136+
// When: Converting to parsed tree
137+
final Object result = param.toParsedTree(charArray);
138+
139+
// Then: Should return the array as-is, not converted to PCollection
140+
assertThat(result).isInstanceOf(char[].class);
141+
assertThat(result).isSameAs(charArray);
142+
}
143+
144+
@Test
145+
void testWrapperFloatArrayNotConvertedToPCollection() {
146+
// Float[] (boxed) should also be excluded for consistency
147+
final Float[] floatWrapperArray = new Float[]{1.0f, 2.0f, 3.0f};
148+
final InputParameter param = new InputParameter(-1);
149+
150+
// When: Converting to parsed tree
151+
final Object result = param.toParsedTree(floatWrapperArray);
152+
153+
// Then: Should return the array as-is, not converted to PCollection
154+
assertThat(result).isInstanceOf(Float[].class);
155+
assertThat(result).isSameAs(floatWrapperArray);
156+
}
157+
158+
@Test
159+
void testWrapperIntegerArrayNotConvertedToPCollection() {
160+
// Integer[] (boxed) should also be excluded for consistency
161+
final Integer[] integerWrapperArray = new Integer[]{1, 2, 3};
162+
final InputParameter param = new InputParameter(-1);
163+
164+
// When: Converting to parsed tree
165+
final Object result = param.toParsedTree(integerWrapperArray);
166+
167+
// Then: Should return the array as-is, not converted to PCollection
168+
assertThat(result).isInstanceOf(Integer[].class);
169+
assertThat(result).isSameAs(integerWrapperArray);
170+
}
171+
172+
@Test
173+
void testWrapperDoubleArrayNotConvertedToPCollection() {
174+
// Double[] (boxed) should also be excluded for consistency
175+
final Double[] doubleWrapperArray = new Double[]{1.0, 2.0, 3.0};
176+
final InputParameter param = new InputParameter(-1);
177+
178+
// When: Converting to parsed tree
179+
final Object result = param.toParsedTree(doubleWrapperArray);
180+
181+
// Then: Should return the array as-is, not converted to PCollection
182+
assertThat(result).isInstanceOf(Double[].class);
183+
assertThat(result).isSameAs(doubleWrapperArray);
184+
}
185+
186+
@Test
187+
void testWrapperByteArrayNotConvertedToPCollection() {
188+
// Byte[] (boxed) should also be excluded (was already excluded before)
189+
final Byte[] byteWrapperArray = new Byte[]{1, 2, 3};
190+
final InputParameter param = new InputParameter(-1);
191+
192+
// When: Converting to parsed tree
193+
final Object result = param.toParsedTree(byteWrapperArray);
194+
195+
// Then: Should return the array as-is, not converted to PCollection
196+
assertThat(result).isInstanceOf(Byte[].class);
197+
assertThat(result).isSameAs(byteWrapperArray);
198+
}
199+
200+
@Test
201+
void testObjectArrayStillConvertedToPCollection() {
202+
// String[] should still be converted to PCollection (existing behavior for object arrays)
203+
final String[] stringArray = new String[]{"a", "b", "c"};
204+
final InputParameter param = new InputParameter(-1);
205+
206+
// When: Converting to parsed tree
207+
final Object result = param.toParsedTree(stringArray);
208+
209+
// Then: Should be converted to PCollection, not passed as-is
210+
assertThat(result).isInstanceOf(PCollection.class);
211+
assertThat(result).isNotSameAs(stringArray);
212+
}
213+
214+
@Test
215+
void testEmptyFloatArrayNotConvertedToPCollection() {
216+
// Edge case: Empty float array
217+
final float[] emptyArray = new float[0];
218+
final InputParameter param = new InputParameter(-1);
219+
220+
// When: Converting to parsed tree
221+
final Object result = param.toParsedTree(emptyArray);
222+
223+
// Then: Should return the array as-is
224+
assertThat(result).isInstanceOf(float[].class);
225+
assertThat(result).isSameAs(emptyArray);
226+
}
227+
228+
@Test
229+
void testSingleElementFloatArrayNotConvertedToPCollection() {
230+
// Edge case: Single element float array
231+
final float[] singleElementArray = new float[]{42.0f};
232+
final InputParameter param = new InputParameter(-1);
233+
234+
// When: Converting to parsed tree
235+
final Object result = param.toParsedTree(singleElementArray);
236+
237+
// Then: Should return the array as-is
238+
assertThat(result).isInstanceOf(float[].class);
239+
assertThat(result).isSameAs(singleElementArray);
240+
}
241+
242+
@Test
243+
void testLargeFloatArrayNotConvertedToPCollection() {
244+
// Performance test: Large float array (typical vector size)
245+
final float[] largeArray = new float[128];
246+
for (int i = 0; i < 128; i++) {
247+
largeArray[i] = i * 1.0f;
248+
}
249+
final InputParameter param = new InputParameter(-1);
250+
251+
// When: Converting to parsed tree
252+
final Object result = param.toParsedTree(largeArray);
253+
254+
// Then: Should return the array as-is (critical for vector performance)
255+
assertThat(result).isInstanceOf(float[].class);
256+
assertThat(result).isSameAs(largeArray);
257+
}
258+
}

0 commit comments

Comments
 (0)