From eb94edab0d956c6164d167a799eeebbe59f338ea Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind <natebauernfeind@deephaven.io> Date: Thu, 19 Jan 2023 08:34:50 -0700 Subject: [PATCH 1/5] Avoid Redirection of Row Agnostic Column Sources Port DH-12201: Create BooleanSingleValueSource Port DH-12310: SingleValue Column Sources Must Handle NULL_ROW_KEY --- .../deephaven/engine/rowset/RowSequence.java | 1 - .../engine/table/impl/AsOfJoinHelper.java | 3 +- .../engine/table/impl/CrossJoinHelper.java | 12 +- .../engine/table/impl/FlattenOperation.java | 2 +- .../engine/table/impl/NaturalJoinHelper.java | 3 +- .../engine/table/impl/QueryTable.java | 2 +- .../engine/table/impl/SortOperation.java | 23 ++- ...BaseAddOnlyFirstOrLastChunkedOperator.java | 5 +- .../impl/by/FirstOrLastChunkedOperator.java | 11 +- ...regationStateManagerOpenAddressedBase.java | 3 +- ...ratorAggregationStateManagerTypedBase.java | 2 +- .../by/SortedFirstOrLastChunkedOperator.java | 5 +- ...regationStateManagerOpenAddressedBase.java | 2 +- ...ratorAggregationStateManagerTypedBase.java | 2 +- .../impl/remote/InitialSnapshotTable.java | 2 +- .../impl/replay/QueryReplayGroupedTable.java | 2 +- .../analyzers/SelectAndViewAnalyzer.java | 5 +- .../select/analyzers/StaticFlattenLayer.java | 2 +- .../impl/sources/BitMaskingColumnSource.java | 17 +- .../impl/sources/BitShiftingColumnSource.java | 19 ++- .../sources/BooleanSingleValueSource.java | 149 ++++++++++++++++++ .../impl/sources/ByteSingleValueSource.java | 55 ++++++- .../sources/CharacterSingleValueSource.java | 55 ++++++- .../sources/CrossJoinRightColumnSource.java | 30 +++- .../impl/sources/DoubleSingleValueSource.java | 55 ++++++- .../impl/sources/FloatSingleValueSource.java | 55 ++++++- .../sources/IntegerSingleValueSource.java | 55 ++++++- .../impl/sources/LongSingleValueSource.java | 55 ++++++- .../impl/sources/NullValueColumnSource.java | 23 ++- .../impl/sources/ObjectSingleValueSource.java | 55 ++++++- .../impl/sources/RedirectedColumnSource.java | 19 ++- .../sources/RowKeyAgnosticColumnSource.java | 16 ++ .../impl/sources/ShortSingleValueSource.java | 55 ++++++- .../impl/sources/SingleValueColumnSource.java | 13 +- .../WritableRedirectedColumnSource.java | 27 +++- .../ImmutableConstantByteSource.java | 31 +++- .../ImmutableConstantCharSource.java | 31 +++- .../ImmutableConstantDoubleSource.java | 31 +++- .../ImmutableConstantFloatSource.java | 31 +++- .../immutable/ImmutableConstantIntSource.java | 31 +++- .../ImmutableConstantLongSource.java | 31 +++- .../ImmutableConstantObjectSource.java | 31 +++- .../ImmutableConstantShortSource.java | 31 +++- .../internal/BaseByteUpdateByOperator.java | 2 +- .../internal/BaseCharUpdateByOperator.java | 2 +- .../internal/BaseDoubleUpdateByOperator.java | 2 +- .../internal/BaseFloatUpdateByOperator.java | 2 +- .../internal/BaseIntUpdateByOperator.java | 2 +- .../internal/BaseLongUpdateByOperator.java | 2 +- .../internal/BaseObjectUpdateByOperator.java | 2 +- .../internal/BaseShortUpdateByOperator.java | 2 +- .../impl/util/ColumnsToRowsTransform.java | 2 +- .../table/impl/QueryTableNaturalJoinTest.java | 22 +++ .../impl/StreamTableAggregationTest.java | 2 +- .../table/impl/StreamTableOperationsTest.java | 2 +- .../barrage/table/BarrageTable.java | 2 +- .../ReplicateSourcesAndChunks.java | 7 +- 57 files changed, 1049 insertions(+), 92 deletions(-) create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java diff --git a/engine/rowset/src/main/java/io/deephaven/engine/rowset/RowSequence.java b/engine/rowset/src/main/java/io/deephaven/engine/rowset/RowSequence.java index 5e9611e499f..a8d5e416e0e 100644 --- a/engine/rowset/src/main/java/io/deephaven/engine/rowset/RowSequence.java +++ b/engine/rowset/src/main/java/io/deephaven/engine/rowset/RowSequence.java @@ -8,7 +8,6 @@ import io.deephaven.util.datastructures.LongSizedDataStructure; import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeyRanges; import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; -import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.chunk.LongChunk; import io.deephaven.chunk.WritableLongChunk; import io.deephaven.util.datastructures.LongRangeAbortableConsumer; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java index 66800ca77c3..24125ecfdf6 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java @@ -1528,7 +1528,8 @@ private static QueryTable makeResult(QueryTable leftTable, Table rightTable, Row MatchPair[] columnsToAdd, boolean refreshing) { final Map<String, ColumnSource<?>> columnSources = new LinkedHashMap<>(leftTable.getColumnSourceMap()); Arrays.stream(columnsToAdd).forEach(mp -> { - final RedirectedColumnSource<?> rightSource = + // note that we must always redirect the right-hand side, because unmatched rows will be redirected to null + final ColumnSource<?> rightSource = new RedirectedColumnSource<>(rowRedirection, rightTable.getColumnSource(mp.rightColumn())); if (refreshing) { rightSource.startTrackingPrevValues(); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/CrossJoinHelper.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/CrossJoinHelper.java index 972f81a0ec3..7f188cbcf22 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/CrossJoinHelper.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/CrossJoinHelper.java @@ -177,7 +177,8 @@ private static QueryTable internalJoin( return makeResult(leftTable, rightTable, columnsToAdd, resultStateManager, resultRowSet.toTracking(), - cs -> new CrossJoinRightColumnSource<>(resultStateManager, cs, rightTable.isRefreshing())); + cs -> CrossJoinRightColumnSource.maybeWrap( + resultStateManager, cs, rightTable.isRefreshing())); } final LeftOnlyIncrementalChunkedCrossJoinStateManager jsm = @@ -190,7 +191,7 @@ private static QueryTable internalJoin( final TrackingWritableRowSet resultRowSet = jsm.buildLeftTicking(leftTable, rightTable, bucketingContext.rightSources).toTracking(); final QueryTable resultTable = makeResult(leftTable, rightTable, columnsToAdd, jsm, resultRowSet, - cs -> new CrossJoinRightColumnSource<>(jsm, cs, rightTable.isRefreshing())); + cs -> CrossJoinRightColumnSource.maybeWrap(jsm, cs, rightTable.isRefreshing())); jsm.startTrackingPrevValues(); final ModifiedColumnSet.Transformer leftTransformer = leftTable.newModifiedColumnSetTransformer( @@ -290,7 +291,7 @@ public void onUpdate(final TableUpdate upstream) { final TrackingWritableRowSet resultRowSet = jsm.build(leftTable, rightTable).toTracking(); final QueryTable resultTable = makeResult(leftTable, rightTable, columnsToAdd, jsm, resultRowSet, - cs -> new CrossJoinRightColumnSource<>(jsm, cs, rightTable.isRefreshing())); + cs -> CrossJoinRightColumnSource.maybeWrap(jsm, cs, rightTable.isRefreshing())); final ModifiedColumnSet.Transformer rightTransformer = rightTable.newModifiedColumnSetTransformer(resultTable, columnsToAdd); @@ -1045,7 +1046,7 @@ private static QueryTable zeroKeyColumnsJoin( } final QueryTable result = makeResult(leftTable, rightTable, columnsToAdd, crossJoinState, resultRowSet, - cs -> new BitMaskingColumnSource<>(crossJoinState, cs)); + cs -> BitMaskingColumnSource.maybeWrap(crossJoinState, cs)); if (leftTable.isRefreshing() || rightTable.isRefreshing()) { crossJoinState.startTrackingPrevious(); @@ -1409,8 +1410,7 @@ private static <T extends ColumnSource<?>> QueryTable makeResult( final Map<String, ColumnSource<?>> columnSourceMap = new LinkedHashMap<>(); for (final Map.Entry<String, ColumnSource<?>> leftColumn : leftTable.getColumnSourceMap().entrySet()) { - final BitShiftingColumnSource<?> wrappedSource = - new BitShiftingColumnSource<>(joinState, leftColumn.getValue()); + final ColumnSource<?> wrappedSource = BitShiftingColumnSource.maybeWrap(joinState, leftColumn.getValue()); columnSourceMap.put(leftColumn.getKey(), wrappedSource); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/FlattenOperation.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/FlattenOperation.java index 499cf580af1..ee526102699 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/FlattenOperation.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/FlattenOperation.java @@ -43,7 +43,7 @@ public Result<QueryTable> initialize(boolean usePrev, long beforeClock) { final long size = usePrev ? rowSet.sizePrev() : rowSet.size(); for (Map.Entry<String, ColumnSource<?>> entry : parent.getColumnSourceMap().entrySet()) { - resultColumns.put(entry.getKey(), new RedirectedColumnSource<>(rowRedirection, entry.getValue())); + resultColumns.put(entry.getKey(), RedirectedColumnSource.maybeRedirect(rowRedirection, entry.getValue())); } resultTable = new QueryTable(RowSetFactory.flat(size).toTracking(), resultColumns); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java index c1e5e02d4d0..be3d3cb90e1 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java @@ -440,7 +440,8 @@ private static QueryTable makeResult(@NotNull final QueryTable leftTable, final boolean rightRefreshingColumns) { final Map<String, ColumnSource<?>> columnSourceMap = new LinkedHashMap<>(leftTable.getColumnSourceMap()); for (MatchPair mp : columnsToAdd) { - final RedirectedColumnSource<?> redirectedColumnSource = + // note that we must always redirect the right-hand side, because unmatched rows will be redirected to null + final ColumnSource<?> redirectedColumnSource = new RedirectedColumnSource<>(rowRedirection, rightTable.getColumnSource(mp.rightColumn())); if (rightRefreshingColumns) { redirectedColumnSource.startTrackingPrevValues(); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java index d6a0d575ec0..da1a97a1391 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java @@ -2297,7 +2297,7 @@ public Table ungroup(boolean nullFill, Collection<? extends ColumnName> columnsT ungroupedSource.initializeBase(initialBase); result = ungroupedSource; } else { - result = new BitShiftingColumnSource<>(shiftState, column); + result = BitShiftingColumnSource.maybeWrap(shiftState, column); } resultMap.put(name, result); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java index 18cc4aba062..ec3db462d80 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java @@ -116,7 +116,7 @@ private QueryTable historicalSort(SortHelpers.SortMapping sortedKeys) { final Map<String, ColumnSource<?>> resultMap = new LinkedHashMap<>(); for (Map.Entry<String, ColumnSource<?>> stringColumnSourceEntry : parent.getColumnSourceMap().entrySet()) { resultMap.put(stringColumnSourceEntry.getKey(), - new RedirectedColumnSource<>(sortMapping, stringColumnSourceEntry.getValue())); + RedirectedColumnSource.maybeRedirect(sortMapping, stringColumnSourceEntry.getValue())); } resultTable = new QueryTable(resultRowSet, resultMap); @@ -148,7 +148,7 @@ private Result<QueryTable> streamSort(@NotNull final SortHelpers.SortMapping ini final Map<String, ColumnSource<?>> resultMap = new LinkedHashMap<>(); for (Map.Entry<String, ColumnSource<?>> stringColumnSourceEntry : parent.getColumnSourceMap().entrySet()) { resultMap.put(stringColumnSourceEntry.getKey(), - new RedirectedColumnSource<>(sortMapping, stringColumnSourceEntry.getValue())); + RedirectedColumnSource.maybeRedirect(sortMapping, stringColumnSourceEntry.getValue())); } resultTable = new QueryTable(resultRowSet, resultMap); @@ -256,7 +256,7 @@ public Result<QueryTable> initialize(boolean usePrev, long beforeClock) { for (Map.Entry<String, ColumnSource<?>> stringColumnSourceEntry : parent.getColumnSourceMap().entrySet()) { resultMap.put(stringColumnSourceEntry.getKey(), - new RedirectedColumnSource<>(sortMapping, stringColumnSourceEntry.getValue())); + RedirectedColumnSource.maybeRedirect(sortMapping, stringColumnSourceEntry.getValue())); } // noinspection unchecked @@ -288,13 +288,20 @@ public Result<QueryTable> initialize(boolean usePrev, long beforeClock) { } } + /** + * Get the row redirection for a sort result. + * + * @param sortResult The sort result table; <em>must</em> be the direct result of a sort. + * @return The row redirection if at least one column required redirection, otherwise {@code null} + */ public static RowRedirection getRowRedirection(@NotNull final Table sortResult) { - final String firstColumnName = sortResult.getDefinition().getColumns().get(0).getName(); - final ColumnSource<?> firstColumnSource = sortResult.getColumnSource(firstColumnName); - if (!(firstColumnSource instanceof RedirectedColumnSource)) { - return null; + for (final ColumnSource<?> columnSource : sortResult.getColumnSources()) { + if (!(columnSource instanceof RedirectedColumnSource)) { + continue; + } + return ((RedirectedColumnSource<?>) columnSource).getRowRedirection(); } - return ((RedirectedColumnSource) firstColumnSource).getRowRedirection(); + return null; } /** diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/BaseAddOnlyFirstOrLastChunkedOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/BaseAddOnlyFirstOrLastChunkedOperator.java index b1c88357e58..dd547a33b64 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/BaseAddOnlyFirstOrLastChunkedOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/BaseAddOnlyFirstOrLastChunkedOperator.java @@ -35,9 +35,8 @@ abstract class BaseAddOnlyFirstOrLastChunkedOperator this.resultColumns = new LinkedHashMap<>(resultPairs.length); for (final MatchPair mp : resultPairs) { - // noinspection unchecked - resultColumns.put(mp.leftColumn(), - new RedirectedColumnSource(rowRedirection, originalTable.getColumnSource(mp.rightColumn()))); + resultColumns.put(mp.leftColumn(), RedirectedColumnSource.maybeRedirect( + rowRedirection, originalTable.getColumnSource(mp.rightColumn()))); } if (exposeRedirectionAs != null) { resultColumns.put(exposeRedirectionAs, redirections); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/FirstOrLastChunkedOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/FirstOrLastChunkedOperator.java index 2769566928d..77144d84ea0 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/FirstOrLastChunkedOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/FirstOrLastChunkedOperator.java @@ -44,9 +44,8 @@ public class FirstOrLastChunkedOperator this.resultColumns = new LinkedHashMap<>(resultPairs.length); for (final MatchPair mp : resultPairs) { - // noinspection unchecked - resultColumns.put(mp.leftColumn(), - new RedirectedColumnSource(rowRedirection, originalTable.getColumnSource(mp.rightColumn()))); + resultColumns.put(mp.leftColumn(), RedirectedColumnSource.maybeRedirect( + rowRedirection, originalTable.getColumnSource(mp.rightColumn()))); } exposeRedirections = exposeRedirectionAs != null; if (exposeRedirectionAs != null) { @@ -298,9 +297,8 @@ private class DuplicateOperator implements IterativeChunkedAggregationOperator { private DuplicateOperator(MatchPair[] resultPairs, Table table, String exposeRedirectionAs) { for (final MatchPair mp : resultPairs) { - // noinspection unchecked resultColumns.put(mp.leftColumn(), - new RedirectedColumnSource(rowRedirection, table.getColumnSource(mp.rightColumn()))); + RedirectedColumnSource.maybeRedirect(rowRedirection, table.getColumnSource(mp.rightColumn()))); } if (exposeRedirectionAs != null) { resultColumns.put(exposeRedirectionAs, redirections); @@ -466,9 +464,8 @@ private ComplementaryOperator(boolean isFirst, MatchPair[] resultPairs, Table ta this.resultColumns = new LinkedHashMap<>(resultPairs.length); for (final MatchPair mp : resultPairs) { - // noinspection unchecked resultColumns.put(mp.leftColumn(), - new RedirectedColumnSource(rowRedirection, table.getColumnSource(mp.rightColumn()))); + RedirectedColumnSource.maybeRedirect(rowRedirection, table.getColumnSource(mp.rightColumn()))); } exposeRedirections = exposeRedirectionAs != null; if (exposeRedirections) { diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerOpenAddressedBase.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerOpenAddressedBase.java index 8c6f5fd55a2..90b672d798b 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerOpenAddressedBase.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerOpenAddressedBase.java @@ -140,7 +140,8 @@ public ColumnSource[] getKeyHashTableSources() { alternateKeySources[kci], mainKeySources[kci]); } // noinspection unchecked - keyHashTableSources[kci] = new RedirectedColumnSource(resultIndexToHashSlot, alternatingColumnSources[kci]); + keyHashTableSources[kci] = + RedirectedColumnSource.maybeRedirect(resultIndexToHashSlot, alternatingColumnSources[kci]); } return keyHashTableSources; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerTypedBase.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerTypedBase.java index f6ce5d37929..c0fc54b923d 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerTypedBase.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/IncrementalChunkedOperatorAggregationStateManagerTypedBase.java @@ -76,7 +76,7 @@ public ColumnSource[] getKeyHashTableSources() { final ColumnSource[] keyHashTableSources = new ColumnSource[mainKeySources.length]; for (int kci = 0; kci < mainKeySources.length; ++kci) { // noinspection unchecked - keyHashTableSources[kci] = new RedirectedColumnSource(resultRowKeyToHashSlot, + keyHashTableSources[kci] = RedirectedColumnSource.maybeRedirect(resultRowKeyToHashSlot, new HashTableColumnSource(mainKeySources[kci], overflowKeySources[kci])); } return keyHashTableSources; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/SortedFirstOrLastChunkedOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/SortedFirstOrLastChunkedOperator.java index daa30528726..c86df1511ca 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/SortedFirstOrLastChunkedOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/SortedFirstOrLastChunkedOperator.java @@ -49,9 +49,8 @@ public class SortedFirstOrLastChunkedOperator this.resultColumns = new LinkedHashMap<>(); for (final MatchPair mp : resultNames) { - // noinspection unchecked,rawtypes - resultColumns.put(mp.leftColumn(), - new RedirectedColumnSource(rowRedirection, originalTable.getColumnSource(mp.rightColumn()))); + resultColumns.put(mp.leftColumn(), RedirectedColumnSource.maybeRedirect( + rowRedirection, originalTable.getColumnSource(mp.rightColumn()))); } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerOpenAddressedBase.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerOpenAddressedBase.java index 13a9134b9c7..7e5e2f86fa6 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerOpenAddressedBase.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerOpenAddressedBase.java @@ -69,7 +69,7 @@ public ColumnSource[] getKeyHashTableSources() { final ColumnSource[] keyHashTableSources = new ColumnSource[mainKeySources.length]; for (int kci = 0; kci < mainKeySources.length; ++kci) { // noinspection unchecked - keyHashTableSources[kci] = new RedirectedColumnSource(resultIndexToHashSlot, mainKeySources[kci]); + keyHashTableSources[kci] = RedirectedColumnSource.maybeRedirect(resultIndexToHashSlot, mainKeySources[kci]); } return keyHashTableSources; } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerTypedBase.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerTypedBase.java index 32a3a555d74..26d492d449f 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerTypedBase.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/StaticChunkedOperatorAggregationStateManagerTypedBase.java @@ -123,7 +123,7 @@ public ColumnSource[] getKeyHashTableSources() { final ColumnSource[] keyHashTableSources = new ColumnSource[mainKeySources.length]; for (int kci = 0; kci < mainKeySources.length; ++kci) { // noinspection unchecked - keyHashTableSources[kci] = new RedirectedColumnSource(resultIndexToHashSlot, + keyHashTableSources[kci] = RedirectedColumnSource.maybeRedirect(resultIndexToHashSlot, new HashTableColumnSource(mainKeySources[kci], overflowKeySources[kci])); } return keyHashTableSources; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/remote/InitialSnapshotTable.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/remote/InitialSnapshotTable.java index e15c2567830..0cf2b3bfab0 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/remote/InitialSnapshotTable.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/remote/InitialSnapshotTable.java @@ -195,7 +195,7 @@ public static InitialSnapshotTable setupInitialSnapshotTable( writableSources[ci] = ArrayBackedColumnSource.getMemoryColumnSource( 0, column.getDataType(), column.getComponentType()); finalColumns.put(column.getName(), - new WritableRedirectedColumnSource<>(rowRedirection, writableSources[ci], 0)); + WritableRedirectedColumnSource.maybeRedirect(rowRedirection, writableSources[ci], 0)); } // This table does not run, so we don't need to tell our row redirection or column source to start // tracking diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/replay/QueryReplayGroupedTable.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/replay/QueryReplayGroupedTable.java index f03d51ac41a..7b4ee746350 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/replay/QueryReplayGroupedTable.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/replay/QueryReplayGroupedTable.java @@ -34,7 +34,7 @@ private static Map<String, ColumnSource<?>> getResultSources(Map<String, ? exten Map<String, ColumnSource<?>> result = new LinkedHashMap<>(); for (Map.Entry<String, ? extends ColumnSource<?>> stringEntry : input.entrySet()) { ColumnSource<?> value = stringEntry.getValue(); - result.put(stringEntry.getKey(), new RedirectedColumnSource<>(rowRedirection, value)); + result.put(stringEntry.getKey(), RedirectedColumnSource.maybeRedirect(rowRedirection, value)); } return result; } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/SelectAndViewAnalyzer.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/SelectAndViewAnalyzer.java index 194c34bbc69..4e6ea764e14 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/SelectAndViewAnalyzer.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/SelectAndViewAnalyzer.java @@ -167,7 +167,7 @@ public static SelectAndViewAnalyzer create(final Mode mode, final Map<String, Co } case SELECT_REDIRECTED_STATIC: { final WritableColumnSource<?> underlyingSource = sc.newDestInstance(rowSet.size()); - final WritableColumnSource<?> scs = new WritableRedirectedColumnSource<>( + final WritableColumnSource<?> scs = WritableRedirectedColumnSource.maybeRedirect( rowRedirection, underlyingSource, rowSet.size()); analyzer = analyzer.createLayerForSelect(rowSet, sc.getName(), sc, scs, underlyingSource, distinctDeps, @@ -183,7 +183,8 @@ public static SelectAndViewAnalyzer create(final Mode mode, final Map<String, Co WritableColumnSource<?> underlyingSource = null; if (rowRedirection != null) { underlyingSource = scs; - scs = new WritableRedirectedColumnSource<>(rowRedirection, underlyingSource, rowSet.intSize()); + scs = WritableRedirectedColumnSource.maybeRedirect( + rowRedirection, underlyingSource, rowSet.intSize()); } analyzer = analyzer.createLayerForSelect(rowSet, sc.getName(), sc, scs, underlyingSource, distinctDeps, diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/StaticFlattenLayer.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/StaticFlattenLayer.java index e9e2f95294b..ba4d224f4c9 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/StaticFlattenLayer.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/StaticFlattenLayer.java @@ -48,7 +48,7 @@ final public class StaticFlattenLayer extends SelectAndViewAnalyzer { return; } - overriddenColumns.put(name, new RedirectedColumnSource<>(rowRedirection, cs)); + overriddenColumns.put(name, RedirectedColumnSource.maybeRedirect(rowRedirection, cs)); }); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java index 29e6b385f55..95643096d0e 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java @@ -21,10 +21,25 @@ public class BitMaskingColumnSource<T> extends AbstractColumnSource<T> implements UngroupableColumnSource { + /** + * Wrap the innerSource if it is not agnostic to redirection. Otherwise, return the innerSource. + * + * @param shiftState The cross join shift state to use + * @param innerSource The column source to redirect + */ + public static <T> ColumnSource<T> maybeWrap( + final ZeroKeyCrossJoinShiftState shiftState, + @NotNull final ColumnSource<T> innerSource) { + if (innerSource instanceof RowKeyAgnosticColumnSource) { + return innerSource; + } + return new BitMaskingColumnSource<>(shiftState, innerSource); + } + private final ZeroKeyCrossJoinShiftState shiftState; private final ColumnSource<T> innerSource; - public BitMaskingColumnSource( + protected BitMaskingColumnSource( final ZeroKeyCrossJoinShiftState shiftState, @NotNull final ColumnSource<T> innerSource) { super(innerSource.getType()); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java index 5fec3f136c7..e461dd19361 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java @@ -24,10 +24,27 @@ public class BitShiftingColumnSource<T> extends AbstractColumnSource<T> implements UngroupableColumnSource { + /** + * Wrap the innerSource if it is not agnostic to redirection. Otherwise, return the innerSource. + * + * @param shiftState The cross join shift state to use + * @param innerSource The column source to redirect + */ + public static <T> ColumnSource<T> maybeWrap( + @NotNull final CrossJoinShiftState shiftState, + @NotNull final ColumnSource<T> innerSource) { + if (innerSource instanceof RowKeyAgnosticColumnSource) { + return innerSource; + } + return new BitShiftingColumnSource<>(shiftState, innerSource); + } + private final CrossJoinShiftState shiftState; private final ColumnSource<T> innerSource; - public BitShiftingColumnSource(final CrossJoinShiftState shiftState, @NotNull final ColumnSource<T> innerSource) { + protected BitShiftingColumnSource( + @NotNull final CrossJoinShiftState shiftState, + @NotNull final ColumnSource<T> innerSource) { super(innerSource.getType()); this.shiftState = shiftState; this.innerSource = innerSource; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java new file mode 100644 index 00000000000..f39f1ee3925 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.engine.table.impl.sources; + +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.ObjectChunk; +import io.deephaven.chunk.WritableChunk; +import io.deephaven.chunk.WritableObjectChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; +import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; +import io.deephaven.engine.updategraph.LogicalClock; +import io.deephaven.util.QueryConstants; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Single value source for Boolean. + */ +public class BooleanSingleValueSource extends SingleValueColumnSource<Boolean> implements MutableColumnSourceGetDefaults.ForBoolean { + private Boolean current; + private transient Boolean prev; + + BooleanSingleValueSource() { + super(Boolean.class); + current = QueryConstants.NULL_BOOLEAN; + prev = QueryConstants.NULL_BOOLEAN; + } + + @Nullable + @Override + public Boolean get(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return QueryConstants.NULL_BOOLEAN; + } + return current; + } + + @Nullable + @Override + public Boolean getPrev(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return QueryConstants.NULL_BOOLEAN; + } + if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { + return current; + } + return prev; + } + + @Override + public final void set(Boolean value) { + if (isTrackingPrevValues) { + final long currentStep = LogicalClock.DEFAULT.currentStep(); + if (changeTime < currentStep) { + prev = current; + changeTime = currentStep; + } + } + current = value; + } + + @Override + public final void set(long key, Boolean value) { + set(value); + } + + @Override + public void setNull(long key) { + // region null set + set(QueryConstants.NULL_BOOLEAN); + // endregion null set + } + + @Override + public final void fillFromChunk( + @NotNull FillFromContext context, + @NotNull Chunk<? extends Values> src, + @NotNull RowSequence orderedKeys) { + if (orderedKeys.isEmpty()) { + return; + } + + // We can only hold one value anyway, so arbitrarily take the first value in the chunk and ignore the rest. + final ObjectChunk<Boolean, ? extends Values> chunk = src.asObjectChunk(); + set(chunk.get(0)); + } + + @Override + public void fillFromChunkUnordered( + @NotNull FillFromContext context, + @NotNull Chunk<? extends Values> src, + @NotNull LongChunk<RowKeys> keys) { + if (keys.size() == 0) { + return; + } + // We can only hold one value anyway, so arbitrarily take the first value in the chunk and ignore the rest. + final ObjectChunk<Boolean, ? extends Values> chunk = src.asObjectChunk(); + set(chunk.get(0)); + } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), get(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), get(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + Boolean value = get(0); + final WritableObjectChunk<Boolean, ? super Values> destChunk = dest.asWritableObjectChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + Boolean value = getPrev(0); + final WritableObjectChunk<Boolean, ? super Values> destChunk = dest.asWritableObjectChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } +} \ No newline at end of file diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java index 7ac7717420a..c08f5404b2a 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java @@ -8,12 +8,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableByteChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.ByteChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -89,11 +89,17 @@ public final void setNull(long key) { @Override public final byte getByte(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_BYTE; + } return current; } @Override public final byte getPrevByte(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_BYTE; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -119,4 +125,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final ByteChunk<? extends Values> chunk = src.asByteChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableByteChunk().fillWithValue(0, rowSequence.intSize(), getByte(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableByteChunk().fillWithValue(0, rowSequence.intSize(), getPrevByte(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + byte value = getByte(0); + final WritableByteChunk<? super Values> destChunk = dest.asWritableByteChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BYTE : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + byte value = getPrevByte(0); + final WritableByteChunk<? super Values> destChunk = dest.asWritableByteChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BYTE : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java index 330ed39e385..0cde437c6b9 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java @@ -3,12 +3,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableCharChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.CharChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -84,11 +84,17 @@ public final void setNull(long key) { @Override public final char getChar(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_CHAR; + } return current; } @Override public final char getPrevChar(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_CHAR; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -114,4 +120,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final CharChunk<? extends Values> chunk = src.asCharChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableCharChunk().fillWithValue(0, rowSequence.intSize(), getChar(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableCharChunk().fillWithValue(0, rowSequence.intSize(), getPrevChar(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + char value = getChar(0); + final WritableCharChunk<? super Values> destChunk = dest.asWritableCharChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_CHAR : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + char value = getPrevChar(0); + final WritableCharChunk<? super Values> destChunk = dest.asWritableCharChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_CHAR : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java index d732c74ed04..a6b437a0b90 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java @@ -29,6 +29,7 @@ import io.deephaven.engine.rowset.RowSet; import io.deephaven.engine.rowset.TrackingRowSet; import io.deephaven.engine.table.impl.util.ChunkUtils; +import io.deephaven.proto.backplane.grpc.NullValue; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableLong; import org.jetbrains.annotations.NotNull; @@ -36,13 +37,34 @@ import static io.deephaven.util.QueryConstants.*; public class CrossJoinRightColumnSource<T> extends AbstractColumnSource<T> implements UngroupableColumnSource { + + /** + * Wrap the innerSource if it is not agnostic to redirection. Otherwise, return the innerSource. + * + * @param crossJoinManager The cross join manager to use + * @param innerSource The column source to redirect + * @param rightIsLive Whether the right side is live + */ + public static <T> ColumnSource<T> maybeWrap( + @NotNull final CrossJoinStateManager crossJoinManager, + @NotNull final ColumnSource<T> innerSource, + boolean rightIsLive) { + // Force wrapping if this is a leftOuterJoin or else we will not see the nulls; unless every row is null. + if ((!crossJoinManager.leftOuterJoin() && innerSource instanceof RowKeyAgnosticColumnSource) + || innerSource instanceof NullValueColumnSource) { + return innerSource; + } + return new CrossJoinRightColumnSource<>(crossJoinManager, innerSource, rightIsLive); + } + private final boolean rightIsLive; private final CrossJoinStateManager crossJoinManager; protected final ColumnSource<T> innerSource; - - public CrossJoinRightColumnSource(@NotNull final CrossJoinStateManager crossJoinManager, - @NotNull final ColumnSource<T> innerSource, boolean rightIsLive) { + protected CrossJoinRightColumnSource( + @NotNull final CrossJoinStateManager crossJoinManager, + @NotNull final ColumnSource<T> innerSource, + boolean rightIsLive) { super(innerSource.getType()); this.rightIsLive = rightIsLive; this.crossJoinManager = crossJoinManager; @@ -397,7 +419,6 @@ private static class FillContext implements ColumnSource.FillContext { private final ResettableWritableChunk<Values> innerOrderedValuesSlice; private final DupExpandKernel dupExpandKernel; private final PermuteKernel permuteKernel; - private final boolean allowRightSideNulls; FillContext(final CrossJoinRightColumnSource<?> cs, final int chunkCapacity, final SharedContext sharedContext) { @@ -420,7 +441,6 @@ private static class FillContext implements ColumnSource.FillContext { dupExpandKernel = DupExpandKernel.makeDupExpand(cs.getChunkType()); permuteKernel = PermuteKernel.makePermuteKernel(cs.getChunkType()); } - allowRightSideNulls = cs.crossJoinManager.leftOuterJoin(); } @Override diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java index b6e28cd2c91..bff59af4298 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java @@ -8,12 +8,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableDoubleChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.DoubleChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -89,11 +89,17 @@ public final void setNull(long key) { @Override public final double getDouble(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_DOUBLE; + } return current; } @Override public final double getPrevDouble(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_DOUBLE; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -119,4 +125,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final DoubleChunk<? extends Values> chunk = src.asDoubleChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableDoubleChunk().fillWithValue(0, rowSequence.intSize(), getDouble(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableDoubleChunk().fillWithValue(0, rowSequence.intSize(), getPrevDouble(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + double value = getDouble(0); + final WritableDoubleChunk<? super Values> destChunk = dest.asWritableDoubleChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_DOUBLE : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + double value = getPrevDouble(0); + final WritableDoubleChunk<? super Values> destChunk = dest.asWritableDoubleChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_DOUBLE : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java index 7c9aac9336a..9d10fb61b1e 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java @@ -8,12 +8,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableFloatChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.FloatChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -89,11 +89,17 @@ public final void setNull(long key) { @Override public final float getFloat(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_FLOAT; + } return current; } @Override public final float getPrevFloat(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_FLOAT; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -119,4 +125,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final FloatChunk<? extends Values> chunk = src.asFloatChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableFloatChunk().fillWithValue(0, rowSequence.intSize(), getFloat(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableFloatChunk().fillWithValue(0, rowSequence.intSize(), getPrevFloat(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + float value = getFloat(0); + final WritableFloatChunk<? super Values> destChunk = dest.asWritableFloatChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_FLOAT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + float value = getPrevFloat(0); + final WritableFloatChunk<? super Values> destChunk = dest.asWritableFloatChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_FLOAT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java index 6a1b5cbe69b..21ded020289 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java @@ -8,12 +8,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableIntChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.IntChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -89,11 +89,17 @@ public final void setNull(long key) { @Override public final int getInt(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_INT; + } return current; } @Override public final int getPrevInt(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_INT; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -119,4 +125,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final IntChunk<? extends Values> chunk = src.asIntChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableIntChunk().fillWithValue(0, rowSequence.intSize(), getInt(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableIntChunk().fillWithValue(0, rowSequence.intSize(), getPrevInt(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + int value = getInt(0); + final WritableIntChunk<? super Values> destChunk = dest.asWritableIntChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_INT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + int value = getPrevInt(0); + final WritableIntChunk<? super Values> destChunk = dest.asWritableIntChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_INT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java index 7891841cda1..ab7df16511e 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java @@ -8,12 +8,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableLongChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.LongChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -89,11 +89,17 @@ public final void setNull(long key) { @Override public final long getLong(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_LONG; + } return current; } @Override public final long getPrevLong(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_LONG; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -119,4 +125,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final LongChunk<? extends Values> chunk = src.asLongChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableLongChunk().fillWithValue(0, rowSequence.intSize(), getLong(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableLongChunk().fillWithValue(0, rowSequence.intSize(), getPrevLong(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + long value = getLong(0); + final WritableLongChunk<? super Values> destChunk = dest.asWritableLongChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_LONG : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + long value = getPrevLong(0); + final WritableLongChunk<? super Values> destChunk = dest.asWritableLongChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_LONG : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java index e69eb0bb64d..003042f2779 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java @@ -5,7 +5,9 @@ import io.deephaven.base.Pair; import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.LongChunk; import io.deephaven.chunk.attributes.Values; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.ColumnDefinition; import io.deephaven.engine.table.TableDefinition; @@ -26,7 +28,7 @@ * A column source that returns null for all keys. */ public class NullValueColumnSource<T> extends AbstractColumnSource<T> - implements ShiftData.ShiftCallback, InMemoryColumnSource { + implements ShiftData.ShiftCallback, RowKeyAgnosticColumnSource<Values> { private static final KeyedObjectKey.Basic<Pair<Class<?>, Class<?>>, NullValueColumnSource<?>> KEY_TYPE = new KeyedObjectKey.Basic<>() { @Override @@ -192,4 +194,23 @@ public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { fillChunk(context, destination, rowSequence); } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull LongChunk<? extends RowKeys> keys) { + // note that we do not need to look for RowSequence.NULL_ROW_KEY; all values are null + destination.setSize(keys.size()); + destination.fillWithNullValue(0, keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context, destination, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java index e06b0f04b5a..01e0e1e7bec 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java @@ -8,12 +8,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableObjectChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.ObjectChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -77,11 +77,17 @@ public final void setNull(long key) { @Override public final T get(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return null; + } return current; } @Override public final T getPrev(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return null; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -107,4 +113,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final ObjectChunk<T, ? extends Values> chunk = src.asObjectChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), get(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), getPrev(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + T value = get(0); + final WritableObjectChunk<T, ? super Values> destChunk = dest.asWritableObjectChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + T value = getPrev(0); + final WritableObjectChunk<T, ? super Values> destChunk = dest.asWritableObjectChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java index e10b4b7c1a8..da3a359c279 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java @@ -8,6 +8,7 @@ import io.deephaven.engine.table.SharedContext; import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.Table; +import io.deephaven.engine.table.WritableColumnSource; import io.deephaven.engine.table.impl.util.RowRedirection; import io.deephaven.util.BooleanUtils; import io.deephaven.engine.table.impl.join.dupexpand.DupExpandKernel; @@ -35,11 +36,27 @@ */ public class RedirectedColumnSource<T> extends AbstractDeferredGroupingColumnSource<T> implements UngroupableColumnSource { + /** + * Redirect the innerSource if it is not agnostic to redirection. Otherwise, return the innerSource. + * + * @param rowRedirection The row redirection to use + * @param innerSource The column source to redirect + */ + public static <T> ColumnSource<T> maybeRedirect( + @NotNull final RowRedirection rowRedirection, + @NotNull final ColumnSource<T> innerSource) { + if (innerSource instanceof RowKeyAgnosticColumnSource) { + return innerSource; + } + return new RedirectedColumnSource<>(rowRedirection, innerSource); + } + protected final RowRedirection rowRedirection; protected final ColumnSource<T> innerSource; private final boolean ascendingMapping; - public RedirectedColumnSource(@NotNull final RowRedirection rowRedirection, + public RedirectedColumnSource( + @NotNull final RowRedirection rowRedirection, @NotNull final ColumnSource<T> innerSource) { super(innerSource.getType()); this.rowRedirection = rowRedirection; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java new file mode 100644 index 00000000000..726872f4dbf --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.engine.table.impl.sources; + +import io.deephaven.chunk.attributes.Any; + +/** + * This is a marker interface for column sources that are agnostic when fulfilling requested row keys. + * + * The marker extends from {@link InMemoryColumnSource} whether the column source is actually in memory or not; it would + * be a waste to materialize the same value for all rows via select. + */ +public interface RowKeyAgnosticColumnSource<ATTR extends Any> extends FillUnordered<ATTR>, InMemoryColumnSource { + +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java index ae99200ca48..8a54ec8aa43 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java @@ -8,12 +8,12 @@ */ package io.deephaven.engine.table.impl.sources; +import io.deephaven.chunk.WritableShortChunk; +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; import io.deephaven.engine.rowset.chunkattributes.RowKeys; -import io.deephaven.util.QueryConstants; import io.deephaven.chunk.ShortChunk; import io.deephaven.chunk.Chunk; import io.deephaven.chunk.LongChunk; @@ -89,11 +89,17 @@ public final void setNull(long key) { @Override public final short getShort(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_SHORT; + } return current; } @Override public final short getPrevShort(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_SHORT; + } if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { return current; } @@ -119,4 +125,49 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch final ShortChunk<? extends Values> chunk = src.asShortChunk(); set(chunk.get(0)); } + + @Override + public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, + @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableShortChunk().fillWithValue(0, rowSequence.intSize(), getShort(0)); + } + + @Override + public void fillPrevChunk(@NotNull FillContext context, + @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + destination.setSize(rowSequence.intSize()); + destination.asWritableShortChunk().fillWithValue(0, rowSequence.intSize(), getPrevShort(0)); + } + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + short value = getShort(0); + final WritableShortChunk<? super Values> destChunk = dest.asWritableShortChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_SHORT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + short value = getPrevShort(0); + final WritableShortChunk<? super Values> destChunk = dest.asWritableShortChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_SHORT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java index 8be483202ce..bf1a924604d 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java @@ -4,13 +4,15 @@ package io.deephaven.engine.table.impl.sources; import io.deephaven.chunk.attributes.Values; +import io.deephaven.engine.rowset.RowSequence; import io.deephaven.engine.table.ChunkSink; import io.deephaven.engine.table.WritableColumnSource; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.util.ShiftData; public abstract class SingleValueColumnSource<T> extends AbstractColumnSource<T> - implements WritableColumnSource<T>, ChunkSink<Values>, ShiftData.ShiftCallback, InMemoryColumnSource { + implements WritableColumnSource<T>, ChunkSink<Values>, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { protected transient long changeTime; protected boolean isTrackingPrevValues; @@ -43,6 +45,8 @@ public static <T> SingleValueColumnSource<T> getSingleValueColumnSource(Class<T> result = new LongSingleValueSource(); } else if (type == Short.class || type == short.class) { result = new ShortSingleValueSource(); + } else if (type == Boolean.class || type == boolean.class) { + result = new BooleanSingleValueSource(); } else { result = new ObjectSingleValueSource<>(type); } @@ -91,6 +95,13 @@ public void setNull() { throw new UnsupportedOperationException(); } + @Override + public final void setNull(RowSequence orderedKeys) { + if (!orderedKeys.isEmpty()) { + setNull(); + } + } + @Override public final void ensureCapacity(long capacity, boolean nullFilled) { // Do nothing diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java index edee7e4f34a..4cc083580b8 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java @@ -19,7 +19,25 @@ * {@link RowRedirection}. */ public class WritableRedirectedColumnSource<T> extends RedirectedColumnSource<T> implements WritableColumnSource<T> { - private long maxInnerIndex; + /** + * Redirect the innerSource if it is not agnostic to redirection. Otherwise, return the innerSource. + * + * @param rowRedirection The row redirection to use + * @param innerSource The column source to redirect + * @param maxInnerIndex The maximum row key available in innerSource + */ + public static <T> WritableColumnSource<T> maybeRedirect( + @NotNull final RowRedirection rowRedirection, + @NotNull final WritableColumnSource<T> innerSource, + final long maxInnerIndex) { + if (innerSource instanceof RowKeyAgnosticColumnSource) { + return innerSource; + } + return new WritableRedirectedColumnSource<>(rowRedirection, innerSource, maxInnerIndex); + } + + /** The maximum row key available in innerSource. */ + private final long maxInnerIndex; /** * Create a type-appropriate WritableRedirectedColumnSource for the supplied {@link WritableRowRedirection} and @@ -29,7 +47,8 @@ public class WritableRedirectedColumnSource<T> extends RedirectedColumnSource<T> * @param innerSource The column source to redirect * @param maxInnerIndex The maximum row key available in innerSource */ - public WritableRedirectedColumnSource(@NotNull final RowRedirection rowRedirection, + protected WritableRedirectedColumnSource( + @NotNull final RowRedirection rowRedirection, @NotNull final ColumnSource<T> innerSource, final long maxInnerIndex) { super(rowRedirection, innerSource); @@ -140,7 +159,7 @@ public <ALTERNATE_DATA_TYPE> boolean allowsReinterpret(@NotNull Class<ALTERNATE_ @Override protected <ALTERNATE_DATA_TYPE> ColumnSource<ALTERNATE_DATA_TYPE> doReinterpret( @NotNull Class<ALTERNATE_DATA_TYPE> alternateDataType) { - return new WritableRedirectedColumnSource<>( - rowRedirection, innerSource.reinterpret(alternateDataType), maxInnerIndex); + return WritableRedirectedColumnSource.maybeRedirect(rowRedirection, + (WritableColumnSource<ALTERNATE_DATA_TYPE>) innerSource.reinterpret(alternateDataType), maxInnerIndex); } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java index 05a54abd5fa..279b052a10d 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java @@ -1,3 +1,6 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ /* * --------------------------------------------------------------------------------------------------------------------- * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit ImmutableConstantCharSource and regenerate @@ -7,9 +10,12 @@ import io.deephaven.engine.table.ColumnSource; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableByteChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -27,7 +33,8 @@ */ public class ImmutableConstantByteSource extends AbstractColumnSource<Byte> - implements ImmutableColumnSourceGetDefaults.ForByte, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForByte, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final byte value; @@ -80,4 +87,26 @@ protected <ALTERNATE_DATA_TYPE> ColumnSource<ALTERNATE_DATA_TYPE> doReinterpret( return (ColumnSource<ALTERNATE_DATA_TYPE>) new ByteAsBooleanColumnSource(this); } // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableByteChunk<? super Values> destChunk = dest.asWritableByteChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BYTE : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java index c39a3d1f530..95d8afb17b5 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java @@ -1,8 +1,14 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ package io.deephaven.engine.table.impl.sources.immutable; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableCharChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -20,7 +26,8 @@ */ public class ImmutableConstantCharSource extends AbstractColumnSource<Character> - implements ImmutableColumnSourceGetDefaults.ForChar, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForChar, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final char value; @@ -62,4 +69,26 @@ public final void shift(final long start, final long end, final long offset) {} // region reinterpret // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableCharChunk<? super Values> destChunk = dest.asWritableCharChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_CHAR : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java index 54c21ecd4c3..72d72ba7060 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java @@ -1,3 +1,6 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ /* * --------------------------------------------------------------------------------------------------------------------- * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit ImmutableConstantCharSource and regenerate @@ -5,9 +8,12 @@ */ package io.deephaven.engine.table.impl.sources.immutable; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableDoubleChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -25,7 +31,8 @@ */ public class ImmutableConstantDoubleSource extends AbstractColumnSource<Double> - implements ImmutableColumnSourceGetDefaults.ForDouble, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForDouble, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final double value; @@ -67,4 +74,26 @@ public final void shift(final long start, final long end, final long offset) {} // region reinterpret // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableDoubleChunk<? super Values> destChunk = dest.asWritableDoubleChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_DOUBLE : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java index f09cfe25540..06a30f4da50 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java @@ -1,3 +1,6 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ /* * --------------------------------------------------------------------------------------------------------------------- * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit ImmutableConstantCharSource and regenerate @@ -5,9 +8,12 @@ */ package io.deephaven.engine.table.impl.sources.immutable; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableFloatChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -25,7 +31,8 @@ */ public class ImmutableConstantFloatSource extends AbstractColumnSource<Float> - implements ImmutableColumnSourceGetDefaults.ForFloat, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForFloat, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final float value; @@ -67,4 +74,26 @@ public final void shift(final long start, final long end, final long offset) {} // region reinterpret // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableFloatChunk<? super Values> destChunk = dest.asWritableFloatChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_FLOAT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java index 3ed6604a411..83b46b7e60c 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java @@ -1,3 +1,6 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ /* * --------------------------------------------------------------------------------------------------------------------- * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit ImmutableConstantCharSource and regenerate @@ -5,9 +8,12 @@ */ package io.deephaven.engine.table.impl.sources.immutable; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableIntChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -25,7 +31,8 @@ */ public class ImmutableConstantIntSource extends AbstractColumnSource<Integer> - implements ImmutableColumnSourceGetDefaults.ForInt, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForInt, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final int value; @@ -67,4 +74,26 @@ public final void shift(final long start, final long end, final long offset) {} // region reinterpret // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableIntChunk<? super Values> destChunk = dest.asWritableIntChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_INT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java index fc269dd4014..3bd263faead 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java @@ -1,3 +1,6 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ /* * --------------------------------------------------------------------------------------------------------------------- * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit ImmutableConstantCharSource and regenerate @@ -9,9 +12,12 @@ import io.deephaven.time.DateTime; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableLongChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -29,7 +35,8 @@ */ public class ImmutableConstantLongSource extends AbstractColumnSource<Long> - implements ImmutableColumnSourceGetDefaults.ForLong, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForLong, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final long value; @@ -82,4 +89,26 @@ protected <ALTERNATE_DATA_TYPE> ColumnSource<ALTERNATE_DATA_TYPE> doReinterpret( return (ColumnSource<ALTERNATE_DATA_TYPE>) new LongAsDateTimeColumnSource(this); } // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableLongChunk<? super Values> destChunk = dest.asWritableLongChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_LONG : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java index d44b6df4e88..947562e4ef5 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java @@ -1,3 +1,6 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ /* * --------------------------------------------------------------------------------------------------------------------- * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit ImmutableConstantCharSource and regenerate @@ -5,9 +8,12 @@ */ package io.deephaven.engine.table.impl.sources.immutable; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableObjectChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -24,7 +30,8 @@ */ public class ImmutableConstantObjectSource<T> extends AbstractColumnSource<T> - implements ImmutableColumnSourceGetDefaults.ForObject<T>, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForObject<T>, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final T value; @@ -66,4 +73,26 @@ public final void shift(final long start, final long end, final long offset) {} // region reinterpret // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableObjectChunk<T, ? super Values> destChunk = dest.asWritableObjectChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java index cdab3b09a31..c394ac5c2bf 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java @@ -1,3 +1,6 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ /* * --------------------------------------------------------------------------------------------------------------------- * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit ImmutableConstantCharSource and regenerate @@ -5,9 +8,12 @@ */ package io.deephaven.engine.table.impl.sources.immutable; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.WritableShortChunk; import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.AbstractColumnSource; import io.deephaven.engine.table.impl.ImmutableColumnSourceGetDefaults; import io.deephaven.engine.table.impl.sources.*; @@ -25,7 +31,8 @@ */ public class ImmutableConstantShortSource extends AbstractColumnSource<Short> - implements ImmutableColumnSourceGetDefaults.ForShort, InMemoryColumnSource, ShiftData.ShiftCallback { + implements ImmutableColumnSourceGetDefaults.ForShort, ShiftData.ShiftCallback, + RowKeyAgnosticColumnSource<Values> { private final short value; @@ -67,4 +74,26 @@ public final void shift(final long start, final long end, final long offset) {} // region reinterpret // endregion reinterpret + + @Override + public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + final WritableShortChunk<? super Values> destChunk = dest.asWritableShortChunk(); + for (int ii = 0; ii < keys.size(); ++ii) { + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_SHORT : value); + } + destChunk.setSize(keys.size()); + } + + @Override + public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + @NotNull LongChunk<? extends RowKeys> keys) { + fillChunkUnordered(context , dest, keys); + } + + @Override + public boolean providesFillUnordered() { + return true; + } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseByteUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseByteUpdateByOperator.java index 1fd0c385d46..24432a06d53 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseByteUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseByteUpdateByOperator.java @@ -101,7 +101,7 @@ public BaseByteUpdateByOperator(@NotNull final MatchPair pair, // region create-dense this.maybeInnerSource = makeDenseSource(); // endregion create-dense - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; // region create-sparse diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseCharUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseCharUpdateByOperator.java index 0e21db78eed..adcf7d101c7 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseCharUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseCharUpdateByOperator.java @@ -95,7 +95,7 @@ public BaseCharUpdateByOperator(@NotNull final MatchPair pair, // region create-dense this.maybeInnerSource = new CharacterArraySource(); // endregion create-dense - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; // region create-sparse diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseDoubleUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseDoubleUpdateByOperator.java index 354860af0ee..c3cbd33c0a9 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseDoubleUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseDoubleUpdateByOperator.java @@ -98,7 +98,7 @@ public BaseDoubleUpdateByOperator(@NotNull final MatchPair pair, this.isRedirected = rowRedirection != null; if(rowRedirection != null) { this.maybeInnerSource = new DoubleArraySource(); - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; this.outputSource = new DoubleSparseArraySource(); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseFloatUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseFloatUpdateByOperator.java index 60ea52d2548..613a699f132 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseFloatUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseFloatUpdateByOperator.java @@ -93,7 +93,7 @@ public BaseFloatUpdateByOperator(@NotNull final MatchPair pair, this.isRedirected = rowRedirection != null; if(rowRedirection != null) { this.maybeInnerSource = new FloatArraySource(); - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; this.outputSource = new FloatSparseArraySource(); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseIntUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseIntUpdateByOperator.java index 49871e2dad3..8adf21343bc 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseIntUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseIntUpdateByOperator.java @@ -100,7 +100,7 @@ public BaseIntUpdateByOperator(@NotNull final MatchPair pair, // region create-dense this.maybeInnerSource = new IntegerArraySource(); // endregion create-dense - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; // region create-sparse diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseLongUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseLongUpdateByOperator.java index cad71cddca9..623359b1e34 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseLongUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseLongUpdateByOperator.java @@ -100,7 +100,7 @@ public BaseLongUpdateByOperator(@NotNull final MatchPair pair, // region create-dense this.maybeInnerSource = new LongArraySource(); // endregion create-dense - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; // region create-sparse diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseObjectUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseObjectUpdateByOperator.java index 477c356fe30..a3bc08f8c3b 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseObjectUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseObjectUpdateByOperator.java @@ -102,7 +102,7 @@ public BaseObjectUpdateByOperator(@NotNull final MatchPair pair, // region create-dense this.maybeInnerSource = new ObjectArraySource(colType); // endregion create-dense - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; // region create-sparse diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseShortUpdateByOperator.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseShortUpdateByOperator.java index 073cf9360eb..158e19f4ecf 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseShortUpdateByOperator.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/updateby/internal/BaseShortUpdateByOperator.java @@ -100,7 +100,7 @@ public BaseShortUpdateByOperator(@NotNull final MatchPair pair, // region create-dense this.maybeInnerSource = new ShortArraySource(); // endregion create-dense - this.outputSource = new WritableRedirectedColumnSource(rowRedirection, maybeInnerSource, 0); + this.outputSource = WritableRedirectedColumnSource.maybeRedirect(rowRedirection, maybeInnerSource, 0); } else { this.maybeInnerSource = null; // region create-sparse diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/util/ColumnsToRowsTransform.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/util/ColumnsToRowsTransform.java index b8aab4bd16c..4089e955bbd 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/util/ColumnsToRowsTransform.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/util/ColumnsToRowsTransform.java @@ -179,7 +179,7 @@ public static Table columnsToRows(final Table source, final String labelColumn, } expandSet.add(name); if (crossJoinShiftState != null) { - resultMap.put(name, new BitShiftingColumnSource<>(crossJoinShiftState, cs)); + resultMap.put(name, BitShiftingColumnSource.maybeWrap(crossJoinShiftState, cs)); } else { resultMap.put(name, cs); } diff --git a/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableNaturalJoinTest.java b/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableNaturalJoinTest.java index e5496b1fe67..3e59a74c830 100644 --- a/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableNaturalJoinTest.java +++ b/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableNaturalJoinTest.java @@ -4,13 +4,16 @@ package io.deephaven.engine.table.impl; import io.deephaven.base.FileUtils; +import io.deephaven.chunk.ObjectChunk; import io.deephaven.datastructures.util.CollectionUtil; import io.deephaven.engine.rowset.RowSet; import io.deephaven.engine.rowset.RowSetBuilderSequential; import io.deephaven.engine.rowset.RowSetFactory; import io.deephaven.engine.rowset.TrackingRowSet; +import io.deephaven.engine.table.ChunkSource; import io.deephaven.engine.table.ColumnDefinition; import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.DataColumn; import io.deephaven.engine.table.Table; import io.deephaven.engine.table.TableDefinition; import io.deephaven.engine.table.impl.indexer.RowSetIndexer; @@ -1576,6 +1579,25 @@ public void testDHC3202_v2() { } } + public void testGetDirectAfterNaturalJoin() { + final Table sodiumLeft = emptyTable(3).updateView("Value=(i%5==0? null : i*2)", "ColLeft=`LeftOnlyContents`"); + final Table peppermintRight = + emptyTable(4).updateView("Value=(i%5==0? null : i)", "ColRight=`RightOnlyContents`"); + final Table vanillaVanilla = sodiumLeft.naturalJoin(peppermintRight, "Value"); + final String rightValue = "RightOnlyContents"; + + final ColumnSource<?> colRightSource = vanillaVanilla.getColumnSource("ColRight"); + try (final ChunkSource.GetContext gc = colRightSource.makeGetContext(3)) { + final ObjectChunk<String, ?> ck = colRightSource.getChunk(gc, vanillaVanilla.getRowSet()).asObjectChunk(); + assertEquals(rightValue, ck.get(0)); + assertEquals(rightValue, ck.get(1)); + assertNull(ck.get(2)); + } + final DataColumn<?> colRight = vanillaVanilla.getColumn("ColRight"); + assertEquals(rightValue, colRight.get(0)); + assertEquals(rightValue, colRight.get(1)); + assertNull(colRight.get(2)); + } private void diskBackedTestHarness(BiConsumer<Table, Table> testFunction) throws IOException { final File leftDirectory = Files.createTempDirectory("QueryTableJoinTest-Left").toFile(); diff --git a/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableAggregationTest.java b/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableAggregationTest.java index 94ca3417c60..6600b19d6bb 100644 --- a/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableAggregationTest.java +++ b/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableAggregationTest.java @@ -80,7 +80,7 @@ private void doOperatorTest(@NotNull final UnaryOperator<Table> operator, final new WrappedRowSetWritableRowRedirection(streamInternalRowSet); streamSources = source.getColumnSourceMap().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, - (entry -> new RedirectedColumnSource<>(streamRedirections, entry.getValue())), + (entry -> RedirectedColumnSource.maybeRedirect(streamRedirections, entry.getValue())), Assert::neverInvoked, LinkedHashMap::new)); } diff --git a/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableOperationsTest.java b/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableOperationsTest.java index 1f049210332..8cf1723cb5e 100644 --- a/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableOperationsTest.java +++ b/engine/table/src/test/java/io/deephaven/engine/table/impl/StreamTableOperationsTest.java @@ -79,7 +79,7 @@ private void doOperatorTest(@NotNull final UnaryOperator<Table> operator, final new WrappedRowSetWritableRowRedirection(streamInternalRowSet); streamSources = source.getColumnSourceMap().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, - (entry -> new RedirectedColumnSource<>(streamRedirections, entry.getValue())), + (entry -> RedirectedColumnSource.maybeRedirect(streamRedirections, entry.getValue())), Assert::neverInvoked, LinkedHashMap::new)); } diff --git a/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/table/BarrageTable.java b/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/table/BarrageTable.java index 3a9d673c3ec..00d50e978a5 100644 --- a/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/table/BarrageTable.java +++ b/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/table/BarrageTable.java @@ -428,7 +428,7 @@ protected static LinkedHashMap<String, ColumnSource<?>> makeColumns( writableSources[ii] = ArrayBackedColumnSource.getMemoryColumnSource( 0, column.getDataType(), column.getComponentType()); finalColumns.put(column.getName(), - new WritableRedirectedColumnSource<>(emptyRowRedirection, writableSources[ii], 0)); + WritableRedirectedColumnSource.maybeRedirect(emptyRowRedirection, writableSources[ii], 0)); } return finalColumns; } diff --git a/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java b/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java index 2a2ca06acf1..6b47485a225 100644 --- a/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java +++ b/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java @@ -160,11 +160,16 @@ private static void replicateObjectSingleValue() throws IOException { "Object current", "T current", "Object prev", "T prev", "ColumnSource<[?] extends Object>", "ColumnSource<? extends T>", + "getObject", "get", + "getPrevObject", "getPrev", "set\\(Object", "set(T", "set\\(long key, Object", "set(long key, T", "set\\(NULL_OBJECT", "set(null", "final ObjectChunk<[?] extends Values>", "final ObjectChunk<T, ? extends Values>", - "unbox\\((.*)\\)", "$1"); + "unbox\\((.*)\\)", "$1", + "NULL_OBJECT", "null", + "WritableObjectChunk<[?] super Values>", "WritableObjectChunk<T, ? super Values>", + "Object value", "T value"); lines = ReplicationUtils.removeRegion(lines, "UnboxedSetter"); lines = ReplicationUtils.replaceRegion(lines, "Constructor", Arrays.asList( " public ObjectSingleValueSource(Class<T> type) {", From 95b56fcebea82b186f4420bd301bad82c2b3ee62 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind <natebauernfeind@deephaven.io> Date: Thu, 19 Jan 2023 10:48:56 -0700 Subject: [PATCH 2/5] Add JavaDoc; add BooleanSingleValueSource to Replication --- .../sources/BooleanSingleValueSource.java | 109 ++++++++++-------- .../table/impl/sources/FillUnordered.java | 18 +++ .../ReplicateSourcesAndChunks.java | 31 +++++ 3 files changed, 110 insertions(+), 48 deletions(-) diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java index f39f1ee3925..6956b5b0f99 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java @@ -1,55 +1,48 @@ /** - * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending + */ +/* + * --------------------------------------------------------------------------------------------------------------------- + * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit CharacterSingleValueSource and regenerate + * --------------------------------------------------------------------------------------------------------------------- */ package io.deephaven.engine.table.impl.sources; -import io.deephaven.chunk.Chunk; -import io.deephaven.chunk.LongChunk; import io.deephaven.chunk.ObjectChunk; -import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.WritableObjectChunk; + +import io.deephaven.chunk.WritableChunk; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.rowset.RowSequence; -import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.impl.MutableColumnSourceGetDefaults; import io.deephaven.engine.updategraph.LogicalClock; -import io.deephaven.util.QueryConstants; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.engine.rowset.RowSequence; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; + +import static io.deephaven.util.QueryConstants.NULL_BOOLEAN; /** * Single value source for Boolean. + * <p> + * The C-haracterSingleValueSource is replicated to all other types with + * io.deephaven.engine.table.impl.sources.Replicate. + * + * (C-haracter is deliberately spelled that way in order to prevent Replicate from altering this very comment). */ public class BooleanSingleValueSource extends SingleValueColumnSource<Boolean> implements MutableColumnSourceGetDefaults.ForBoolean { + private Boolean current; private transient Boolean prev; - BooleanSingleValueSource() { + // region Constructor + public BooleanSingleValueSource() { super(Boolean.class); - current = QueryConstants.NULL_BOOLEAN; - prev = QueryConstants.NULL_BOOLEAN; - } - - @Nullable - @Override - public Boolean get(long rowKey) { - if (rowKey == RowSequence.NULL_ROW_KEY) { - return QueryConstants.NULL_BOOLEAN; - } - return current; - } - - @Nullable - @Override - public Boolean getPrev(long rowKey) { - if (rowKey == RowSequence.NULL_ROW_KEY) { - return QueryConstants.NULL_BOOLEAN; - } - if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { - return current; - } - return prev; + current = NULL_BOOLEAN; + prev = NULL_BOOLEAN; } + // endregion Constructor @Override public final void set(Boolean value) { @@ -63,37 +56,57 @@ public final void set(Boolean value) { current = value; } + // region UnboxedSetter + // endregion UnboxedSetter + + @Override + public final void setNull() { + set(NULL_BOOLEAN); + } + @Override public final void set(long key, Boolean value) { set(value); } @Override - public void setNull(long key) { + public final void setNull(long key) { // region null set - set(QueryConstants.NULL_BOOLEAN); + set(NULL_BOOLEAN); // endregion null set } @Override - public final void fillFromChunk( - @NotNull FillFromContext context, - @NotNull Chunk<? extends Values> src, - @NotNull RowSequence orderedKeys) { - if (orderedKeys.isEmpty()) { - return; + public final Boolean get(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_BOOLEAN; } + return current; + } + @Override + public final Boolean getPrev(long rowKey) { + if (rowKey == RowSequence.NULL_ROW_KEY) { + return NULL_BOOLEAN; + } + if (!isTrackingPrevValues || changeTime < LogicalClock.DEFAULT.currentStep()) { + return current; + } + return prev; + } + + @Override + public final void fillFromChunk(@NotNull FillFromContext context, @NotNull Chunk<? extends Values> src, @NotNull RowSequence rowSequence) { + if (rowSequence.size() == 0) { + return; + } // We can only hold one value anyway, so arbitrarily take the first value in the chunk and ignore the rest. final ObjectChunk<Boolean, ? extends Values> chunk = src.asObjectChunk(); set(chunk.get(0)); } @Override - public void fillFromChunkUnordered( - @NotNull FillFromContext context, - @NotNull Chunk<? extends Values> src, - @NotNull LongChunk<RowKeys> keys) { + public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Chunk<? extends Values> src, @NotNull LongChunk<RowKeys> keys) { if (keys.size() == 0) { return; } @@ -115,7 +128,7 @@ public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), get(0)); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), getPrev(0)); } @Override @@ -125,7 +138,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh Boolean value = get(0); final WritableObjectChunk<Boolean, ? super Values> destChunk = dest.asWritableObjectChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BOOLEAN : value); } destChunk.setSize(keys.size()); } @@ -137,7 +150,7 @@ public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull Writab Boolean value = getPrev(0); final WritableObjectChunk<Boolean, ? super Values> destChunk = dest.asWritableObjectChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BOOLEAN : value); } destChunk.setSize(keys.size()); } @@ -146,4 +159,4 @@ public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull Writab public boolean providesFillUnordered() { return true; } -} \ No newline at end of file +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FillUnordered.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FillUnordered.java index d40eff84d42..f12a524e71b 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FillUnordered.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FillUnordered.java @@ -14,7 +14,16 @@ public interface FillUnordered<ATTR extends Any> { /** * Populates a contiguous portion of the given destination chunk with data corresponding to the keys from the given * {@link LongChunk}. + * <p> + * It behaves as if the following code were executed: * + * <pre> + * destination.setSize(keys.size()); + * for (int ii = 0; ii < keys.size(); ++ii) { + * destination.set(ii, get(keys.get(ii))); + * } + * </pre> + * * @param context A context containing all mutable/state related data used in retrieving the Chunk. * @param dest The chunk to be populated according to {@code keys} * @param keys A chunk of individual, not assumed to be ordered keys to be fetched @@ -27,7 +36,16 @@ void fillChunkUnordered( /** * Populates a contiguous portion of the given destination chunk with prev data corresponding to the keys from the * given {@link LongChunk}. + * <p> + * It behaves as if the following code were executed: * + * <pre> + * destination.setSize(keys.size()); + * for (int ii = 0; ii < keys.size(); ++ii) { + * destination.set(ii, getPrev(keys.get(ii))); + * } + * </pre> + * * @param context A context containing all mutable/state related data used in retrieving the Chunk. * @param dest The chunk to be populated according to {@code keys} * @param keys A chunk of individual, not assumed to be ordered keys to be fetched diff --git a/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java b/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java index 6b47485a225..76086c98f8e 100644 --- a/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java +++ b/replication/static/src/main/java/io/deephaven/replicators/ReplicateSourcesAndChunks.java @@ -139,6 +139,7 @@ private static void replicateSingleValues() throws IOException { charToAllButBoolean( "engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java"); replicateObjectSingleValue(); + replicateBooleanSingleValue(); } private static void replicateObjectSingleValue() throws IOException { @@ -180,6 +181,36 @@ private static void replicateObjectSingleValue() throws IOException { FileUtils.writeLines(resultClassJavaFile, lines); } + private static void replicateBooleanSingleValue() throws IOException { + final String resultClassJavaPath = charToBoolean( + "engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java"); + final File resultClassJavaFile = new File(resultClassJavaPath); + List<String> lines = FileUtils.readLines(resultClassJavaFile, Charset.defaultCharset()); + lines = ReplicationUtils.addImport(lines, + "import io.deephaven.chunk.ObjectChunk;", + "import io.deephaven.chunk.WritableObjectChunk;"); + lines = ReplicationUtils.removeImport(lines, + "import io.deephaven.chunk.BooleanChunk;", + "import io.deephaven.chunk.WritableBooleanChunk;", + "import static io.deephaven.util.type.TypeUtils.unbox;"); + lines = globalReplacements(lines, + "boolean current", "Boolean current", + "boolean prev", "Boolean prev", + "super\\(boolean.class", "super(Boolean.class", + "set\\(long key, boolean", "set(long key, Boolean", + "getBoolean", "get", + "getPrevBoolean", "getPrev", + "boolean get", "Boolean get", + "boolean value", "Boolean value", + "final BooleanChunk<[?] extends Values>", "final ObjectChunk<Boolean, ? extends Values>", + "final WritableBooleanChunk<[?] super Values>", "final WritableObjectChunk<Boolean, ? super Values>", + "asBooleanChunk\\(", "asObjectChunk(", + "asWritableBooleanChunk\\(", "asWritableObjectChunk(", + "unbox\\((.*)\\)", "$1"); + lines = ReplicationUtils.removeRegion(lines, "UnboxedSetter"); + FileUtils.writeLines(resultClassJavaFile, lines); + } + private static void replicateChunkColumnSource() throws IOException { charToAllButBoolean( "engine/table/src/main/java/io/deephaven/engine/table/impl/sources/chunkcolumnsource/CharChunkColumnSource.java"); From a63d9831f5f1bd74d6bd5073884d7c6529582a58 Mon Sep 17 00:00:00 2001 From: Nate Bauernfeind <nate.bauernfeind@gmail.com> Date: Thu, 19 Jan 2023 11:23:14 -0700 Subject: [PATCH 3/5] Update engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java Co-authored-by: Ryan Caudy <rcaudy@gmail.com> --- .../java/io/deephaven/engine/table/impl/SortOperation.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java index ec3db462d80..374e0722c0d 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/SortOperation.java @@ -296,10 +296,9 @@ public Result<QueryTable> initialize(boolean usePrev, long beforeClock) { */ public static RowRedirection getRowRedirection(@NotNull final Table sortResult) { for (final ColumnSource<?> columnSource : sortResult.getColumnSources()) { - if (!(columnSource instanceof RedirectedColumnSource)) { - continue; + if (columnSource instanceof RedirectedColumnSource) { + return ((RedirectedColumnSource<?>) columnSource).getRowRedirection(); } - return ((RedirectedColumnSource<?>) columnSource).getRowRedirection(); } return null; } From e135247aafd63b26e05912c7c5a7d294e08ee6ad Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind <natebauernfeind@deephaven.io> Date: Thu, 19 Jan 2023 11:41:17 -0700 Subject: [PATCH 4/5] Ryan's feedback --- .../impl/sources/BitMaskingColumnSource.java | 2 +- .../impl/sources/BitShiftingColumnSource.java | 2 +- .../impl/sources/BooleanSingleValueSource.java | 14 +++++--------- .../impl/sources/ByteSingleValueSource.java | 14 +++++--------- .../impl/sources/CharacterSingleValueSource.java | 14 +++++--------- .../impl/sources/CrossJoinRightColumnSource.java | 3 +-- .../impl/sources/DoubleSingleValueSource.java | 14 +++++--------- .../impl/sources/FloatSingleValueSource.java | 14 +++++--------- .../impl/sources/IntegerSingleValueSource.java | 14 +++++--------- .../impl/sources/LongSingleValueSource.java | 14 +++++--------- .../impl/sources/NullValueColumnSource.java | 2 +- .../impl/sources/ObjectSingleValueSource.java | 14 +++++--------- .../impl/sources/RedirectedColumnSource.java | 3 +-- .../impl/sources/RowKeyAgnosticChunkSource.java | 14 ++++++++++++++ .../impl/sources/RowKeyAgnosticColumnSource.java | 16 ---------------- .../impl/sources/ShortSingleValueSource.java | 14 +++++--------- .../impl/sources/SingleValueColumnSource.java | 4 ++-- .../sources/WritableRedirectedColumnSource.java | 2 +- .../immutable/ImmutableConstantByteSource.java | 13 ++++++++----- .../immutable/ImmutableConstantCharSource.java | 13 ++++++++----- .../immutable/ImmutableConstantDoubleSource.java | 13 ++++++++----- .../immutable/ImmutableConstantFloatSource.java | 13 ++++++++----- .../immutable/ImmutableConstantIntSource.java | 13 ++++++++----- .../immutable/ImmutableConstantLongSource.java | 13 ++++++++----- .../immutable/ImmutableConstantObjectSource.java | 13 ++++++++----- .../immutable/ImmutableConstantShortSource.java | 13 ++++++++----- 26 files changed, 131 insertions(+), 147 deletions(-) create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticChunkSource.java delete mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java index 95643096d0e..1f967af1d33 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitMaskingColumnSource.java @@ -30,7 +30,7 @@ public class BitMaskingColumnSource<T> extends AbstractColumnSource<T> implement public static <T> ColumnSource<T> maybeWrap( final ZeroKeyCrossJoinShiftState shiftState, @NotNull final ColumnSource<T> innerSource) { - if (innerSource instanceof RowKeyAgnosticColumnSource) { + if (innerSource instanceof RowKeyAgnosticChunkSource) { return innerSource; } return new BitMaskingColumnSource<>(shiftState, innerSource); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java index e461dd19361..4de026a49f9 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BitShiftingColumnSource.java @@ -33,7 +33,7 @@ public class BitShiftingColumnSource<T> extends AbstractColumnSource<T> implemen public static <T> ColumnSource<T> maybeWrap( @NotNull final CrossJoinShiftState shiftState, @NotNull final ColumnSource<T> innerSource) { - if (innerSource instanceof RowKeyAgnosticColumnSource) { + if (innerSource instanceof RowKeyAgnosticChunkSource) { return innerSource; } return new BitShiftingColumnSource<>(shiftState, innerSource); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java index 6956b5b0f99..885c44a8569 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/BooleanSingleValueSource.java @@ -118,27 +118,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), get(0)); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + Boolean value = getPrev(0); // avoid duplicating the current vs prev logic in getPrev destination.setSize(rowSequence.intSize()); - destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), getPrev(0)); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - Boolean value = get(0); final WritableObjectChunk<Boolean, ? super Values> destChunk = dest.asWritableObjectChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BOOLEAN : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BOOLEAN : current); } destChunk.setSize(keys.size()); } @@ -146,8 +143,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - Boolean value = getPrev(0); + Boolean value = getPrev(0); // avoid duplicating the current vs prev logic in getPrev final WritableObjectChunk<Boolean, ? super Values> destChunk = dest.asWritableObjectChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BOOLEAN : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java index c08f5404b2a..fa78a8ed06c 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ByteSingleValueSource.java @@ -129,27 +129,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableByteChunk().fillWithValue(0, rowSequence.intSize(), getByte(0)); + destination.asWritableByteChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + byte value = getPrevByte(0); // avoid duplicating the current vs prev logic in getPrevByte destination.setSize(rowSequence.intSize()); - destination.asWritableByteChunk().fillWithValue(0, rowSequence.intSize(), getPrevByte(0)); + destination.asWritableByteChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - byte value = getByte(0); final WritableByteChunk<? super Values> destChunk = dest.asWritableByteChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BYTE : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BYTE : current); } destChunk.setSize(keys.size()); } @@ -157,8 +154,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - byte value = getPrevByte(0); + byte value = getPrevByte(0); // avoid duplicating the current vs prev logic in getPrevByte final WritableByteChunk<? super Values> destChunk = dest.asWritableByteChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BYTE : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java index 0cde437c6b9..2fbd654e8b4 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CharacterSingleValueSource.java @@ -124,27 +124,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableCharChunk().fillWithValue(0, rowSequence.intSize(), getChar(0)); + destination.asWritableCharChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + char value = getPrevChar(0); // avoid duplicating the current vs prev logic in getPrevChar destination.setSize(rowSequence.intSize()); - destination.asWritableCharChunk().fillWithValue(0, rowSequence.intSize(), getPrevChar(0)); + destination.asWritableCharChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - char value = getChar(0); final WritableCharChunk<? super Values> destChunk = dest.asWritableCharChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_CHAR : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_CHAR : current); } destChunk.setSize(keys.size()); } @@ -152,8 +149,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - char value = getPrevChar(0); + char value = getPrevChar(0); // avoid duplicating the current vs prev logic in getPrevChar final WritableCharChunk<? super Values> destChunk = dest.asWritableCharChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_CHAR : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java index a6b437a0b90..f1cd6747890 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/CrossJoinRightColumnSource.java @@ -29,7 +29,6 @@ import io.deephaven.engine.rowset.RowSet; import io.deephaven.engine.rowset.TrackingRowSet; import io.deephaven.engine.table.impl.util.ChunkUtils; -import io.deephaven.proto.backplane.grpc.NullValue; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableLong; import org.jetbrains.annotations.NotNull; @@ -50,7 +49,7 @@ public static <T> ColumnSource<T> maybeWrap( @NotNull final ColumnSource<T> innerSource, boolean rightIsLive) { // Force wrapping if this is a leftOuterJoin or else we will not see the nulls; unless every row is null. - if ((!crossJoinManager.leftOuterJoin() && innerSource instanceof RowKeyAgnosticColumnSource) + if ((!crossJoinManager.leftOuterJoin() && innerSource instanceof RowKeyAgnosticChunkSource) || innerSource instanceof NullValueColumnSource) { return innerSource; } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java index bff59af4298..8ac199e2820 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/DoubleSingleValueSource.java @@ -129,27 +129,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableDoubleChunk().fillWithValue(0, rowSequence.intSize(), getDouble(0)); + destination.asWritableDoubleChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + double value = getPrevDouble(0); // avoid duplicating the current vs prev logic in getPrevDouble destination.setSize(rowSequence.intSize()); - destination.asWritableDoubleChunk().fillWithValue(0, rowSequence.intSize(), getPrevDouble(0)); + destination.asWritableDoubleChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - double value = getDouble(0); final WritableDoubleChunk<? super Values> destChunk = dest.asWritableDoubleChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_DOUBLE : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_DOUBLE : current); } destChunk.setSize(keys.size()); } @@ -157,8 +154,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - double value = getPrevDouble(0); + double value = getPrevDouble(0); // avoid duplicating the current vs prev logic in getPrevDouble final WritableDoubleChunk<? super Values> destChunk = dest.asWritableDoubleChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_DOUBLE : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java index 9d10fb61b1e..aeb0d13293d 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/FloatSingleValueSource.java @@ -129,27 +129,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableFloatChunk().fillWithValue(0, rowSequence.intSize(), getFloat(0)); + destination.asWritableFloatChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + float value = getPrevFloat(0); // avoid duplicating the current vs prev logic in getPrevFloat destination.setSize(rowSequence.intSize()); - destination.asWritableFloatChunk().fillWithValue(0, rowSequence.intSize(), getPrevFloat(0)); + destination.asWritableFloatChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - float value = getFloat(0); final WritableFloatChunk<? super Values> destChunk = dest.asWritableFloatChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_FLOAT : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_FLOAT : current); } destChunk.setSize(keys.size()); } @@ -157,8 +154,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - float value = getPrevFloat(0); + float value = getPrevFloat(0); // avoid duplicating the current vs prev logic in getPrevFloat final WritableFloatChunk<? super Values> destChunk = dest.asWritableFloatChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_FLOAT : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java index 21ded020289..ab48582e797 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/IntegerSingleValueSource.java @@ -129,27 +129,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableIntChunk().fillWithValue(0, rowSequence.intSize(), getInt(0)); + destination.asWritableIntChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + int value = getPrevInt(0); // avoid duplicating the current vs prev logic in getPrevInt destination.setSize(rowSequence.intSize()); - destination.asWritableIntChunk().fillWithValue(0, rowSequence.intSize(), getPrevInt(0)); + destination.asWritableIntChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - int value = getInt(0); final WritableIntChunk<? super Values> destChunk = dest.asWritableIntChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_INT : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_INT : current); } destChunk.setSize(keys.size()); } @@ -157,8 +154,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - int value = getPrevInt(0); + int value = getPrevInt(0); // avoid duplicating the current vs prev logic in getPrevInt final WritableIntChunk<? super Values> destChunk = dest.asWritableIntChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_INT : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java index ab7df16511e..57907e9b332 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/LongSingleValueSource.java @@ -129,27 +129,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableLongChunk().fillWithValue(0, rowSequence.intSize(), getLong(0)); + destination.asWritableLongChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + long value = getPrevLong(0); // avoid duplicating the current vs prev logic in getPrevLong destination.setSize(rowSequence.intSize()); - destination.asWritableLongChunk().fillWithValue(0, rowSequence.intSize(), getPrevLong(0)); + destination.asWritableLongChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - long value = getLong(0); final WritableLongChunk<? super Values> destChunk = dest.asWritableLongChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_LONG : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_LONG : current); } destChunk.setSize(keys.size()); } @@ -157,8 +154,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - long value = getPrevLong(0); + long value = getPrevLong(0); // avoid duplicating the current vs prev logic in getPrevLong final WritableLongChunk<? super Values> destChunk = dest.asWritableLongChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_LONG : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java index 003042f2779..da10ae46990 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/NullValueColumnSource.java @@ -28,7 +28,7 @@ * A column source that returns null for all keys. */ public class NullValueColumnSource<T> extends AbstractColumnSource<T> - implements ShiftData.ShiftCallback, RowKeyAgnosticColumnSource<Values> { + implements ShiftData.ShiftCallback, InMemoryColumnSource, RowKeyAgnosticChunkSource<Values> { private static final KeyedObjectKey.Basic<Pair<Class<?>, Class<?>>, NullValueColumnSource<?>> KEY_TYPE = new KeyedObjectKey.Basic<>() { @Override diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java index 01e0e1e7bec..fd90fceb1a3 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ObjectSingleValueSource.java @@ -117,27 +117,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), get(0)); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + T value = getPrev(0); // avoid duplicating the current vs prev logic in getPrev destination.setSize(rowSequence.intSize()); - destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), getPrev(0)); + destination.asWritableObjectChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - T value = get(0); final WritableObjectChunk<T, ? super Values> destChunk = dest.asWritableObjectChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : current); } destChunk.setSize(keys.size()); } @@ -145,8 +142,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - T value = getPrev(0); + T value = getPrev(0); // avoid duplicating the current vs prev logic in getPrev final WritableObjectChunk<T, ? super Values> destChunk = dest.asWritableObjectChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java index da3a359c279..335d89a624b 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java @@ -8,7 +8,6 @@ import io.deephaven.engine.table.SharedContext; import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.Table; -import io.deephaven.engine.table.WritableColumnSource; import io.deephaven.engine.table.impl.util.RowRedirection; import io.deephaven.util.BooleanUtils; import io.deephaven.engine.table.impl.join.dupexpand.DupExpandKernel; @@ -45,7 +44,7 @@ public class RedirectedColumnSource<T> extends AbstractDeferredGroupingColumnSou public static <T> ColumnSource<T> maybeRedirect( @NotNull final RowRedirection rowRedirection, @NotNull final ColumnSource<T> innerSource) { - if (innerSource instanceof RowKeyAgnosticColumnSource) { + if (innerSource instanceof RowKeyAgnosticChunkSource) { return innerSource; } return new RedirectedColumnSource<>(rowRedirection, innerSource); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticChunkSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticChunkSource.java new file mode 100644 index 00000000000..edfd6d0ca2a --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticChunkSource.java @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.engine.table.impl.sources; + +import io.deephaven.chunk.attributes.Any; + +/** + * This is a marker interface for chunk sources that are agnostic of the row key when evaluating the value for a given + * row key. + */ +public interface RowKeyAgnosticChunkSource<ATTR extends Any> extends FillUnordered<ATTR> { + +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java deleted file mode 100644 index 726872f4dbf..00000000000 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RowKeyAgnosticColumnSource.java +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending - */ -package io.deephaven.engine.table.impl.sources; - -import io.deephaven.chunk.attributes.Any; - -/** - * This is a marker interface for column sources that are agnostic when fulfilling requested row keys. - * - * The marker extends from {@link InMemoryColumnSource} whether the column source is actually in memory or not; it would - * be a waste to materialize the same value for all rows via select. - */ -public interface RowKeyAgnosticColumnSource<ATTR extends Any> extends FillUnordered<ATTR>, InMemoryColumnSource { - -} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java index 8a54ec8aa43..d30619ecda4 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/ShortSingleValueSource.java @@ -129,27 +129,24 @@ public void fillFromChunkUnordered(@NotNull FillFromContext context, @NotNull Ch @Override public void fillChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey destination.setSize(rowSequence.intSize()); - destination.asWritableShortChunk().fillWithValue(0, rowSequence.intSize(), getShort(0)); + destination.asWritableShortChunk().fillWithValue(0, rowSequence.intSize(), current); } @Override public void fillPrevChunk(@NotNull FillContext context, @NotNull WritableChunk<? super Values> destination, @NotNull RowSequence rowSequence) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey + short value = getPrevShort(0); // avoid duplicating the current vs prev logic in getPrevShort destination.setSize(rowSequence.intSize()); - destination.asWritableShortChunk().fillWithValue(0, rowSequence.intSize(), getPrevShort(0)); + destination.asWritableShortChunk().fillWithValue(0, rowSequence.intSize(), value); } @Override public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - short value = getShort(0); final WritableShortChunk<? super Values> destChunk = dest.asWritableShortChunk(); for (int ii = 0; ii < keys.size(); ++ii) { - destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_SHORT : value); + destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_SHORT : current); } destChunk.setSize(keys.size()); } @@ -157,8 +154,7 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh @Override public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey - short value = getPrevShort(0); + short value = getPrevShort(0); // avoid duplicating the current vs prev logic in getPrevShort final WritableShortChunk<? super Values> destChunk = dest.asWritableShortChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_SHORT : value); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java index bf1a924604d..599b3f830d1 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/SingleValueColumnSource.java @@ -11,8 +11,8 @@ import io.deephaven.engine.table.impl.util.ShiftData; public abstract class SingleValueColumnSource<T> extends AbstractColumnSource<T> - implements WritableColumnSource<T>, ChunkSink<Values>, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements WritableColumnSource<T>, ChunkSink<Values>, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { protected transient long changeTime; protected boolean isTrackingPrevValues; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java index 4cc083580b8..df90ac9deec 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/WritableRedirectedColumnSource.java @@ -30,7 +30,7 @@ public static <T> WritableColumnSource<T> maybeRedirect( @NotNull final RowRedirection rowRedirection, @NotNull final WritableColumnSource<T> innerSource, final long maxInnerIndex) { - if (innerSource instanceof RowKeyAgnosticColumnSource) { + if (innerSource instanceof RowKeyAgnosticChunkSource) { return innerSource; } return new WritableRedirectedColumnSource<>(rowRedirection, innerSource, maxInnerIndex); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java index 279b052a10d..5fb13e6f403 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantByteSource.java @@ -33,8 +33,8 @@ */ public class ImmutableConstantByteSource extends AbstractColumnSource<Byte> - implements ImmutableColumnSourceGetDefaults.ForByte, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForByte, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final byte value; @@ -89,9 +89,10 @@ protected <ALTERNATE_DATA_TYPE> ColumnSource<ALTERNATE_DATA_TYPE> doReinterpret( // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableByteChunk<? super Values> destChunk = dest.asWritableByteChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_BYTE : value); @@ -100,7 +101,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java index 95d8afb17b5..dee2302e1c8 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantCharSource.java @@ -26,8 +26,8 @@ */ public class ImmutableConstantCharSource extends AbstractColumnSource<Character> - implements ImmutableColumnSourceGetDefaults.ForChar, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForChar, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final char value; @@ -71,9 +71,10 @@ public final void shift(final long start, final long end, final long offset) {} // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableCharChunk<? super Values> destChunk = dest.asWritableCharChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_CHAR : value); @@ -82,7 +83,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java index 72d72ba7060..c8192949f45 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantDoubleSource.java @@ -31,8 +31,8 @@ */ public class ImmutableConstantDoubleSource extends AbstractColumnSource<Double> - implements ImmutableColumnSourceGetDefaults.ForDouble, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForDouble, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final double value; @@ -76,9 +76,10 @@ public final void shift(final long start, final long end, final long offset) {} // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableDoubleChunk<? super Values> destChunk = dest.asWritableDoubleChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_DOUBLE : value); @@ -87,7 +88,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java index 06a30f4da50..67e063c645a 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantFloatSource.java @@ -31,8 +31,8 @@ */ public class ImmutableConstantFloatSource extends AbstractColumnSource<Float> - implements ImmutableColumnSourceGetDefaults.ForFloat, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForFloat, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final float value; @@ -76,9 +76,10 @@ public final void shift(final long start, final long end, final long offset) {} // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableFloatChunk<? super Values> destChunk = dest.asWritableFloatChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_FLOAT : value); @@ -87,7 +88,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java index 83b46b7e60c..8c9d8826f8a 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantIntSource.java @@ -31,8 +31,8 @@ */ public class ImmutableConstantIntSource extends AbstractColumnSource<Integer> - implements ImmutableColumnSourceGetDefaults.ForInt, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForInt, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final int value; @@ -76,9 +76,10 @@ public final void shift(final long start, final long end, final long offset) {} // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableIntChunk<? super Values> destChunk = dest.asWritableIntChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_INT : value); @@ -87,7 +88,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java index 3bd263faead..361c45c9805 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantLongSource.java @@ -35,8 +35,8 @@ */ public class ImmutableConstantLongSource extends AbstractColumnSource<Long> - implements ImmutableColumnSourceGetDefaults.ForLong, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForLong, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final long value; @@ -91,9 +91,10 @@ protected <ALTERNATE_DATA_TYPE> ColumnSource<ALTERNATE_DATA_TYPE> doReinterpret( // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableLongChunk<? super Values> destChunk = dest.asWritableLongChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_LONG : value); @@ -102,7 +103,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java index 947562e4ef5..872874053b8 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantObjectSource.java @@ -30,8 +30,8 @@ */ public class ImmutableConstantObjectSource<T> extends AbstractColumnSource<T> - implements ImmutableColumnSourceGetDefaults.ForObject<T>, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForObject<T>, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final T value; @@ -75,9 +75,10 @@ public final void shift(final long start, final long end, final long offset) {} // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableObjectChunk<T, ? super Values> destChunk = dest.asWritableObjectChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? null : value); @@ -86,7 +87,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java index c394ac5c2bf..e0a9f3c5317 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/immutable/ImmutableConstantShortSource.java @@ -31,8 +31,8 @@ */ public class ImmutableConstantShortSource extends AbstractColumnSource<Short> - implements ImmutableColumnSourceGetDefaults.ForShort, ShiftData.ShiftCallback, - RowKeyAgnosticColumnSource<Values> { + implements ImmutableColumnSourceGetDefaults.ForShort, ShiftData.ShiftCallback, InMemoryColumnSource, + RowKeyAgnosticChunkSource<Values> { private final short value; @@ -76,9 +76,10 @@ public final void shift(final long start, final long end, final long offset) {} // endregion reinterpret @Override - public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { - // We can only hold one value, fill the chunk with the value obtained from an arbitrarily valid rowKey final WritableShortChunk<? super Values> destChunk = dest.asWritableShortChunk(); for (int ii = 0; ii < keys.size(); ++ii) { destChunk.set(ii, keys.get(ii) == RowSequence.NULL_ROW_KEY ? NULL_SHORT : value); @@ -87,7 +88,9 @@ public void fillChunkUnordered(@NotNull FillContext context, @NotNull WritableCh } @Override - public void fillPrevChunkUnordered(@NotNull FillContext context, @NotNull WritableChunk<? super Values> dest, + public void fillPrevChunkUnordered( + @NotNull FillContext context, + @NotNull WritableChunk<? super Values> dest, @NotNull LongChunk<? extends RowKeys> keys) { fillChunkUnordered(context , dest, keys); } From c54475ef849feb05b7ae848d542bfe1bcc199b85 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind <natebauernfeind@deephaven.io> Date: Thu, 19 Jan 2023 11:50:05 -0700 Subject: [PATCH 5/5] Revert RedirectedColumnSource constructor to protected and add --- .../engine/table/impl/AsOfJoinHelper.java | 2 +- .../engine/table/impl/NaturalJoinHelper.java | 2 +- .../impl/sources/RedirectedColumnSource.java | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java index 24125ecfdf6..80469aea3e5 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java @@ -1530,7 +1530,7 @@ private static QueryTable makeResult(QueryTable leftTable, Table rightTable, Row Arrays.stream(columnsToAdd).forEach(mp -> { // note that we must always redirect the right-hand side, because unmatched rows will be redirected to null final ColumnSource<?> rightSource = - new RedirectedColumnSource<>(rowRedirection, rightTable.getColumnSource(mp.rightColumn())); + RedirectedColumnSource.alwaysRedirect(rowRedirection, rightTable.getColumnSource(mp.rightColumn())); if (refreshing) { rightSource.startTrackingPrevValues(); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java index be3d3cb90e1..0907d8f72b9 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/NaturalJoinHelper.java @@ -442,7 +442,7 @@ private static QueryTable makeResult(@NotNull final QueryTable leftTable, for (MatchPair mp : columnsToAdd) { // note that we must always redirect the right-hand side, because unmatched rows will be redirected to null final ColumnSource<?> redirectedColumnSource = - new RedirectedColumnSource<>(rowRedirection, rightTable.getColumnSource(mp.rightColumn())); + RedirectedColumnSource.alwaysRedirect(rowRedirection, rightTable.getColumnSource(mp.rightColumn())); if (rightRefreshingColumns) { redirectedColumnSource.startTrackingPrevValues(); } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java index 335d89a624b..1454a3a98ac 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/sources/RedirectedColumnSource.java @@ -50,11 +50,25 @@ public static <T> ColumnSource<T> maybeRedirect( return new RedirectedColumnSource<>(rowRedirection, innerSource); } + /** + * This factory method should be used when unmapped rows in the row redirection must be redirected to null values. + * For example, natural joins, left outer joins, and as-of joins must map unmatched rows to null values in + * right-side columns. + * + * @param rowRedirection The row redirection to use + * @param innerSource The column source to redirect + */ + public static <T> ColumnSource<T> alwaysRedirect( + @NotNull final RowRedirection rowRedirection, + @NotNull final ColumnSource<T> innerSource) { + return new RedirectedColumnSource<>(rowRedirection, innerSource); + } + protected final RowRedirection rowRedirection; protected final ColumnSource<T> innerSource; private final boolean ascendingMapping; - public RedirectedColumnSource( + protected RedirectedColumnSource( @NotNull final RowRedirection rowRedirection, @NotNull final ColumnSource<T> innerSource) { super(innerSource.getType());