/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.operator.scalar;
import com.facebook.presto.spi.ConnectorSession;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.block.BlockBuilder;
import com.facebook.presto.spi.block.BlockBuilderStatus;
import com.facebook.presto.spi.function.Description;
import com.facebook.presto.spi.function.ScalarFunction;
import com.facebook.presto.spi.function.SqlType;
import com.facebook.presto.spi.type.FixedWidthType;
import com.facebook.presto.spi.type.StandardTypes;
import com.facebook.presto.type.DateTimeOperators;
import io.airlift.slice.Slice;
import io.airlift.slice.Slices;
import static com.facebook.presto.operator.scalar.DateTimeFunctions.diffTimestamp;
import static com.facebook.presto.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT;
import static com.facebook.presto.spi.type.BigintType.BIGINT;
import static com.facebook.presto.spi.type.TimestampType.TIMESTAMP;
import static com.facebook.presto.util.Failures.checkCondition;
import static java.lang.Math.toIntExact;
public final class SequenceFunction
{
private static final Slice MONTH = Slices.utf8Slice("month");
private SequenceFunction() {}
@Description("Sequence function to generate synthetic arrays")
@ScalarFunction("sequence")
@SqlType("array(bigint)")
public static Block sequence(
@SqlType(StandardTypes.BIGINT) long start,
@SqlType(StandardTypes.BIGINT) long stop,
@SqlType(StandardTypes.BIGINT) long step)
{
return fixedWidthSequence(start, stop, step, BIGINT);
}
@ScalarFunction("sequence")
@SqlType("array(bigint)")
public static Block sequenceDefaultStep(
@SqlType(StandardTypes.BIGINT) long start,
@SqlType(StandardTypes.BIGINT) long stop)
{
return fixedWidthSequence(start, stop, stop >= start ? 1 : -1, BIGINT);
}
@ScalarFunction("sequence")
@SqlType("array(timestamp)")
public static Block sequenceTimestampDayToSecond(
@SqlType(StandardTypes.TIMESTAMP) long start,
@SqlType(StandardTypes.TIMESTAMP) long stop,
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long step)
{
return fixedWidthSequence(start, stop, step, TIMESTAMP);
}
@ScalarFunction("sequence")
@SqlType("array(timestamp)")
public static Block sequenceTimestampYearToMonth(
ConnectorSession session,
@SqlType(StandardTypes.TIMESTAMP) long start,
@SqlType(StandardTypes.TIMESTAMP) long end,
@SqlType(StandardTypes.INTERVAL_YEAR_TO_MONTH) long step)
{
checkCondition(step != 0, INVALID_FUNCTION_ARGUMENT, "interval must not be zero");
checkCondition(step > 0 ? end >= start : end <= start, INVALID_FUNCTION_ARGUMENT,
"sequence end value should be greater than or equal to start value if step is greater than zero otherwise end should be less than start");
int length = toIntExact(diffTimestamp(session, MONTH, start, end) / step + 1);
BlockBuilder blockBuilder = BIGINT.createBlockBuilder(new BlockBuilderStatus(), length);
int value = 0;
for (int i = 0; i < length; ++i) {
BIGINT.writeLong(blockBuilder, DateTimeOperators.timestampPlusIntervalYearToMonth(session, start, value));
value += step;
}
return blockBuilder.build();
}
private static Block fixedWidthSequence(long start, long stop, long step, FixedWidthType type)
{
checkCondition(step != 0, INVALID_FUNCTION_ARGUMENT, "step must not be zero");
checkCondition(step > 0 ? stop >= start : stop < start, INVALID_FUNCTION_ARGUMENT,
"sequence stop value should be greater than or equal to start value if step is greater than zero otherwise stop should be less than start");
int length = toIntExact((stop - start) / step + 1L);
BlockBuilder blockBuilder = type.createBlockBuilder(new BlockBuilderStatus(), length);
for (long i = 0, value = start; i < length; ++i, value += step) {
type.writeLong(blockBuilder, value);
}
return blockBuilder.build();
}
}