This is an automated email from the ASF dual-hosted git repository. jackie pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push: new 5416df1088 Bugfix: prevent certain `not (x and y)` filters from causing a NPE (#13527) 5416df1088 is described below commit 5416df10883dcd8fc571e7d6007ab37824617ae1 Author: Christopher Peck <27231838+itschrisp...@users.noreply.github.com> AuthorDate: Mon Jul 8 18:16:46 2024 -0700 Bugfix: prevent certain `not (x and y)` filters from causing a NPE (#13527) --- .../operator/dociditerators/NotDocIdIterator.java | 3 + .../pinot/queries/TransformFilterQueriesTest.java | 165 +++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/dociditerators/NotDocIdIterator.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/dociditerators/NotDocIdIterator.java index 5ce0de3a67..f5fbe52bdc 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/dociditerators/NotDocIdIterator.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/dociditerators/NotDocIdIterator.java @@ -43,6 +43,9 @@ public class NotDocIdIterator implements BlockDocIdIterator { @Override public int next() { + if (_nextDocId >= _numDocs) { + return Constants.EOF; + } while (_nextDocId == _nextNonMatchingDocId) { _nextDocId++; int nextNonMatchingDocId = _childDocIdIterator.next(); diff --git a/pinot-core/src/test/java/org/apache/pinot/queries/TransformFilterQueriesTest.java b/pinot-core/src/test/java/org/apache/pinot/queries/TransformFilterQueriesTest.java new file mode 100644 index 0000000000..7116368bdd --- /dev/null +++ b/pinot-core/src/test/java/org/apache/pinot/queries/TransformFilterQueriesTest.java @@ -0,0 +1,165 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pinot.queries; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.apache.commons.io.FileUtils; +import org.apache.pinot.core.common.Operator; +import org.apache.pinot.core.operator.blocks.results.SelectionResultsBlock; +import org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentLoader; +import org.apache.pinot.segment.local.segment.creator.impl.SegmentIndexCreationDriverImpl; +import org.apache.pinot.segment.local.segment.readers.GenericRowRecordReader; +import org.apache.pinot.segment.spi.ImmutableSegment; +import org.apache.pinot.segment.spi.IndexSegment; +import org.apache.pinot.segment.spi.creator.SegmentGeneratorConfig; +import org.apache.pinot.spi.config.table.TableConfig; +import org.apache.pinot.spi.config.table.TableType; +import org.apache.pinot.spi.data.FieldSpec; +import org.apache.pinot.spi.data.Schema; +import org.apache.pinot.spi.data.readers.GenericRow; +import org.apache.pinot.spi.data.readers.RecordReader; +import org.apache.pinot.spi.utils.ReadMode; +import org.apache.pinot.spi.utils.builder.TableConfigBuilder; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + + +public class TransformFilterQueriesTest extends BaseQueriesTest { + private static final File INDEX_DIR = new File(FileUtils.getTempDirectory(), "TransformFilterQueriesTest"); + private static final String TABLE_NAME = "testTable"; + private static final String SEGMENT_NAME = "testSegment"; + private static final String INT_COLUMN = "intColumn"; + private static final String STRING_COLUMN = "stringColumn"; + + private static final int NUM_ROWS = 4; + + private IndexSegment _indexSegment; + private List<IndexSegment> _indexSegments; + + @Override + protected String getFilter() { + return ""; + } + + @Override + protected IndexSegment getIndexSegment() { + return _indexSegment; + } + + @Override + protected List<IndexSegment> getIndexSegments() { + return _indexSegments; + } + + GenericRow createRecord(int intValue, String stringValue) { + GenericRow record = new GenericRow(); + record.putValue(INT_COLUMN, intValue); + record.putValue(STRING_COLUMN, stringValue); + + return record; + } + + @BeforeClass + public void setUp() + throws Exception { + FileUtils.deleteDirectory(INDEX_DIR); + + List<GenericRow> rows = new ArrayList<>(NUM_ROWS); + rows.add(createRecord(1, "apple")); + rows.add(createRecord(2, "banana")); + rows.add(createRecord(3, "carrot")); + rows.add(createRecord(4, "fruit")); + + Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(INT_COLUMN, FieldSpec.DataType.INT) + .addSingleValueDimension(STRING_COLUMN, FieldSpec.DataType.STRING).build(); + TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(TABLE_NAME) + .setNoDictionaryColumns(List.of(STRING_COLUMN, INT_COLUMN)).build(); + SegmentGeneratorConfig config = new SegmentGeneratorConfig(tableConfig, schema); + config.setOutDir(INDEX_DIR.getPath()); + config.setTableName(TABLE_NAME); + config.setSegmentName(SEGMENT_NAME); + + SegmentIndexCreationDriverImpl driver = new SegmentIndexCreationDriverImpl(); + try (RecordReader recordReader = new GenericRowRecordReader(rows)) { + driver.init(config, recordReader); + driver.build(); + } + + ImmutableSegment immutableSegment = ImmutableSegmentLoader.load(new File(INDEX_DIR, SEGMENT_NAME), ReadMode.mmap); + _indexSegment = immutableSegment; + _indexSegments = Arrays.asList(immutableSegment, immutableSegment); + } + + @AfterClass + public void tearDown() { + _indexSegment.destroy(); + FileUtils.deleteQuietly(INDEX_DIR); + } + + @Test + public void testTransformDocIdsLessThanFiltered() { + Operator<SelectionResultsBlock> operator = getOperator( + "SELECT * FROM testTable WHERE NOT (intColumn = 3 AND lower(stringColumn) = 'banana')"); + SelectionResultsBlock block = operator.nextBlock(); + List<Object[]> rows = block.getRows(); + + assertNotNull(rows); + assertEquals(rows.size(), 4); + assertEquals(rows.get(0)[0], 1); + assertEquals(rows.get(1)[0], 2); + assertEquals(rows.get(2)[0], 3); + assertEquals(rows.get(3)[0], 4); + } + + @Test + public void testTransformDocIdsGreaterThanFiltered() { + Operator<SelectionResultsBlock> operator = getOperator( + "SELECT * FROM testTable WHERE NOT (intColumn = 1 AND lower(stringColumn) = 'banana')"); + SelectionResultsBlock block = operator.nextBlock(); + List<Object[]> rows = block.getRows(); + + assertNotNull(rows); + assertEquals(rows.size(), 4); + assertEquals(rows.get(0)[0], 1); + assertEquals(rows.get(1)[0], 2); + assertEquals(rows.get(2)[0], 3); + assertEquals(rows.get(3)[0], 4); + } + + @Test + public void testTransformDocIdsEqualToFiltered() { + Operator<SelectionResultsBlock> operator = getOperator( + "SELECT * FROM testTable WHERE NOT (intColumn = 2 AND lower(stringColumn) = 'banana')"); + SelectionResultsBlock block = operator.nextBlock(); + List<Object[]> rows = block.getRows(); + + assertNotNull(rows); + assertEquals(rows.size(), 3); + assertEquals(rows.get(0)[0], 1); + assertEquals(rows.get(1)[0], 3); + assertEquals(rows.get(2)[0], 4); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org