diff --git a/core/trino-spi/src/main/java/io/trino/spi/type/Int128Math.java b/core/trino-spi/src/main/java/io/trino/spi/type/Int128Math.java
index b4a2e07aec00..f7fb0a3ed7d2 100644
--- a/core/trino-spi/src/main/java/io/trino/spi/type/Int128Math.java
+++ b/core/trino-spi/src/main/java/io/trino/spi/type/Int128Math.java
@@ -189,6 +189,13 @@ public static void add(long leftHigh, long leftLow, long rightHigh, long rightLo
}
}
+ public static Int128 add(Int128 left, Int128 right)
+ {
+ long[] result = new long[2];
+ add(left.getHigh(), left.getLow(), right.getHigh(), right.getLow(), result, 0);
+ return Int128.valueOf(result);
+ }
+
public static long addWithOverflow(long leftHigh, long leftLow, long rightHigh, long rightLow, long[] decimal, int offset)
{
long low = leftLow + rightLow;
diff --git a/docs/src/main/sphinx/connector/faker.md b/docs/src/main/sphinx/connector/faker.md
index d5fb56791659..21260339de23 100644
--- a/docs/src/main/sphinx/connector/faker.md
+++ b/docs/src/main/sphinx/connector/faker.md
@@ -111,6 +111,9 @@ The following table details all supported column properties.
* - `allowed_values`
- List of allowed values. Cannot be set together with the `min`, or `max`
properties.
+* - `step`
+ - If set, generate sequential values with this step. For date and time columns
+ set this to a duration. Cannot be set for character-based type columns.
:::
### Character types
diff --git a/plugin/trino-faker/pom.xml b/plugin/trino-faker/pom.xml
index 8a87b91f122e..c0866b9f3445 100644
--- a/plugin/trino-faker/pom.xml
+++ b/plugin/trino-faker/pom.xml
@@ -40,6 +40,11 @@
configuration
+
+ io.airlift
+ units
+
+
io.trino
trino-main
@@ -119,12 +124,6 @@
runtime
-
- io.airlift
- units
- runtime
-
-
io.trino
trino-client
diff --git a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/ColumnInfo.java b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/ColumnInfo.java
index bd52ae4fa776..9bd28af238b4 100644
--- a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/ColumnInfo.java
+++ b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/ColumnInfo.java
@@ -27,6 +27,7 @@ public record ColumnInfo(FakerColumnHandle handle, ColumnMetadata metadata)
public static final String MIN_PROPERTY = "min";
public static final String MAX_PROPERTY = "max";
public static final String ALLOWED_VALUES_PROPERTY = "allowed_values";
+ public static final String STEP_PROPERTY = "step";
public ColumnInfo
{
diff --git a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerColumnHandle.java b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerColumnHandle.java
index 96d870eafb8e..770ee83d20d4 100644
--- a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerColumnHandle.java
+++ b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerColumnHandle.java
@@ -15,6 +15,7 @@
package io.trino.plugin.faker;
import com.google.common.collect.ImmutableList;
+import io.airlift.units.Duration;
import io.trino.spi.TrinoException;
import io.trino.spi.connector.ColumnHandle;
import io.trino.spi.connector.ColumnMetadata;
@@ -22,20 +23,30 @@
import io.trino.spi.predicate.Range;
import io.trino.spi.predicate.ValueSet;
import io.trino.spi.type.CharType;
+import io.trino.spi.type.TimeType;
+import io.trino.spi.type.TimeWithTimeZoneType;
+import io.trino.spi.type.TimestampType;
+import io.trino.spi.type.TimestampWithTimeZoneType;
import io.trino.spi.type.Type;
import io.trino.spi.type.VarbinaryType;
import io.trino.spi.type.VarcharType;
import java.util.Collection;
import java.util.List;
+import java.util.concurrent.TimeUnit;
+import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static io.trino.plugin.faker.ColumnInfo.ALLOWED_VALUES_PROPERTY;
import static io.trino.plugin.faker.ColumnInfo.GENERATOR_PROPERTY;
import static io.trino.plugin.faker.ColumnInfo.MAX_PROPERTY;
import static io.trino.plugin.faker.ColumnInfo.MIN_PROPERTY;
import static io.trino.plugin.faker.ColumnInfo.NULL_PROBABILITY_PROPERTY;
+import static io.trino.plugin.faker.ColumnInfo.STEP_PROPERTY;
import static io.trino.spi.StandardErrorCode.INVALID_COLUMN_PROPERTY;
+import static io.trino.spi.type.BigintType.BIGINT;
+import static io.trino.spi.type.DateType.DATE;
+import static io.trino.spi.type.IntegerType.INTEGER;
import static java.util.Objects.requireNonNull;
public record FakerColumnHandle(
@@ -44,13 +55,17 @@ public record FakerColumnHandle(
Type type,
double nullProbability,
String generator,
- Domain domain)
+ Domain domain,
+ ValueSet step)
implements ColumnHandle
{
public FakerColumnHandle
{
requireNonNull(name, "name is null");
requireNonNull(type, "type is null");
+ requireNonNull(domain, "domain is null");
+ requireNonNull(step, "step is null");
+ checkState(step.isNone() || step.isSingleValue(), "step must be a single value");
}
public static FakerColumnHandle of(int columnId, ColumnMetadata column, double defaultNullProbability)
@@ -63,20 +78,8 @@ public static FakerColumnHandle of(int columnId, ColumnMetadata column, double d
if (generator != null && !isCharacterColumn(column)) {
throw new TrinoException(INVALID_COLUMN_PROPERTY, "The `%s` property can only be set for CHAR, VARCHAR or VARBINARY columns".formatted(GENERATOR_PROPERTY));
}
- Object min;
- try {
- min = Literal.parse((String) column.getProperties().get(MIN_PROPERTY), column.getType());
- }
- catch (IllegalArgumentException e) {
- throw new TrinoException(INVALID_COLUMN_PROPERTY, "The `%s` property must be a valid %s literal".formatted(MIN_PROPERTY, column.getType().getDisplayName()), e);
- }
- Object max;
- try {
- max = Literal.parse((String) column.getProperties().get(MAX_PROPERTY), column.getType());
- }
- catch (IllegalArgumentException e) {
- throw new TrinoException(INVALID_COLUMN_PROPERTY, "The `%s` property must be a valid %s literal".formatted(MAX_PROPERTY, column.getType().getDisplayName()), e);
- }
+ Object min = propertyValue(column, MIN_PROPERTY);
+ Object max = propertyValue(column, MAX_PROPERTY);
Domain domain = Domain.all(column.getType());
if (min != null || max != null) {
if (isCharacterColumn(column)) {
@@ -106,7 +109,8 @@ public static FakerColumnHandle of(int columnId, ColumnMetadata column, double d
column.getType(),
nullProbability,
generator,
- domain);
+ domain,
+ stepValue(column));
}
private static boolean isCharacterColumn(ColumnMetadata column)
@@ -114,6 +118,42 @@ private static boolean isCharacterColumn(ColumnMetadata column)
return column.getType() instanceof CharType || column.getType() instanceof VarcharType || column.getType() instanceof VarbinaryType;
}
+ private static Object propertyValue(ColumnMetadata column, String property)
+ {
+ try {
+ return Literal.parse((String) column.getProperties().get(property), column.getType());
+ }
+ catch (IllegalArgumentException e) {
+ throw new TrinoException(INVALID_COLUMN_PROPERTY, "The `%s` property must be a valid %s literal".formatted(property, column.getType().getDisplayName()), e);
+ }
+ }
+
+ private static ValueSet stepValue(ColumnMetadata column)
+ {
+ Type type = column.getType();
+ String rawStep = (String) column.getProperties().get(STEP_PROPERTY);
+ if (rawStep == null) {
+ return ValueSet.none(type);
+ }
+ if (isCharacterColumn(column)) {
+ throw new TrinoException(INVALID_COLUMN_PROPERTY, "The `%s` property cannot be set for CHAR, VARCHAR or VARBINARY columns".formatted(STEP_PROPERTY));
+ }
+ if (DATE.equals(column.getType()) || type instanceof TimestampType || type instanceof TimestampWithTimeZoneType || type instanceof TimeType || type instanceof TimeWithTimeZoneType) {
+ try {
+ return ValueSet.of(BIGINT, Duration.valueOf(rawStep).roundTo(TimeUnit.NANOSECONDS));
+ }
+ catch (IllegalArgumentException e) {
+ throw new TrinoException(INVALID_COLUMN_PROPERTY, "The `%s` property for a %s column must be a valid duration literal".formatted(STEP_PROPERTY, column.getType().getDisplayName()), e);
+ }
+ }
+ try {
+ return ValueSet.of(type, Literal.parse(rawStep, type));
+ }
+ catch (IllegalArgumentException e) {
+ throw new TrinoException(INVALID_COLUMN_PROPERTY, "The `%s` property for a %s column must be a valid %s literal".formatted(STEP_PROPERTY, column.getType().getDisplayName(), type.getDisplayName()), e);
+ }
+ }
+
private static Range range(Type type, Object min, Object max)
{
requireNonNull(type, "type is null");
diff --git a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerConnector.java b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerConnector.java
index 2a5819c04b47..734fa513b355 100644
--- a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerConnector.java
+++ b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerConnector.java
@@ -39,6 +39,7 @@
import static io.trino.plugin.faker.ColumnInfo.ALLOWED_VALUES_PROPERTY;
import static io.trino.plugin.faker.ColumnInfo.MAX_PROPERTY;
import static io.trino.plugin.faker.ColumnInfo.MIN_PROPERTY;
+import static io.trino.plugin.faker.ColumnInfo.STEP_PROPERTY;
import static io.trino.spi.StandardErrorCode.INVALID_COLUMN_PROPERTY;
import static io.trino.spi.StandardErrorCode.INVALID_SCHEMA_PROPERTY;
import static io.trino.spi.StandardErrorCode.INVALID_TABLE_PROPERTY;
@@ -188,7 +189,12 @@ public List> getColumnProperties()
value -> ((List>) value).stream()
.map(String.class::cast)
.collect(toImmutableList()),
- value -> value));
+ value -> value),
+ stringProperty(
+ STEP_PROPERTY,
+ "If set, generate sequential values with this step. For date and time columns set this to a duration",
+ null,
+ false));
}
private static void checkProperty(boolean expression, ErrorCodeSupplier errorCode, String errorMessage)
diff --git a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerMetadata.java b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerMetadata.java
index 275d04d62004..46d246e9d8d0 100644
--- a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerMetadata.java
+++ b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerMetadata.java
@@ -43,6 +43,8 @@
import io.trino.spi.function.FunctionMetadata;
import io.trino.spi.function.SchemaFunctionName;
import io.trino.spi.predicate.Domain;
+import io.trino.spi.predicate.Range;
+import io.trino.spi.predicate.ValueSet;
import io.trino.spi.security.TrinoPrincipal;
import io.trino.spi.statistics.ComputedStatistics;
import io.trino.spi.type.BigintType;
@@ -336,7 +338,8 @@ public synchronized FakerOutputTableHandle beginCreateTable(ConnectorSession ses
BigintType.BIGINT,
0,
"",
- Domain.all(BigintType.BIGINT)),
+ Domain.create(ValueSet.ofRanges(Range.greaterThanOrEqual(BigintType.BIGINT, 0L)), false),
+ ValueSet.of(BigintType.BIGINT, 1L)),
ColumnMetadata.builder()
.setName(ROW_ID_COLUMN_NAME)
.setType(BigintType.BIGINT)
diff --git a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerPageSource.java b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerPageSource.java
index aa750f147208..5b27a72557bd 100644
--- a/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerPageSource.java
+++ b/plugin/trino-faker/src/main/java/io/trino/plugin/faker/FakerPageSource.java
@@ -50,7 +50,6 @@
import java.util.Random;
import static com.google.common.collect.ImmutableList.toImmutableList;
-import static io.trino.plugin.faker.FakerMetadata.ROW_ID_COLUMN_NAME;
import static io.trino.spi.StandardErrorCode.INVALID_ROW_FILTER;
import static io.trino.spi.type.BigintType.BIGINT;
import static io.trino.spi.type.BooleanType.BOOLEAN;
@@ -66,10 +65,17 @@
import static io.trino.spi.type.LongTimestampWithTimeZone.fromEpochMillisAndFraction;
import static io.trino.spi.type.RealType.REAL;
import static io.trino.spi.type.SmallintType.SMALLINT;
+import static io.trino.spi.type.Timestamps.MICROSECONDS_PER_MILLISECOND;
+import static io.trino.spi.type.Timestamps.MILLISECONDS_PER_DAY;
+import static io.trino.spi.type.Timestamps.MILLISECONDS_PER_SECOND;
import static io.trino.spi.type.Timestamps.NANOSECONDS_PER_DAY;
+import static io.trino.spi.type.Timestamps.NANOSECONDS_PER_MICROSECOND;
+import static io.trino.spi.type.Timestamps.NANOSECONDS_PER_MILLISECOND;
+import static io.trino.spi.type.Timestamps.NANOSECONDS_PER_SECOND;
import static io.trino.spi.type.Timestamps.PICOSECONDS_PER_DAY;
import static io.trino.spi.type.Timestamps.PICOSECONDS_PER_MICROSECOND;
import static io.trino.spi.type.Timestamps.PICOSECONDS_PER_MILLISECOND;
+import static io.trino.spi.type.Timestamps.PICOSECONDS_PER_NANOSECOND;
import static io.trino.spi.type.Timestamps.roundDiv;
import static io.trino.spi.type.TinyintType.TINYINT;
import static io.trino.spi.type.UuidType.UUID;
@@ -126,7 +132,7 @@ class FakerPageSource
Faker faker,
Random random,
List columns,
- long offset,
+ long rowOffset,
long limit)
{
this.faker = requireNonNull(faker, "faker is null");
@@ -141,29 +147,38 @@ class FakerPageSource
this.generators = columns
.stream()
- .map(column -> getGenerator(column, offset))
+ .map(column -> getGenerator(column, rowOffset))
.collect(toImmutableList());
this.pageBuilder = new PageBuilder(types);
}
private Generator getGenerator(
FakerColumnHandle column,
- long offset)
+ long rowOffset)
{
- if (ROW_ID_COLUMN_NAME.equals(column.name())) {
- return new Generator()
- {
- long currentRowId = offset;
-
- @Override
- public void accept(BlockBuilder blockBuilder)
- {
- BIGINT.writeLong(blockBuilder, currentRowId++);
- }
- };
+ if (column.domain().getValues().isDiscreteSet()) {
+ List