Fix IndexOutOfBoundsException for MSQ window function queries with empty RAC (#16865)

* Fix IndexOutOfBoundsException for MSQ window function queries with empty RAC
This commit is contained in:
Akshat Jain 2024-08-09 11:39:53 +05:30 committed by GitHub
parent cb09b572e6
commit 3d6cedb25f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 77 additions and 0 deletions

View File

@ -19,6 +19,7 @@
package org.apache.druid.query.rowsandcols; package org.apache.druid.query.rowsandcols;
import com.google.common.base.Preconditions;
import org.apache.druid.java.util.common.ISE; import org.apache.druid.java.util.common.ISE;
import org.apache.druid.query.rowsandcols.column.Column; import org.apache.druid.query.rowsandcols.column.Column;
import org.apache.druid.query.rowsandcols.column.ColumnAccessor; import org.apache.druid.query.rowsandcols.column.ColumnAccessor;
@ -30,6 +31,7 @@ import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -53,6 +55,7 @@ public class ConcatRowsAndColumns implements RowsAndColumns
ArrayList<RowsAndColumns> racBuffer ArrayList<RowsAndColumns> racBuffer
) )
{ {
Preconditions.checkNotNull(racBuffer, "racBuffer cannot be null");
this.racBuffer = racBuffer; this.racBuffer = racBuffer;
int numRows = 0; int numRows = 0;
@ -76,6 +79,9 @@ public class ConcatRowsAndColumns implements RowsAndColumns
@Override @Override
public Collection<String> getColumnNames() public Collection<String> getColumnNames()
{ {
if (racBuffer.isEmpty()) {
return Collections.emptySet();
}
return racBuffer.get(0).getColumnNames(); return racBuffer.get(0).getColumnNames();
} }
@ -92,6 +98,9 @@ public class ConcatRowsAndColumns implements RowsAndColumns
if (columnCache.containsKey(name)) { if (columnCache.containsKey(name)) {
return columnCache.get(name); return columnCache.get(name);
} else { } else {
if (racBuffer.isEmpty()) {
return null;
}
final Column firstCol = racBuffer.get(0).findColumn(name); final Column firstCol = racBuffer.get(0).findColumn(name);
if (firstCol == null) { if (firstCol == null) {
for (int i = 1; i < racBuffer.size(); ++i) { for (int i = 1; i < racBuffer.size(); ++i) {

View File

@ -19,7 +19,13 @@
package org.apache.druid.query.rowsandcols; package org.apache.druid.query.rowsandcols;
import com.google.common.collect.ImmutableMap;
import org.apache.druid.query.rowsandcols.column.IntArrayColumn;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Function; import java.util.function.Function;
public class ConcatRowsAndColumnsTest extends RowsAndColumnsTestBase public class ConcatRowsAndColumnsTest extends RowsAndColumnsTestBase
@ -42,4 +48,55 @@ public class ConcatRowsAndColumnsTest extends RowsAndColumnsTestBase
return new ConcatRowsAndColumns(theRac); return new ConcatRowsAndColumns(theRac);
}; };
@Test
public void testConstructorWithNullRacBuffer()
{
final NullPointerException e = Assert.assertThrows(
NullPointerException.class,
() -> new ConcatRowsAndColumns(null)
);
Assert.assertEquals("racBuffer cannot be null", e.getMessage());
}
@Test
public void testFindColumn()
{
MapOfColumnsRowsAndColumns rac = MapOfColumnsRowsAndColumns.fromMap(
ImmutableMap.of(
"column1", new IntArrayColumn(new int[]{1, 2, 3, 4, 5, 6}),
"column2", new IntArrayColumn(new int[]{6, 5, 4, 3, 2, 1})
)
);
ConcatRowsAndColumns apply = MAKER.apply(rac);
Assert.assertEquals(1, apply.findColumn("column1").toAccessor().getInt(0));
Assert.assertEquals(6, apply.findColumn("column2").toAccessor().getInt(0));
}
@Test
public void testFindColumnWithEmptyRacBuffer()
{
ConcatRowsAndColumns concatRowsAndColumns = new ConcatRowsAndColumns(new ArrayList<>());
Assert.assertNull(concatRowsAndColumns.findColumn("columnName"));
}
@Test
public void testGetColumns()
{
MapOfColumnsRowsAndColumns rac = MapOfColumnsRowsAndColumns.fromMap(
ImmutableMap.of(
"column1", new IntArrayColumn(new int[]{0, 0, 0, 1, 1, 2, 4, 4, 4}),
"column2", new IntArrayColumn(new int[]{3, 54, 21, 1, 5, 54, 2, 3, 92})
)
);
ConcatRowsAndColumns apply = MAKER.apply(rac);
Assert.assertEquals(Arrays.asList("column1", "column2"), new ArrayList<>(apply.getColumnNames()));
}
@Test
public void testGetColumnsWithEmptyRacBuffer()
{
ConcatRowsAndColumns concatRowsAndColumns = new ConcatRowsAndColumns(new ArrayList<>());
Assert.assertTrue(concatRowsAndColumns.getColumnNames().isEmpty());
}
} }

View File

@ -7622,6 +7622,13 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
windowQueryTest(); windowQueryTest();
} }
@DrillTest("druid_queries/empty_over_clause/single_empty_over_3")
@Test
public void test_empty_over_single_empty_over_3()
{
windowQueryTest();
}
@DrillTest("druid_queries/empty_over_clause/multiple_empty_over_1") @DrillTest("druid_queries/empty_over_clause/multiple_empty_over_1")
@Test @Test
public void test_empty_over_multiple_empty_over_1() public void test_empty_over_multiple_empty_over_1()

View File

@ -0,0 +1,4 @@
select countryName, row_number() over () as c1
from wikipedia
where countryName in ('non-existent-country')
group by countryName, cityName, channel