From 09e02512536d71aeb2cbd62bd7691c4a511f44c6 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 24 Dec 2024 09:33:25 -0800 Subject: [PATCH 01/12] Updates datum datetime to use java.time --- .../java/org/partiql/spi/value/Datum.java | 116 ++++++++---------- .../java/org/partiql/spi/value/DatumDate.java | 31 +++-- .../java/org/partiql/spi/value/DatumTime.java | 40 +++--- .../org/partiql/spi/value/DatumTimestamp.java | 55 ++++++--- .../partiql/spi/value/DatumTimestampz.java | 60 +++++++++ .../org/partiql/spi/value/DatumTimez.java | 42 +++++++ 6 files changed, 231 insertions(+), 113 deletions(-) create mode 100644 partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java create mode 100644 partiql-spi/src/main/java/org/partiql/spi/value/DatumTimez.java diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java b/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java index 9db896e65b..fe4aa5e38f 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java @@ -18,6 +18,7 @@ import java.math.MathContext; import java.math.RoundingMode; import java.nio.charset.Charset; +import java.time.*; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -123,153 +124,144 @@ default byte getByte() { /** * @return the underlying value applicable to the types: - * {@link PType#DATE}. + * {@link PType#SMALLINT} * @throws UnsupportedOperationException if the operation is not applicable to the type returned from * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method * will throw this exception upon invocation. * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that * {@link #isNull()} returns false before attempting to invoke this method. */ - @NotNull - default org.partiql.value.datetime.Date getDate() { + default short getShort() { throw new UnsupportedOperationException(); } /** * @return the underlying value applicable to the types: - * {@link PType#TIME} + * {@link PType#INTEGER} * @throws UnsupportedOperationException if the operation is not applicable to the type returned from * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method * will throw this exception upon invocation. * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that * {@link #isNull()} returns false before attempting to invoke this method. */ - @NotNull - default Time getTime() { + default int getInt() { throw new UnsupportedOperationException(); } /** * @return the underlying value applicable to the types: - * {@link PType#TIMESTAMP}. + * {@link PType#BIGINT} * @throws UnsupportedOperationException if the operation is not applicable to the type returned from * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method * will throw this exception upon invocation. * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that * {@link #isNull()} returns false before attempting to invoke this method. */ - @NotNull - default Timestamp getTimestamp() { + default long getLong() { throw new UnsupportedOperationException(); } /** - * ! ! ! EXPERIMENTAL ! ! ! This is an experimental API under development by the PartiQL maintainers. * @return the underlying value applicable to the types: - * TODO + * {@link PType#INTEGER} * @throws UnsupportedOperationException if the operation is not applicable to the type returned from * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method * will throw this exception upon invocation. * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that * {@link #isNull()} returns false before attempting to invoke this method. - * Please abstain from using this API until given notice otherwise. This may break between iterations without prior notice. - * @deprecated This implementation is likely wrong and is not recommended for use. */ - @Deprecated - default long getInterval() { + @NotNull + default BigInteger getBigInteger() { throw new UnsupportedOperationException(); } /** * @return the underlying value applicable to the types: - * {@link PType#SMALLINT} + * {@link PType#REAL} * @throws UnsupportedOperationException if the operation is not applicable to the type returned from * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method * will throw this exception upon invocation. * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that * {@link #isNull()} returns false before attempting to invoke this method. */ - default short getShort() { + default float getFloat() { throw new UnsupportedOperationException(); } /** * @return the underlying value applicable to the types: - * {@link PType#INTEGER} + * {@link PType#DOUBLE} * @throws UnsupportedOperationException if the operation is not applicable to the type returned from * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method * will throw this exception upon invocation. * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that * {@link #isNull()} returns false before attempting to invoke this method. */ - default int getInt() { + default double getDouble() { throw new UnsupportedOperationException(); } /** * @return the underlying value applicable to the types: - * {@link PType#BIGINT} + * {@link PType#DECIMAL} * @throws UnsupportedOperationException if the operation is not applicable to the type returned from * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method * will throw this exception upon invocation. * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that * {@link #isNull()} returns false before attempting to invoke this method. */ - default long getLong() { + @NotNull + default BigDecimal getBigDecimal() { throw new UnsupportedOperationException(); } /** - * @return the underlying value applicable to the types: - * {@link PType#INTEGER} - * @throws UnsupportedOperationException if the operation is not applicable to the type returned from - * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method - * will throw this exception upon invocation. - * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that - * {@link #isNull()} returns false before attempting to invoke this method. + * @return a {@link LocalDate} for DATE, TIMESTAMP, and TIMESTAMPZ types. + * @throws UnsupportedOperationException if type not in (DATE, TIMESTAMP, TIMESTAMPZ) + * @throws NullPointerException if isNull() is true; callers should check to avoid NPEs. */ @NotNull - default BigInteger getBigInteger() { + default LocalDate getLocalDate() { throw new UnsupportedOperationException(); } /** - * @return the underlying value applicable to the types: - * {@link PType#REAL} - * @throws UnsupportedOperationException if the operation is not applicable to the type returned from - * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method - * will throw this exception upon invocation. - * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that - * {@link #isNull()} returns false before attempting to invoke this method. + * @return an {@link OffsetTime} for TIME, TIMEZ, TIMESTAMP, TIMESTAMPZ types. + * @throws UnsupportedOperationException if type not in (TIME, TIMEZ, TIMESTAMP, TIMESTAMPZ) + * @throws NullPointerException if isNull() is true; callers should check to avoid NPEs. */ - default float getFloat() { + @NotNull + default LocalTime getLocalTime() { throw new UnsupportedOperationException(); } /** - * @return the underlying value applicable to the types: - * {@link PType#DOUBLE} - * @throws UnsupportedOperationException if the operation is not applicable to the type returned from - * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method - * will throw this exception upon invocation. - * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that - * {@link #isNull()} returns false before attempting to invoke this method. + * @return an {@link OffsetTime} for TIMEZ and TIMESTAMPZ types. + * @throws UnsupportedOperationException if type not in (TIMEZ, TIMESTAMPZ) + * @throws NullPointerException if isNull() is true; callers should check to avoid NPEs. */ - default double getDouble() { + @NotNull + default OffsetTime getOffsetTime() { + throw new UnsupportedOperationException("Cannot call getOffsetTime "); + } + + /** + * @return a {@link LocalDateTime} for TIMESTAMP, TIMESTAMPZ types. + * @throws UnsupportedOperationException if type not in (TIMESTAMP, TIMESTAMPZ) + * @throws NullPointerException if isNull() is true; callers should check to avoid NPEs. + */ + @NotNull + default LocalDateTime getLocalDateTime() { throw new UnsupportedOperationException(); } /** - * @return the underlying value applicable to the types: - * {@link PType#DECIMAL} - * @throws UnsupportedOperationException if the operation is not applicable to the type returned from - * {@link #getType()}; for example, if {@link #getType()} returns a {@link PType#INTEGER}, then this method - * will throw this exception upon invocation. - * @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that - * {@link #isNull()} returns false before attempting to invoke this method. + * @return a {@link OffsetDateTime} for TIMESTAMPZ types. + * @throws UnsupportedOperationException if type not TIMESTAMPZ + * @throws NullPointerException if isNull() is true; callers should check to avoid NPEs. */ @NotNull - default BigDecimal getBigDecimal() { + default OffsetDateTime getOffsetDateTime() { throw new UnsupportedOperationException(); } @@ -529,28 +521,28 @@ static Datum blob(@NotNull byte[] value, int length) { // DATE/TIME @NotNull - static Datum date(@NotNull Date value) { + static Datum date(@NotNull LocalDate value) { return new DatumDate(value); } @NotNull - static Datum time(@NotNull Time value) { - return new DatumTime(value); + static Datum time(@NotNull LocalTime value, int precision) { + return new DatumTime(value, precision); } @NotNull - static Datum time(@NotNull Time value, int precision) { - return new DatumTime(value, precision); + static Datum timez(@NotNull OffsetTime value, int precision) { + return new DatumTimez(value, precision); } @NotNull - static Datum timestamp(@NotNull Timestamp value) { - return new DatumTimestamp(value); + static Datum timestamp(@NotNull LocalDateTime value, int precision) { + return new DatumTimestamp(value, precision); } @NotNull - static Datum timestamp(@NotNull Timestamp value, int precision) { - return new DatumTimestamp(value, precision); + static Datum timestampz(@NotNull OffsetDateTime value, int precision) { + return new DatumTimestampz(value, precision); } // COLLECTIONS diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumDate.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumDate.java index cac1a359ab..d8c1dce6e3 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumDate.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumDate.java @@ -3,34 +3,33 @@ import org.jetbrains.annotations.NotNull; import org.partiql.types.PType; +import java.time.LocalDate; + /** - * This shall always be package-private (internal). + * Today we wrap a {@link LocalDate}, in the future we can do a 7-byte array to avoid double references. */ -class DatumDate implements Datum { +final class DatumDate implements Datum { @NotNull - private final org.partiql.value.datetime.Date _value; + private final PType type; - private static final PType _type = PType.date(); + @NotNull + private final LocalDate value; - DatumDate(@NotNull org.partiql.value.datetime.Date value) { - _value = value; + DatumDate(@NotNull LocalDate value) { + this.type = PType.date(); + this.value = value; } + @NotNull @Override - public boolean isNull() { - return false; + public PType getType() { + return type; } @Override @NotNull - public org.partiql.value.datetime.Date getDate() { - return _value; - } - - @NotNull - @Override - public PType getType() { - return _type; + public LocalDate getLocalDate() { + return value; } } diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTime.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTime.java index 803440bfc5..0922c0c57e 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTime.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTime.java @@ -2,38 +2,42 @@ import org.jetbrains.annotations.NotNull; import org.partiql.types.PType; -import org.partiql.value.datetime.Time; + +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; /** - * This shall always be package-private (internal). + * Today we wrap a {@link LocalTime}, in the future we do a 4-byte array to avoid double references. */ -class DatumTime implements Datum { +final class DatumTime implements Datum { @NotNull - private final Time _value; + private final PType type; - // TODO: Create a variant specifically for without TZ - private final PType _type; + @NotNull + private final LocalTime value; - DatumTime(@NotNull Time value) { - _value = value.toPrecision(6); - _type = PType.timez(6); + DatumTime(@NotNull LocalTime value, int precision) { + this.type = PType.time(precision); + this.value = value; } - DatumTime(@NotNull Time value, int precision) { - _value = value.toPrecision(precision); - _type = PType.timez(precision); + @NotNull + @Override + public PType getType() { + return type; } - @Override @NotNull - public Time getTime() { - return _value; + @Override + public LocalTime getLocalTime() { + return value; } @NotNull @Override - public PType getType() { - return _type; + public OffsetTime getOffsetTime() { + return value.atOffset(ZoneOffset.UTC); } -} +} \ No newline at end of file diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java index 75bda7a27f..0a1fe584e5 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java @@ -1,39 +1,60 @@ package org.partiql.spi.value; + import org.jetbrains.annotations.NotNull; import org.partiql.types.PType; -import org.partiql.value.datetime.Timestamp; + +import java.time.*; /** - * This shall always be package-private (internal). + * Today we wrap a {@link LocalDateTime}, in the future we do a 7-byte array to avoid double references. */ -class DatumTimestamp implements Datum { +final class DatumTimestamp implements Datum { @NotNull - private final Timestamp _value; + private final PType type; - // TODO: Create a variant specifically for without TZ - private final PType _type; + @NotNull + private final LocalDateTime value; - DatumTimestamp(@NotNull Timestamp value) { - _value = value.toPrecision(6); - _type = PType.timestampz(6); + DatumTimestamp(@NotNull LocalDateTime value, int precision) { + this.type = PType.timestamp(precision); + this.value = value; } - DatumTimestamp(@NotNull Timestamp value, int precision) { - _value = value.toPrecision(precision); - _type = PType.timestampz(precision); + @NotNull + @Override + public PType getType() { + return type; } + @NotNull @Override + public LocalDate getLocalDate() { + return value.toLocalDate(); + } + @NotNull - public Timestamp getTimestamp() { - return _value; + @Override + public LocalTime getLocalTime() { + return value.toLocalTime(); } @NotNull @Override - public PType getType() { - return _type; + public OffsetTime getOffsetTime() { + return value.atOffset(ZoneOffset.UTC).toOffsetTime(); + } + + @NotNull + @Override + public LocalDateTime getLocalDateTime() { + return value; + } + + @NotNull + @Override + public OffsetDateTime getOffsetDateTime() { + return value.atOffset(ZoneOffset.UTC); } -} +} \ No newline at end of file diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java new file mode 100644 index 0000000000..7a8a760b14 --- /dev/null +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java @@ -0,0 +1,60 @@ +package org.partiql.spi.value; + + +import org.jetbrains.annotations.NotNull; +import org.partiql.types.PType; + +import java.time.*; + +/** + * Today we wrap an {@link OffsetDateTime}, in the future we do an 8-byte array to avoid double references. + */ +final class DatumTimestampz implements Datum { + + @NotNull + private final PType type; + + @NotNull + private final OffsetDateTime value; + + DatumTimestampz(@NotNull OffsetDateTime value, int precision) { + this.type = PType.timestamp(precision); + this.value = value; + } + + @NotNull + @Override + public PType getType() { + return type; + } + + @NotNull + @Override + public LocalDate getLocalDate() { + return value.toLocalDate(); + } + + @NotNull + @Override + public LocalTime getLocalTime() { + return value.toLocalTime(); + } + + @NotNull + @Override + public OffsetTime getOffsetTime() { + return value.toOffsetTime(); + } + + @NotNull + @Override + public LocalDateTime getLocalDateTime() { + return value.toLocalDateTime(); + } + + @NotNull + @Override + public OffsetDateTime getOffsetDateTime() { + return value; + } +} \ No newline at end of file diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimez.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimez.java new file mode 100644 index 0000000000..3a5a554555 --- /dev/null +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimez.java @@ -0,0 +1,42 @@ +package org.partiql.spi.value; + +import org.jetbrains.annotations.NotNull; +import org.partiql.types.PType; + +import java.time.LocalTime; +import java.time.OffsetTime; + +/** + * Today we wrap an {@link OffsetTime}, in the future we do a 5-byte array to avoid double references. + */ +final class DatumTimez implements Datum { + + @NotNull + private final PType type; + + @NotNull + private final OffsetTime value; + + DatumTimez(@NotNull OffsetTime value, int precision) { + this.type = PType.timez(precision); + this.value = value; + } + + @NotNull + @Override + public PType getType() { + return type; + } + + @NotNull + @Override + public LocalTime getLocalTime() { + return value.toLocalTime(); + } + + @NotNull + @Override + public OffsetTime getOffsetTime() { + return value; + } +} \ No newline at end of file From 77b6d64cc3a9d4b20bcaca71d2525402611105e5 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 24 Dec 2024 11:04:16 -0800 Subject: [PATCH 02/12] Updates IonVariant for datetime java.time --- .../org/partiql/spi/value/ion/IonVariant.kt | 156 +++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt index 90d3a586bb..f000c089cf 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt @@ -1,8 +1,12 @@ package org.partiql.spi.value.ion +import com.amazon.ion.Timestamp import com.amazon.ion.system.IonBinaryWriterBuilder import com.amazon.ion.system.IonTextWriterBuilder import com.amazon.ionelement.api.AnyElement +import java.math.BigDecimal +import java.math.BigInteger + import com.amazon.ionelement.api.ElementType import com.amazon.ionelement.api.ElementType.BLOB import com.amazon.ionelement.api.ElementType.BOOL @@ -20,10 +24,15 @@ import com.amazon.ionelement.api.IntElementSize import org.partiql.spi.value.Datum import org.partiql.spi.value.Field import org.partiql.types.PType -import org.partiql.value.datetime.DateTimeValue import java.io.ByteArrayOutputStream import java.nio.charset.Charset import java.nio.charset.StandardCharsets +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.OffsetTime +import java.time.ZoneOffset /** * A [Datum] implemented over Ion's [AnyElement]. @@ -62,7 +71,11 @@ internal class IonVariant(private var value: AnyElement) : Datum { BOOL -> Datum.bool(value.booleanValue) CLOB -> Datum.clob(value.clobValue.copyOfBytes()) BLOB -> Datum.blob(value.blobValue.copyOfBytes()) - TIMESTAMP -> Datum.timestamp(DateTimeValue.timestamp(value.timestampValue)) + TIMESTAMP -> { + val ts = value.timestampValue + val ot = ts.toOffsetDateTime() + Datum.timestampz(ot, 9) + } INT -> { when (value.integerSize) { IntElementSize.LONG -> { @@ -115,4 +128,143 @@ internal class IonVariant(private var value: AnyElement) : Datum { override fun isNull(): Boolean = false override fun isMissing(): Boolean = false + + override fun getString(): String = when (value.type) { + SYMBOL -> value.stringValue + STRING -> value.stringValue + else -> super.getString() + } + + override fun getBoolean(): Boolean = when (value.type) { + BOOL -> value.booleanValue + else -> super.getBoolean() + } + + @Deprecated("Deprecated in Java") + override fun getBytes(): ByteArray = when (value.type) { + CLOB -> value.clobValue.copyOfBytes() + BLOB -> value.blobValue.copyOfBytes() + else -> super.getBytes() + } + + /** + * Ion timestamp with "whole-day precision" and no time component. + */ + override fun getLocalDate(): LocalDate { + if (value.type != TIMESTAMP) { + return super.getLocalDate() + } + val ts = value.timestampValue + return LocalDate.of(ts.year, ts.month, ts.day) + } + + /** + * Ion does not have a TIME type, only TIMESTAMP, so use lower() then coerce. + */ + override fun getLocalTime(): LocalTime { + throw IllegalArgumentException("getLocalTime() not supported, use lower() or getLocalDateTime()") + } + + /** + * Ion does not have TIMEZ type, only TIMESTAMP, so use lower() then coerce. + */ + override fun getOffsetTime(): OffsetTime { + throw IllegalArgumentException("getOffsetTime() not supported, use lower() or getOffsetDateTime()") + } + + /** + * Get the OffsetDateTime and return the local part. + * + * See: https://github.com/partiql/partiql-lang-kotlin/issues/1689 + */ + override fun getLocalDateTime(): LocalDateTime { + return offsetDateTime.toLocalDateTime() + } + + /** + * Get the OffsetDateTime, using UTC if no offset is given. + */ + override fun getOffsetDateTime(): OffsetDateTime { + if (value.type != TIMESTAMP) { + return super.getOffsetDateTime() + } + return value.timestampValue.toOffsetDateTime() + } + + override fun getBigInteger(): BigInteger = when (value.type) { + INT -> value.bigIntegerValue + else -> super.getBigInteger() + } + + override fun getDouble(): Double = when (value.type) { + FLOAT -> value.doubleValue + else -> super.getDouble() + } + + override fun getBigDecimal(): BigDecimal = when (value.type) { + DECIMAL -> value.decimalValue.bigDecimalValue() + else -> super.getBigDecimal() + } + + override fun iterator(): MutableIterator = when (value.type) { + LIST -> value.listValues.map { IonVariant(it) }.toMutableList().iterator() + SEXP -> value.sexpValues.map { IonVariant(it) }.toMutableList().iterator() + else -> super.iterator() + } + + override fun getFields(): MutableIterator { + if (value.type != STRUCT) { + return super.getFields() + } + return value.structFields + .map { Field.of(it.name, IonVariant(it.value)) } + .toMutableList() + .iterator() + } + + override fun get(name: String): Datum { + if (value.type != STRUCT) { + return super.get(name) + } + // TODO handle multiple/ambiguous field names? + val v = value.asStruct().getOptional(name) + return if (v == null) { + Datum.missing() + } else { + IonVariant(v) + } + } + + override fun getInsensitive(name: String): Datum { + if (value.type != STRUCT) { + return super.get(name) + } + // TODO handle multiple/ambiguous field names? + val struct = value.asStruct() + for (field in struct.fields) { + if (field.name.equals(name, ignoreCase = true)) { + return IonVariant(field.value) + } + } + return Datum.missing() + } + + /** + * Get the OffsetDateTime from an Ion Timestamp, using UTC if no offset is given. + */ + private fun Timestamp.toOffsetDateTime(): OffsetDateTime { + val ts = this + val tz = when (ts.localOffset) { + null -> ZoneOffset.UTC + else -> ZoneOffset.ofHoursMinutes(ts.zHour, ts.zMinute) + } + // [0-59].000_000_000 + val ds = ts.decimalSecond + val second: Int = ds.toInt() + val nanoOfSecond: Int = ds.remainder(BigDecimal.ONE).movePointRight(9).toInt() + // date/time pair + val date = LocalDate.of(ts.year, ts.month, ts.day) + val time = LocalTime.of(ts.hour, ts.minute, second, nanoOfSecond) + return OffsetDateTime.of(date, time, tz) + } } From 6234b806211d6a0c9923512ecb041f98c70d87a4 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 24 Dec 2024 11:54:31 -0800 Subject: [PATCH 03/12] Assemble partiql-spi and apiDump --- .../internal/transforms/RexConverter.kt | 81 ++++++++--- partiql-spi/api/partiql-spi.api | 19 +-- .../partiql/spi/value/DatumComparator.java | 10 +- .../org/partiql/spi/value/DatumInterval.java | 27 ---- .../java/org/partiql/spi/value/DatumNull.java | 74 ++++++---- .../spi/function/builtins/FnBetween.kt | 18 +-- .../spi/function/builtins/FnDateAddDay.kt | 18 +-- .../spi/function/builtins/FnDateAddHour.kt | 24 ++-- .../spi/function/builtins/FnDateAddMinute.kt | 24 ++-- .../spi/function/builtins/FnDateAddMonth.kt | 18 +-- .../spi/function/builtins/FnDateAddSecond.kt | 24 ++-- .../spi/function/builtins/FnDateAddYear.kt | 18 +-- .../spi/function/builtins/FnExtract.kt | 135 +++++++----------- .../org/partiql/spi/function/builtins/FnGt.kt | 12 +- .../partiql/spi/function/builtins/FnGte.kt | 12 +- .../org/partiql/spi/function/builtins/FnLt.kt | 12 +- .../partiql/spi/function/builtins/FnLte.kt | 12 +- .../partiql/spi/function/builtins/FnUtcnow.kt | 6 +- 18 files changed, 279 insertions(+), 265 deletions(-) delete mode 100644 partiql-spi/src/main/java/org/partiql/spi/value/DatumInterval.java diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt index 467d3270dd..129b8c2907 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt @@ -90,16 +90,18 @@ import org.partiql.planner.internal.ir.rexOpVarLocal import org.partiql.planner.internal.ir.rexOpVarUnresolved import org.partiql.planner.internal.typer.CompilerType import org.partiql.planner.internal.typer.PlanTyper.Companion.toCType -import org.partiql.planner.internal.utils.DateTimeUtils import org.partiql.spi.catalog.Identifier import org.partiql.spi.value.Datum import org.partiql.types.PType -import org.partiql.value.datetime.DateTimeValue import java.math.BigDecimal import java.math.BigInteger import java.math.MathContext import java.math.RoundingMode import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.OffsetTime import java.time.format.DateTimeFormatter import org.partiql.ast.SetQuantifier as AstSetQuantifier @@ -194,19 +196,28 @@ internal object RexConverter { when (type.code()) { DataType.DATE -> { val value = LocalDate.parse(typedString, DateTimeFormatter.ISO_LOCAL_DATE) - val date = DateTimeValue.date(value.year, value.monthValue, value.dayOfMonth) + val date = LocalDate.of(value.year, value.monthValue, value.dayOfMonth) return Datum.date(date) } - DataType.TIME, DataType.TIME_WITH_TIME_ZONE -> { - val time = DateTimeUtils.parseTimeLiteral(typedString) + DataType.TIME -> { + val time = LocalTime.parse(typedString, DateTimeFormatter.ISO_LOCAL_TIME) val precision = type.precision ?: 6 return Datum.time(time, precision) } - DataType.TIMESTAMP, DataType.TIMESTAMP_WITH_TIME_ZONE -> { - val timestamp = DateTimeUtils.parseTimestamp(typedString) + DataType.TIME_WITH_TIME_ZONE -> { + val time = OffsetTime.parse(typedString, DateTimeFormatter.ISO_OFFSET_TIME) val precision = type.precision ?: 6 - val value = timestamp.toPrecision(precision) - return Datum.timestamp(value) + return Datum.timez(time, precision) + } + DataType.TIMESTAMP -> { + val timestamp = LocalDateTime.parse(typedString, DateTimeFormatter.ISO_LOCAL_DATE_TIME) + val precision = type.precision ?: 6 + return Datum.timestamp(timestamp, precision) + } + DataType.TIMESTAMP_WITH_TIME_ZONE -> { + val timestamp = OffsetDateTime.parse(typedString, DateTimeFormatter.ISO_OFFSET_DATE_TIME) + val precision = type.precision ?: 6 + return Datum.timestampz(timestamp, precision) } else -> error("Unsupported typed literal string: $this") } @@ -241,7 +252,11 @@ internal object RexConverter { * @param ctx * @return */ - internal fun visitExprCoerce(node: Expr, ctx: Env, coercion: Rex.Op.Subquery.Coercion = Rex.Op.Subquery.Coercion.SCALAR): Rex { + internal fun visitExprCoerce( + node: Expr, + ctx: Env, + coercion: Rex.Op.Subquery.Coercion = Rex.Op.Subquery.Coercion.SCALAR, + ): Rex { val rex = node.accept(this, ctx) return when (isSqlSelect(node)) { true -> { @@ -293,7 +308,8 @@ internal object RexConverter { val args = when (symbol) { "<", ">", "<=", ">=", - "=", "<>", "!=" -> { + "=", "<>", "!=", + -> { when { // Example: [1, 2] < (SELECT a, b FROM t) isLiteralArray(lhs) && isSqlSelect(rhs) -> { @@ -555,9 +571,18 @@ internal object RexConverter { val selectRef = fromNode.type.schema.size - 1 val constructor = when (val op = curPathNavi.op) { - is Rex.Op.Path.Index -> rex(curPathNavi.type, rexOpPathIndex(rex(op.root.type, rexOpVarLocal(0, selectRef)), op.key)) - is Rex.Op.Path.Key -> rex(curPathNavi.type, rexOpPathKey(rex(op.root.type, rexOpVarLocal(0, selectRef)), op.key)) - is Rex.Op.Path.Symbol -> rex(curPathNavi.type, rexOpPathSymbol(rex(op.root.type, rexOpVarLocal(0, selectRef)), op.key)) + is Rex.Op.Path.Index -> rex( + curPathNavi.type, + rexOpPathIndex(rex(op.root.type, rexOpVarLocal(0, selectRef)), op.key) + ) + is Rex.Op.Path.Key -> rex( + curPathNavi.type, + rexOpPathKey(rex(op.root.type, rexOpVarLocal(0, selectRef)), op.key) + ) + is Rex.Op.Path.Symbol -> rex( + curPathNavi.type, + rexOpPathSymbol(rex(op.root.type, rexOpVarLocal(0, selectRef)), op.key) + ) is Rex.Op.Var.Local -> rex(curPathNavi.type, rexOpVarLocal(0, selectRef)) else -> throw IllegalStateException() } @@ -869,7 +894,12 @@ internal object RexConverter { DataType.BIT_VARYING -> call("is_bitVarying", arg0) // TODO define in parser // - DataType.NUMERIC -> call("is_numeric", targetType.precision.toRex(), targetType.scale.toRex(), arg0) - DataType.DEC, DataType.DECIMAL -> call("is_decimal", targetType.precision.toRex(), targetType.scale.toRex(), arg0) + DataType.DEC, DataType.DECIMAL -> call( + "is_decimal", + targetType.precision.toRex(), + targetType.scale.toRex(), + arg0 + ) DataType.BIGINT, DataType.INT8, DataType.INTEGER8 -> call("is_int64", arg0) DataType.INT4, DataType.INTEGER4, DataType.INTEGER -> call("is_int32", arg0) DataType.INT -> call("is_int", arg0) @@ -1111,9 +1141,24 @@ internal object RexConverter { // DataType.DATE -> PType.date() DataType.TIME -> assertGtEqZeroAndCreate(PType.TIME, "precision", type.precision ?: 0, PType::time) - DataType.TIME_WITH_TIME_ZONE -> assertGtEqZeroAndCreate(PType.TIMEZ, "precision", type.precision ?: 0, PType::timez) - DataType.TIMESTAMP -> assertGtEqZeroAndCreate(PType.TIMESTAMP, "precision", type.precision ?: 6, PType::timestamp) - DataType.TIMESTAMP_WITH_TIME_ZONE -> assertGtEqZeroAndCreate(PType.TIMESTAMPZ, "precision", type.precision ?: 6, PType::timestampz) + DataType.TIME_WITH_TIME_ZONE -> assertGtEqZeroAndCreate( + PType.TIMEZ, + "precision", + type.precision ?: 0, + PType::timez + ) + DataType.TIMESTAMP -> assertGtEqZeroAndCreate( + PType.TIMESTAMP, + "precision", + type.precision ?: 6, + PType::timestamp + ) + DataType.TIMESTAMP_WITH_TIME_ZONE -> assertGtEqZeroAndCreate( + PType.TIMESTAMPZ, + "precision", + type.precision ?: 6, + PType::timestampz + ) // DataType.INTERVAL -> error("INTERVAL is not supported yet.") // diff --git a/partiql-spi/api/partiql-spi.api b/partiql-spi/api/partiql-spi.api index a784ebee64..46350cacce 100644 --- a/partiql-spi/api/partiql-spi.api +++ b/partiql-spi/api/partiql-spi.api @@ -477,7 +477,7 @@ public abstract interface class org/partiql/spi/value/Datum : java/lang/Iterable public static fun clob ([BI)Lorg/partiql/spi/value/Datum; public static fun comparator ()Ljava/util/Comparator; public static fun comparator (Z)Ljava/util/Comparator; - public static fun date (Lorg/partiql/value/datetime/Date;)Lorg/partiql/spi/value/Datum; + public static fun date (Ljava/time/LocalDate;)Lorg/partiql/spi/value/Datum; public static fun decimal (Ljava/math/BigDecimal;)Lorg/partiql/spi/value/Datum; public static fun decimal (Ljava/math/BigDecimal;II)Lorg/partiql/spi/value/Datum; public static fun doublePrecision (D)Lorg/partiql/spi/value/Datum; @@ -487,18 +487,19 @@ public abstract interface class org/partiql/spi/value/Datum : java/lang/Iterable public fun getBoolean ()Z public fun getByte ()B public fun getBytes ()[B - public fun getDate ()Lorg/partiql/value/datetime/Date; public fun getDouble ()D public fun getFields ()Ljava/util/Iterator; public fun getFloat ()F public fun getInsensitive (Ljava/lang/String;)Lorg/partiql/spi/value/Datum; public fun getInt ()I - public fun getInterval ()J + public fun getLocalDate ()Ljava/time/LocalDate; + public fun getLocalDateTime ()Ljava/time/LocalDateTime; + public fun getLocalTime ()Ljava/time/LocalTime; public fun getLong ()J + public fun getOffsetDateTime ()Ljava/time/OffsetDateTime; + public fun getOffsetTime ()Ljava/time/OffsetTime; public fun getShort ()S public fun getString ()Ljava/lang/String; - public fun getTime ()Lorg/partiql/value/datetime/Time; - public fun getTimestamp ()Lorg/partiql/value/datetime/Timestamp; public abstract fun getType ()Lorg/partiql/types/PType; public static fun integer (I)Lorg/partiql/spi/value/Datum; public static fun ion (Ljava/lang/String;)Lorg/partiql/spi/value/Datum; @@ -517,10 +518,10 @@ public abstract interface class org/partiql/spi/value/Datum : java/lang/Iterable public static fun string (Ljava/lang/String;)Lorg/partiql/spi/value/Datum; public static fun struct ()Lorg/partiql/spi/value/Datum; public static fun struct (Ljava/lang/Iterable;)Lorg/partiql/spi/value/Datum; - public static fun time (Lorg/partiql/value/datetime/Time;)Lorg/partiql/spi/value/Datum; - public static fun time (Lorg/partiql/value/datetime/Time;I)Lorg/partiql/spi/value/Datum; - public static fun timestamp (Lorg/partiql/value/datetime/Timestamp;)Lorg/partiql/spi/value/Datum; - public static fun timestamp (Lorg/partiql/value/datetime/Timestamp;I)Lorg/partiql/spi/value/Datum; + public static fun time (Ljava/time/LocalTime;I)Lorg/partiql/spi/value/Datum; + public static fun timestamp (Ljava/time/LocalDateTime;I)Lorg/partiql/spi/value/Datum; + public static fun timestampz (Ljava/time/OffsetDateTime;I)Lorg/partiql/spi/value/Datum; + public static fun timez (Ljava/time/OffsetTime;I)Lorg/partiql/spi/value/Datum; public static fun tinyint (B)Lorg/partiql/spi/value/Datum; public static fun varchar (Ljava/lang/String;)Lorg/partiql/spi/value/Datum; public static fun varchar (Ljava/lang/String;I)Lorg/partiql/spi/value/Datum; diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumComparator.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumComparator.java index 69fc85884c..e346ee93f1 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumComparator.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumComparator.java @@ -526,7 +526,7 @@ private static DatumComparison[] fillDecimalComparator(DatumComparison[] comps) @SuppressWarnings({"UnusedReturnValue"}) private static DatumComparison[] fillDateComparator(DatumComparison[] comps) { - comps[DATE] = (self, date, comp) -> self.getDate().compareTo(date.getDate()); + comps[DATE] = (self, date, comp) -> self.getLocalDate().compareTo(date.getLocalDate()); return comps; } @@ -538,8 +538,8 @@ private static DatumComparison[] fillDateComparator(DatumComparison[] comps) { */ @SuppressWarnings({"UnusedReturnValue"}) private static DatumComparison[] fillTimeComparator(DatumComparison[] comps) { - comps[TIME] = (self, time, comp) -> self.getTime().compareTo(time.getTime()); - comps[TIMEZ] = (self, time, comp) -> self.getTime().compareTo(time.getTime()); + comps[TIME] = (self, time, comp) -> self.getLocalTime().compareTo(time.getLocalTime()); + comps[TIMEZ] = (self, time, comp) -> self.getOffsetTime().compareTo(time.getOffsetTime()); return comps; } @@ -551,8 +551,8 @@ private static DatumComparison[] fillTimeComparator(DatumComparison[] comps) { */ @SuppressWarnings({"UnusedReturnValue"}) private static DatumComparison[] fillTimestampComparator(DatumComparison[] comps) { - comps[TIMESTAMPZ] = (self, timestamp, comp) -> self.getTimestamp().compareTo(timestamp.getTimestamp()); - comps[TIMESTAMP] = (self, timestamp, comp) -> self.getTimestamp().compareTo(timestamp.getTimestamp()); + comps[TIMESTAMP] = (self, timestamp, comp) -> self.getLocalDateTime().compareTo(timestamp.getLocalDateTime()); + comps[TIMESTAMPZ] = (self, timestamp, comp) -> self.getOffsetDateTime().compareTo(timestamp.getOffsetDateTime()); return comps; } diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumInterval.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumInterval.java deleted file mode 100644 index 4fd9f2b456..0000000000 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumInterval.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.partiql.spi.value; - -import org.jetbrains.annotations.NotNull; -import org.partiql.types.PType; - -/** - * This shall always be package-private (internal). - */ -class DatumInterval implements Datum { - - private final long _value; - - DatumInterval(long value) { - _value = value; - } - - @Override - public long getInterval() { - return _value; - } - - @NotNull - @Override - public PType getType() { - throw new UnsupportedOperationException("NOT YET IMPLEMENTED"); - } -} diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java index 70da87d9ec..c34e82d7f1 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java @@ -2,12 +2,10 @@ import org.jetbrains.annotations.NotNull; import org.partiql.types.PType; -import org.partiql.value.datetime.Date; -import org.partiql.value.datetime.Time; -import org.partiql.value.datetime.Timestamp; import java.math.BigDecimal; import java.math.BigInteger; +import java.time.*; import java.util.Iterator; /** @@ -112,16 +110,6 @@ public byte[] getBytes() { } } - @NotNull - @Override - public Date getDate() { - if (_type.code() == PType.DATE) { - throw new NullPointerException(); - } else { - throw new UnsupportedOperationException(); - } - } - @Override public double getDouble() { if (_type.code() == PType.DOUBLE) { @@ -172,26 +160,62 @@ public String getString() { @NotNull @Override - public Time getTime() { - if (_type.code() == PType.TIMEZ || _type.code() == PType.TIME) { - throw new NullPointerException(); - } else { - throw new UnsupportedOperationException(); + public LocalDate getLocalDate() { + switch (_type.code()) { + case PType.DATE: + case PType.TIMESTAMP: + case PType.TIMESTAMPZ: + throw new NullPointerException(); + default: + throw new UnsupportedOperationException(); } } @NotNull @Override - public Timestamp getTimestamp() { - if (_type.code() == PType.TIMESTAMPZ || _type.code() == PType.TIMESTAMP) { - throw new NullPointerException(); - } else { - throw new UnsupportedOperationException(); + public LocalTime getLocalTime() { + switch (_type.code()) { + case PType.TIME: + case PType.TIMEZ: + case PType.TIMESTAMP: + case PType.TIMESTAMPZ: + throw new NullPointerException(); + default: + throw new UnsupportedOperationException(); } } + @NotNull @Override - public long getInterval() { - throw new UnsupportedOperationException(); + public OffsetTime getOffsetTime() { + switch (_type.code()) { + case PType.TIMEZ: + case PType.TIMESTAMPZ: + throw new NullPointerException(); + default: + throw new UnsupportedOperationException(); + } + } + + @NotNull + @Override + public LocalDateTime getLocalDateTime() { + switch (_type.code()) { + case PType.TIMESTAMP: + case PType.TIMESTAMPZ: + throw new NullPointerException(); + default: + throw new UnsupportedOperationException(); + } + } + + @NotNull + @Override + public OffsetDateTime getOffsetDateTime() { + if (_type.code() == PType.TIMESTAMPZ) { + throw new NullPointerException(); + } else { + throw new UnsupportedOperationException(); + } } } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnBetween.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnBetween.kt index 3df72bc163..f629fdb741 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnBetween.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnBetween.kt @@ -189,9 +189,9 @@ internal val Fn_BETWEEN__DATE_DATE_DATE__BOOL = Function.static( ), ) { args -> - val value = args[0].date - val lower = args[1].date - val upper = args[2].date + val value = args[0].localDate + val lower = args[1].localDate + val upper = args[2].localDate Datum.bool(value in lower..upper) } @@ -206,9 +206,9 @@ internal val Fn_BETWEEN__TIME_TIME_TIME__BOOL = Function.static( ), ) { args -> - val value = args[0].time - val lower = args[1].time - val upper = args[2].time + val value = args[0].localTime + val lower = args[1].localTime + val upper = args[2].localTime Datum.bool(value in lower..upper) } @@ -223,8 +223,8 @@ internal val Fn_BETWEEN__TIMESTAMP_TIMESTAMP_TIMESTAMP__BOOL = Function.static( ), ) { args -> - val value = args[0].timestamp - val lower = args[1].timestamp - val upper = args[2].timestamp + val value = args[0].localDateTime + val lower = args[1].localDateTime + val upper = args[2].localDateTime Datum.bool(value in lower..upper) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddDay.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddDay.kt index 98f9e4f5a9..55b82129ac 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddDay.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddDay.kt @@ -21,7 +21,7 @@ internal val Fn_DATE_ADD_DAY__INT32_DATE__DATE = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = interval.toLong() Datum.date(datetimeValue.plusDays(intervalValue)) @@ -38,7 +38,7 @@ internal val Fn_DATE_ADD_DAY__INT64_DATE__DATE = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = interval Datum.date(datetimeValue.plusDays(intervalValue)) @@ -55,7 +55,7 @@ internal val Fn_DATE_ADD_DAY__INT_DATE__DATE = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = try { interval.toLong() @@ -76,10 +76,10 @@ internal val Fn_DATE_ADD_DAY__INT32_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval.toLong() - Datum.timestamp(datetimeValue.plusDays(intervalValue)) + Datum.timestamp(datetimeValue.plusDays(intervalValue), 6) } internal val Fn_DATE_ADD_DAY__INT64_TIMESTAMP__TIMESTAMP = Function.static( @@ -93,10 +93,10 @@ internal val Fn_DATE_ADD_DAY__INT64_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval - Datum.timestamp(datetimeValue.plusDays(intervalValue)) + Datum.timestamp(datetimeValue.plusDays(intervalValue), 6) } internal val Fn_DATE_ADD_DAY__INT_TIMESTAMP__TIMESTAMP = Function.static( @@ -110,12 +110,12 @@ internal val Fn_DATE_ADD_DAY__INT_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = try { interval.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.timestamp(datetimeValue.plusDays(intervalValue)) + Datum.timestamp(datetimeValue.plusDays(intervalValue), 6) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddHour.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddHour.kt index be21e3c081..ff77ffa8d1 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddHour.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddHour.kt @@ -22,9 +22,9 @@ internal val Fn_DATE_ADD_HOUR__INT32_TIME__TIME = Function.static( ) { args -> val interval = args[0].int val datetime = args[1] - val datetimeValue = datetime.time + val datetimeValue = datetime.localTime val intervalValue = interval.toLong() - Datum.time(datetimeValue.plusHours(intervalValue)) + Datum.time(datetimeValue.plusHours(intervalValue), 6) } internal val Fn_DATE_ADD_HOUR__INT64_TIME__TIME = Function.static( @@ -39,9 +39,9 @@ internal val Fn_DATE_ADD_HOUR__INT64_TIME__TIME = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.time + val datetimeValue = datetime.localTime val intervalValue = interval.long - Datum.time(datetimeValue.plusHours(intervalValue)) + Datum.time(datetimeValue.plusHours(intervalValue), 6) } internal val Fn_DATE_ADD_HOUR__INT_TIME__TIME = Function.static( @@ -56,13 +56,13 @@ internal val Fn_DATE_ADD_HOUR__INT_TIME__TIME = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.time + val datetimeValue = datetime.localTime val intervalValue = try { interval.bigInteger.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.time(datetimeValue.plusHours(intervalValue)) + Datum.time(datetimeValue.plusHours(intervalValue), 6) } internal val Fn_DATE_ADD_HOUR__INT32_TIMESTAMP__TIMESTAMP = Function.static( @@ -77,9 +77,9 @@ internal val Fn_DATE_ADD_HOUR__INT32_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].int val datetime = args[1] - val datetimeValue = datetime.timestamp + val datetimeValue = datetime.localDateTime val intervalValue = interval.toLong() - Datum.timestamp(datetimeValue.plusHours(intervalValue)) + Datum.timestamp(datetimeValue.plusHours(intervalValue), 6) } internal val Fn_DATE_ADD_HOUR__INT64_TIMESTAMP__TIMESTAMP = Function.static( @@ -94,9 +94,9 @@ internal val Fn_DATE_ADD_HOUR__INT64_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.timestamp + val datetimeValue = datetime.localDateTime val intervalValue = interval.long - Datum.timestamp(datetimeValue.plusHours(intervalValue)) + Datum.timestamp(datetimeValue.plusHours(intervalValue), 6) } internal val Fn_DATE_ADD_HOUR__INT_TIMESTAMP__TIMESTAMP = Function.static( @@ -111,11 +111,11 @@ internal val Fn_DATE_ADD_HOUR__INT_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.timestamp + val datetimeValue = datetime.localDateTime val intervalValue = try { interval.bigInteger.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.timestamp(datetimeValue.plusHours(intervalValue)) + Datum.timestamp(datetimeValue.plusHours(intervalValue), 6) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMinute.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMinute.kt index 9811538a93..04a83e36d7 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMinute.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMinute.kt @@ -22,9 +22,9 @@ internal val Fn_DATE_ADD_MINUTE__INT32_TIME__TIME = Function.static( ) { args -> val interval = args[0].int val datetime = args[1] - val datetimeValue = datetime.time + val datetimeValue = datetime.localTime val intervalValue = interval.toLong() - Datum.time(datetimeValue.plusMinutes(intervalValue)) + Datum.time(datetimeValue.plusMinutes(intervalValue), 6) } internal val Fn_DATE_ADD_MINUTE__INT64_TIME__TIME = Function.static( @@ -39,9 +39,9 @@ internal val Fn_DATE_ADD_MINUTE__INT64_TIME__TIME = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.time + val datetimeValue = datetime.localTime val intervalValue = interval.long - Datum.time(datetimeValue.plusMinutes(intervalValue)) + Datum.time(datetimeValue.plusMinutes(intervalValue), 6) } internal val Fn_DATE_ADD_MINUTE__INT_TIME__TIME = Function.static( @@ -56,13 +56,13 @@ internal val Fn_DATE_ADD_MINUTE__INT_TIME__TIME = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.time + val datetimeValue = datetime.localTime val intervalValue = try { interval.bigInteger.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.time(datetimeValue.plusMinutes(intervalValue)) + Datum.time(datetimeValue.plusMinutes(intervalValue), 6) } internal val Fn_DATE_ADD_MINUTE__INT32_TIMESTAMP__TIMESTAMP = Function.static( @@ -77,9 +77,9 @@ internal val Fn_DATE_ADD_MINUTE__INT32_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].int val datetime = args[1] - val datetimeValue = datetime.timestamp + val datetimeValue = datetime.localDateTime val intervalValue = interval.toLong() - Datum.timestamp(datetimeValue.plusMinutes(intervalValue)) + Datum.timestamp(datetimeValue.plusMinutes(intervalValue), 6) } internal val Fn_DATE_ADD_MINUTE__INT64_TIMESTAMP__TIMESTAMP = Function.static( @@ -94,9 +94,9 @@ internal val Fn_DATE_ADD_MINUTE__INT64_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.timestamp + val datetimeValue = datetime.localDateTime val intervalValue = interval.long - Datum.timestamp(datetimeValue.plusMinutes(intervalValue)) + Datum.timestamp(datetimeValue.plusMinutes(intervalValue), 6) } internal val Fn_DATE_ADD_MINUTE__INT_TIMESTAMP__TIMESTAMP = Function.static( @@ -111,11 +111,11 @@ internal val Fn_DATE_ADD_MINUTE__INT_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0] val datetime = args[1] - val datetimeValue = datetime.timestamp + val datetimeValue = datetime.localDateTime val intervalValue = try { interval.bigInteger.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.timestamp(datetimeValue.plusMinutes(intervalValue)) + Datum.timestamp(datetimeValue.plusMinutes(intervalValue), 6) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMonth.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMonth.kt index 5a61e31c59..f8dd23fe1e 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMonth.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddMonth.kt @@ -21,7 +21,7 @@ internal val Fn_DATE_ADD_MONTH__INT32_DATE__DATE = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = interval.toLong() Datum.date(datetimeValue.plusMonths(intervalValue)) @@ -38,7 +38,7 @@ internal val Fn_DATE_ADD_MONTH__INT64_DATE__DATE = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = interval Datum.date(datetimeValue.plusMonths(intervalValue)) @@ -55,7 +55,7 @@ internal val Fn_DATE_ADD_MONTH__INT_DATE__DATE = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = try { interval.toLong() @@ -76,10 +76,10 @@ internal val Fn_DATE_ADD_MONTH__INT32_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval.toLong() - Datum.timestamp(datetimeValue.plusMonths(intervalValue)) + Datum.timestamp(datetimeValue.plusMonths(intervalValue), 6) } internal val Fn_DATE_ADD_MONTH__INT64_TIMESTAMP__TIMESTAMP = Function.static( @@ -93,10 +93,10 @@ internal val Fn_DATE_ADD_MONTH__INT64_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval - Datum.timestamp(datetimeValue.plusMonths(intervalValue)) + Datum.timestamp(datetimeValue.plusMonths(intervalValue), 6) } internal val Fn_DATE_ADD_MONTH__INT_TIMESTAMP__TIMESTAMP = Function.static( @@ -110,12 +110,12 @@ internal val Fn_DATE_ADD_MONTH__INT_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = try { interval.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.timestamp(datetimeValue.plusMonths(intervalValue)) + Datum.timestamp(datetimeValue.plusMonths(intervalValue), 6) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddSecond.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddSecond.kt index 53c3415e58..a8249e457d 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddSecond.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddSecond.kt @@ -21,10 +21,10 @@ internal val Fn_DATE_ADD_SECOND__INT32_TIME__TIME = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].time + val datetime = args[1].localTime val datetimeValue = datetime val intervalValue = interval.toLong() - Datum.time(datetimeValue.plusSeconds(intervalValue)) + Datum.time(datetimeValue.plusSeconds(intervalValue), 6) } internal val Fn_DATE_ADD_SECOND__INT64_TIME__TIME = Function.static( @@ -38,10 +38,10 @@ internal val Fn_DATE_ADD_SECOND__INT64_TIME__TIME = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].time + val datetime = args[1].localTime val datetimeValue = datetime val intervalValue = interval - Datum.time(datetimeValue.plusSeconds(intervalValue)) + Datum.time(datetimeValue.plusSeconds(intervalValue), 6) } internal val Fn_DATE_ADD_SECOND__INT_TIME__TIME = Function.static( @@ -55,14 +55,14 @@ internal val Fn_DATE_ADD_SECOND__INT_TIME__TIME = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].time + val datetime = args[1].localTime val datetimeValue = datetime val intervalValue = try { interval.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.time(datetimeValue.plusSeconds(intervalValue)) + Datum.time(datetimeValue.plusSeconds(intervalValue), 6) } internal val Fn_DATE_ADD_SECOND__INT32_TIMESTAMP__TIMESTAMP = Function.static( @@ -76,10 +76,10 @@ internal val Fn_DATE_ADD_SECOND__INT32_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval.toLong() - Datum.timestamp(datetimeValue.plusSeconds(intervalValue)) + Datum.timestamp(datetimeValue.plusSeconds(intervalValue), 6) } internal val Fn_DATE_ADD_SECOND__INT64_TIMESTAMP__TIMESTAMP = Function.static( @@ -93,10 +93,10 @@ internal val Fn_DATE_ADD_SECOND__INT64_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval - Datum.timestamp(datetimeValue.plusSeconds(intervalValue)) + Datum.timestamp(datetimeValue.plusSeconds(intervalValue), 6) } internal val Fn_DATE_ADD_SECOND__INT_TIMESTAMP__TIMESTAMP = Function.static( @@ -110,12 +110,12 @@ internal val Fn_DATE_ADD_SECOND__INT_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = try { interval.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.timestamp(datetimeValue.plusSeconds(intervalValue)) + Datum.timestamp(datetimeValue.plusSeconds(intervalValue), 6) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddYear.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddYear.kt index 4beae8cbb3..338ed5ba89 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddYear.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnDateAddYear.kt @@ -21,7 +21,7 @@ internal val Fn_DATE_ADD_YEAR__INT32_DATE__DATE = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = interval.toLong() Datum.date(datetimeValue.plusYears(intervalValue)) @@ -38,7 +38,7 @@ internal val Fn_DATE_ADD_YEAR__INT64_DATE__DATE = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = interval Datum.date(datetimeValue.plusYears(intervalValue)) @@ -55,7 +55,7 @@ internal val Fn_DATE_ADD_YEAR__INT_DATE__DATE = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].date + val datetime = args[1].localDate val datetimeValue = datetime val intervalValue = try { interval.toLong() @@ -76,10 +76,10 @@ internal val Fn_DATE_ADD_YEAR__INT32_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].int - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval.toLong() - Datum.timestamp(datetimeValue.plusYears(intervalValue)) + Datum.timestamp(datetimeValue.plusYears(intervalValue), 6) } internal val Fn_DATE_ADD_YEAR__INT64_TIMESTAMP__TIMESTAMP = Function.static( @@ -93,10 +93,10 @@ internal val Fn_DATE_ADD_YEAR__INT64_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].long - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = interval - Datum.timestamp(datetimeValue.plusYears(intervalValue)) + Datum.timestamp(datetimeValue.plusYears(intervalValue), 6) } internal val Fn_DATE_ADD_YEAR__INT_TIMESTAMP__TIMESTAMP = Function.static( @@ -110,12 +110,12 @@ internal val Fn_DATE_ADD_YEAR__INT_TIMESTAMP__TIMESTAMP = Function.static( ) { args -> val interval = args[0].bigInteger - val datetime = args[1].timestamp + val datetime = args[1].localDateTime val datetimeValue = datetime val intervalValue = try { interval.toLong() } catch (e: DataException) { throw TypeCheckException() } - Datum.timestamp(datetimeValue.plusYears(intervalValue)) + Datum.timestamp(datetimeValue.plusYears(intervalValue), 6) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt index dfe6db4cbc..2ef7fe5f2b 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt @@ -8,33 +8,30 @@ import org.partiql.spi.function.Parameter import org.partiql.spi.value.Datum import org.partiql.types.PType import org.partiql.value.datetime.TimeZone +import java.math.BigDecimal // // Extract Year // internal val Fn_EXTRACT_YEAR__DATE__INT32 = Function.static( - name = "extract_year", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.date()), ), - ) { args -> - val v = args[0].date + val v = args[0].localDate Datum.integer(v.year) } internal val Fn_EXTRACT_YEAR__TIMESTAMP__INT32 = Function.static( - name = "extract_year", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.timestamp(6)), ), - ) { args -> - val v = args[0].timestamp + val v = args[0].localDateTime Datum.integer(v.year) } @@ -42,29 +39,25 @@ internal val Fn_EXTRACT_YEAR__TIMESTAMP__INT32 = Function.static( // Extract Month // internal val Fn_EXTRACT_MONTH__DATE__INT32 = Function.static( - name = "extract_month", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.date()), ), - ) { args -> - val v = args[0].date - Datum.integer(v.month) + val v = args[0].localDate + Datum.integer(v.monthValue) } internal val Fn_EXTRACT_MONTH__TIMESTAMP__INT32 = Function.static( - name = "extract_month", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.timestamp(6)), ), - ) { args -> - val v = args[0].timestamp - Datum.integer(v.month) + val v = args[0].localDateTime + Datum.integer(v.monthValue) } // @@ -72,57 +65,52 @@ internal val Fn_EXTRACT_MONTH__TIMESTAMP__INT32 = Function.static( // internal val Fn_EXTRACT_DAY__DATE__INT32 = Function.static( - name = "extract_day", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.date()), ), -) { args -> - val v = args[0].date - Datum.integer(v.day) + ) { args -> + val v = args[0].localDate + Datum.integer(v.dayOfMonth) } internal val Fn_EXTRACT_DAY__TIMESTAMP__INT32 = Function.static( - name = "extract_day", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.timestamp(6)), ), - ) { args -> - val v = args[0].timestamp - Datum.integer(v.day) + val v = args[0].localDateTime + Datum.integer(v.dayOfMonth) } // // Extract Hour // internal val Fn_EXTRACT_HOUR__TIME__INT32 = Function.static( - name = "extract_hour", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.time(6)), ), -) { args -> - val v = args[0].time + ) { args -> + val v = args[0].localTime Datum.integer(v.hour) } internal val Fn_EXTRACT_HOUR__TIMESTAMP__INT32 = Function.static( - name = "extract_hour", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.timestamp(6)), ), -) { args -> - val v = args[0].timestamp + ) { args -> + val v = args[0].localDateTime Datum.integer(v.hour) } @@ -130,130 +118,113 @@ internal val Fn_EXTRACT_HOUR__TIMESTAMP__INT32 = Function.static( // Extract Minute // internal val Fn_EXTRACT_MINUTE__TIME__INT32 = Function.static( - name = "extract_minute", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.time(6)), ), -) { args -> - val v = args[0].time + ) { args -> + val v = args[0].localTime Datum.integer(v.minute) } internal val Fn_EXTRACT_MINUTE__TIMESTAMP__INT32 = Function.static( - name = "extract_minute", returns = PType.integer(), parameters = arrayOf( Parameter("datetime", PType.timestamp(6)), ), - ) { args -> - val v = args[0].timestamp + val v = args[0].localDateTime Datum.integer(v.minute) } // -// Extract Second +// Extract Second. +// +// Rules: +// - The declared type of the result is exact numeric with implementation-defined precision and scale. +// - The implementation-defined scale shall not be less than the fractional seconds precision of the source. +// +// Seconds is limited to [0-59].000_000_000 so DECIMAL(11,9) for now. +// +// We could return the exact precision/scale of the input type, but kiss/scope. // internal val Fn_EXTRACT_SECOND__TIME__DECIMAL_ARBITRARY = Function.static( - name = "extract_second", - returns = PType.decimal(38, 19), // TODO: Rewrite using new function modeling. + returns = PType.decimal(11, 9), // TODO: Rewrite using new function modeling. parameters = arrayOf( - Parameter("datetime", PType.time(6)), + Parameter("datetime", PType.time(9)), ), - ) { args -> - val v = args[0].time - Datum.decimal(v.decimalSecond) + val v = args[0].localTime + val d = BigDecimal(v.second).add(BigDecimal(v.nano).scaleByPowerOfTen(-9)) + Datum.decimal(d, 11, 9) } internal val Fn_EXTRACT_SECOND__TIMESTAMP__DECIMAL_ARBITRARY = Function.static( - name = "extract_second", - returns = PType.decimal(38, 19), // TODO: Rewrite using new function modeling. + returns = PType.decimal(11, 9), // TODO: Rewrite using new function modeling. parameters = arrayOf( Parameter("datetime", PType.timestamp(6)), ), - ) { args -> - val v = args[0].timestamp - Datum.decimal(v.decimalSecond) + val v = args[0].localDateTime + val d = BigDecimal(v.second).add(BigDecimal(v.nano).scaleByPowerOfTen(-9)) + Datum.decimal(d, 11, 9) } // // Extract Timezone Hour // internal val Fn_EXTRACT_TIMEZONE_HOUR__TIME__INT32 = Function.static( - name = "extract_timezone_hour", returns = PType.integer(), parameters = arrayOf( - Parameter("datetime", PType.time(6)), + Parameter("datetime", PType.timez(6)), ), - ) { args -> - val v = args[0].time - when (val tz = v.timeZone) { - TimeZone.UnknownTimeZone -> Datum.integer(0) // TODO: Should this be NULL? - is TimeZone.UtcOffset -> Datum.integer(tz.tzHour) - null -> Datum.nullValue(PType.integer()) - } + val v = args[0].offsetTime + val o = v.offset.totalSeconds / 3600 + Datum.integer(o) } internal val Fn_EXTRACT_TIMEZONE_HOUR__TIMESTAMP__INT32 = Function.static( - name = "extract_timezone_hour", returns = PType.integer(), parameters = arrayOf( - Parameter("datetime", PType.timestamp(6)), + Parameter("datetime", PType.timestampz(6)), ), - ) { args -> - val v = args[0].timestamp - when (val tz = v.timeZone) { - TimeZone.UnknownTimeZone -> Datum.integer(0) // TODO: Should this be NULL? - is TimeZone.UtcOffset -> Datum.integer(tz.tzHour) - null -> Datum.nullValue(PType.integer()) - } + val v = args[0].offsetDateTime + val o = v.offset.totalSeconds / 3600 + Datum.integer(o) } // // Extract Timezone Minute // internal val Fn_EXTRACT_TIMEZONE_MINUTE__TIME__INT32 = Function.static( - name = "extract_timezone_minute", returns = PType.integer(), parameters = arrayOf( - Parameter("datetime", PType.time(6)), + Parameter("datetime", PType.timez(6)), ), - ) { args -> - val v = args[0].time - when (val tz = v.timeZone) { - TimeZone.UnknownTimeZone -> Datum.integer(0) // TODO: Should this be NULL? - is TimeZone.UtcOffset -> Datum.integer(tz.tzMinute) - null -> Datum.nullValue(PType.integer()) - } + val v = args[0].offsetTime + val o = (v.offset.totalSeconds / 60) % 60 + Datum.integer(o) } internal val Fn_EXTRACT_TIMEZONE_MINUTE__TIMESTAMP__INT32 = Function.static( - name = "extract_timezone_minute", returns = PType.integer(), parameters = arrayOf( - Parameter("datetime", PType.timestamp(6)), + Parameter("datetime", PType.timestampz(6)), ), - ) { args -> - val v = args[0].timestamp - when (val tz = v.timeZone) { - TimeZone.UnknownTimeZone -> Datum.integer(0) // TODO: Should this be NULL? - is TimeZone.UtcOffset -> Datum.integer(tz.tzMinute) - null -> Datum.nullValue(PType.integer()) - } + val v = args[0].offsetDateTime + val o = (v.offset.totalSeconds / 60) % 60 + Datum.integer(o) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGt.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGt.kt index c0077be009..42d8e04c95 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGt.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGt.kt @@ -85,24 +85,24 @@ internal object FnGt : DiadicComparisonOperator("gt") { override fun getTimestampInstance(timestampLhs: PType, timestampRhs: PType): Function.Instance { return basic(PType.bool(), timestampLhs, timestampRhs) { args -> - val lhs = args[0].timestamp - val rhs = args[1].timestamp + val lhs = args[0].localDateTime + val rhs = args[1].localDateTime Datum.bool(lhs > rhs) } } override fun getDateInstance(dateLhs: PType, dateRhs: PType): Function.Instance { return basic(PType.bool(), PType.date()) { args -> - val lhs = args[0].date - val rhs = args[1].date + val lhs = args[0].localDate + val rhs = args[1].localDate Datum.bool(lhs > rhs) } } override fun getTimeInstance(timeLhs: PType, timeRhs: PType): Function.Instance { return basic(PType.bool(), timeLhs, timeRhs) { args -> - val lhs = args[0].time - val rhs = args[1].time + val lhs = args[0].localTime + val rhs = args[1].localTime Datum.bool(lhs > rhs) } } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGte.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGte.kt index 9a581b5c2b..17a93d619b 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGte.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnGte.kt @@ -109,24 +109,24 @@ internal object FnGte : DiadicComparisonOperator("gte") { override fun getTimestampInstance(timestampLhs: PType, timestampRhs: PType): Function.Instance { return basic(PType.bool(), timestampLhs, timestampRhs) { args -> - val lhs = args[0].timestamp - val rhs = args[1].timestamp + val lhs = args[0].localDateTime + val rhs = args[1].localDateTime Datum.bool(lhs >= rhs) } } override fun getDateInstance(dateLhs: PType, dateRhs: PType): Function.Instance { return basic(PType.bool(), PType.date()) { args -> - val lhs = args[0].date - val rhs = args[1].date + val lhs = args[0].localDate + val rhs = args[1].localDate Datum.bool(lhs >= rhs) } } override fun getTimeInstance(timeLhs: PType, timeRhs: PType): Function.Instance { return basic(PType.bool(), timeLhs, timeRhs) { args -> - val lhs = args[0].time - val rhs = args[1].time + val lhs = args[0].localTime + val rhs = args[1].localTime Datum.bool(lhs >= rhs) } } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLt.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLt.kt index 8e526a2beb..092752eea4 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLt.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLt.kt @@ -85,24 +85,24 @@ internal object FnLt : DiadicComparisonOperator("lt") { override fun getTimestampInstance(timestampLhs: PType, timestampRhs: PType): Function.Instance { return basic(PType.bool(), timestampLhs, timestampRhs) { args -> - val lhs = args[0].timestamp - val rhs = args[1].timestamp + val lhs = args[0].localDateTime + val rhs = args[1].localDateTime Datum.bool(lhs < rhs) } } override fun getDateInstance(dateLhs: PType, dateRhs: PType): Function.Instance { return basic(PType.bool(), PType.date()) { args -> - val lhs = args[0].date - val rhs = args[1].date + val lhs = args[0].localDate + val rhs = args[1].localDate Datum.bool(lhs < rhs) } } override fun getTimeInstance(timeLhs: PType, timeRhs: PType): Function.Instance { return basic(PType.bool(), timeLhs, timeRhs) { args -> - val lhs = args[0].time - val rhs = args[1].time + val lhs = args[0].localTime + val rhs = args[1].localTime Datum.bool(lhs < rhs) } } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLte.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLte.kt index 35d6cba0e1..c096c5c966 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLte.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnLte.kt @@ -85,24 +85,24 @@ internal object FnLte : DiadicComparisonOperator("lte") { override fun getTimestampInstance(timestampLhs: PType, timestampRhs: PType): Function.Instance { return basic(PType.bool(), timestampLhs, timestampRhs) { args -> - val lhs = args[0].timestamp - val rhs = args[1].timestamp + val lhs = args[0].localDateTime + val rhs = args[1].localDateTime Datum.bool(lhs <= rhs) } } override fun getDateInstance(dateLhs: PType, dateRhs: PType): Function.Instance { return basic(PType.bool(), PType.date()) { args -> - val lhs = args[0].date - val rhs = args[1].date + val lhs = args[0].localDate + val rhs = args[1].localDate Datum.bool(lhs <= rhs) } } override fun getTimeInstance(timeLhs: PType, timeRhs: PType): Function.Instance { return basic(PType.bool(), timeLhs, timeRhs) { args -> - val lhs = args[0].time - val rhs = args[1].time + val lhs = args[0].localTime + val rhs = args[1].localTime Datum.bool(lhs <= rhs) } } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt index 9887245107..a009a254da 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt @@ -6,13 +6,13 @@ package org.partiql.spi.function.builtins import org.partiql.spi.function.Function import org.partiql.spi.value.Datum import org.partiql.types.PType -import org.partiql.value.datetime.TimestampWithTimeZone +import java.time.LocalDateTime internal val Fn_UTCNOW____TIMESTAMP = Function.static( name = "utcnow", returns = PType.timestamp(6), parameters = arrayOf(), ) { - val now = TimestampWithTimeZone.nowZ() - Datum.timestamp(now) + val now = LocalDateTime.now() + Datum.timestamp(now, 6) } From 2ad49e5d67f9d85901e26b94eab844f83d578910 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 24 Dec 2024 12:20:24 -0800 Subject: [PATCH 04/12] Fix partiql-spi build --- .../spi/function/builtins/FnExtract.kt | 13 ++---- .../org/partiql/spi/value/ion/IonVariant.kt | 8 +--- .../partiql/eval/value/DatumComparatorTest.kt | 43 ++++++++----------- 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt index 2ef7fe5f2b..689b67f656 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnExtract.kt @@ -7,7 +7,6 @@ import org.partiql.spi.function.Function import org.partiql.spi.function.Parameter import org.partiql.spi.value.Datum import org.partiql.types.PType -import org.partiql.value.datetime.TimeZone import java.math.BigDecimal // @@ -70,8 +69,7 @@ internal val Fn_EXTRACT_DAY__DATE__INT32 = Function.static( parameters = arrayOf( Parameter("datetime", PType.date()), ), - - ) { args -> +) { args -> val v = args[0].localDate Datum.integer(v.dayOfMonth) } @@ -96,8 +94,7 @@ internal val Fn_EXTRACT_HOUR__TIME__INT32 = Function.static( parameters = arrayOf( Parameter("datetime", PType.time(6)), ), - - ) { args -> +) { args -> val v = args[0].localTime Datum.integer(v.hour) } @@ -108,8 +105,7 @@ internal val Fn_EXTRACT_HOUR__TIMESTAMP__INT32 = Function.static( parameters = arrayOf( Parameter("datetime", PType.timestamp(6)), ), - - ) { args -> +) { args -> val v = args[0].localDateTime Datum.integer(v.hour) } @@ -123,8 +119,7 @@ internal val Fn_EXTRACT_MINUTE__TIME__INT32 = Function.static( parameters = arrayOf( Parameter("datetime", PType.time(6)), ), - - ) { args -> +) { args -> val v = args[0].localTime Datum.integer(v.minute) } diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt index f000c089cf..bdddc268a1 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonVariant.kt @@ -6,7 +6,6 @@ import com.amazon.ion.system.IonTextWriterBuilder import com.amazon.ionelement.api.AnyElement import java.math.BigDecimal import java.math.BigInteger - import com.amazon.ionelement.api.ElementType import com.amazon.ionelement.api.ElementType.BLOB import com.amazon.ionelement.api.ElementType.BOOL @@ -141,7 +140,7 @@ internal class IonVariant(private var value: AnyElement) : Datum { } @Deprecated("Deprecated in Java") - override fun getBytes(): ByteArray = when (value.type) { + override fun getBytes(): ByteArray = when (value.type) { CLOB -> value.clobValue.copyOfBytes() BLOB -> value.blobValue.copyOfBytes() else -> super.getBytes() @@ -216,10 +215,7 @@ internal class IonVariant(private var value: AnyElement) : Datum { if (value.type != STRUCT) { return super.getFields() } - return value.structFields - .map { Field.of(it.name, IonVariant(it.value)) } - .toMutableList() - .iterator() + return value.structFields.map { Field.of(it.name, IonVariant(it.value)) }.toMutableList().iterator() } override fun get(name: String): Datum { diff --git a/partiql-spi/src/test/kotlin/org/partiql/eval/value/DatumComparatorTest.kt b/partiql-spi/src/test/kotlin/org/partiql/eval/value/DatumComparatorTest.kt index 9b19422c34..021f82fa21 100644 --- a/partiql-spi/src/test/kotlin/org/partiql/eval/value/DatumComparatorTest.kt +++ b/partiql-spi/src/test/kotlin/org/partiql/eval/value/DatumComparatorTest.kt @@ -3,11 +3,13 @@ package org.partiql.spi.value import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.partiql.types.PType -import org.partiql.value.datetime.DateTimeValue.date -import org.partiql.value.datetime.DateTimeValue.time -import org.partiql.value.datetime.DateTimeValue.timestamp -import org.partiql.value.datetime.TimeZone import java.math.BigDecimal +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.OffsetTime +import java.time.ZoneOffset import java.util.Base64 import java.util.Random @@ -165,39 +167,30 @@ class DatumComparatorTest { Datum.doublePrecision(Double.POSITIVE_INFINITY), ), EquivValues( - Datum.date(date(year = 1992, month = 8, day = 22)) + Datum.date(LocalDate.of(1992, 8, 22)) ), EquivValues( - Datum.date(date(year = 2021, month = 8, day = 22)) + Datum.date(LocalDate.of(2021, 8, 22)) ), - // Set a [timeZone] for every [TimeValue] and [TimestampValue] since comparison between time types without - // a timezone results in an error. TODO: add a way to compare between time and timestamp types EquivValues( - Datum.time(time(hour = 12, minute = 12, second = 12, timeZone = TimeZone.UnknownTimeZone)), - Datum.time(time(hour = 12, minute = 12, second = 12, nano = 0, timeZone = TimeZone.UnknownTimeZone)), - Datum.time(time(hour = 12, minute = 12, second = 12, timeZone = TimeZone.UnknownTimeZone)), - // time second precision handled by time constructor - Datum.time(time(hour = 12, minute = 12, second = 12, timeZone = TimeZone.UtcOffset.of(0))), + Datum.timez(OffsetTime.of(12, 12, 12, 0, ZoneOffset.UTC), 9), + Datum.timez(OffsetTime.of(12, 12, 12, 0, ZoneOffset.ofHours(0)), 9), ), EquivValues( - Datum.time(time(hour = 12, minute = 12, second = 12, nano = 100000000, timeZone = TimeZone.UnknownTimeZone)), + Datum.time(LocalTime.of(12, 12, 12, 100000000), 9), ), EquivValues( - Datum.time(time(hour = 12, minute = 12, second = 12, nano = 0, timeZone = TimeZone.UtcOffset.of(-8, 0))), - Datum.time(time(hour = 12, minute = 12, second = 12, timeZone = TimeZone.UtcOffset.of(-8, 0))), + Datum.timez(OffsetTime.of(12, 12, 12, 100000000, ZoneOffset.ofHours(-9)), 9), ), EquivValues( - Datum.time(time(hour = 12, minute = 12, second = 12, nano = 100000000, timeZone = TimeZone.UtcOffset.of(-9, 0))), + Datum.timestamp(LocalDateTime.of(2017, 1, 1, 0, 0, 0), 6), ), EquivValues( - Datum.timestamp(timestamp(year = 2017, timeZone = TimeZone.UtcOffset.of(0, 0))), // `2017T` - Datum.timestamp(timestamp(year = 2017, month = 1, timeZone = TimeZone.UtcOffset.of(0, 0))), // `2017-01T` - Datum.timestamp(timestamp(year = 2017, month = 1, day = 1, timeZone = TimeZone.UtcOffset.of(0, 0))), // `2017-01-01T` - Datum.timestamp(timestamp(year = 2017, month = 1, day = 1, hour = 0, minute = 0, second = 0, timeZone = TimeZone.UtcOffset.of(0, 0))), // `2017-01-01T00:00-00:00` - Datum.timestamp(timestamp(year = 2017, month = 1, day = 1, hour = 1, minute = 0, second = 0, timeZone = TimeZone.UtcOffset.of(1, 0))) // `2017-01-01T01:00+01:00` - ), - EquivValues( - Datum.timestamp(timestamp(year = 2017, month = 1, day = 1, hour = 1, minute = 0, second = 0, timeZone = TimeZone.UtcOffset.of(0, 0))) // `2017-01-01T01:00Z` + Datum.timestampz(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.ofHours(0)), 6), // `2017-01-01T00:00+00` + Datum.timestampz(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.ofHoursMinutes(0, 0)), 6), // `2017-01-01T00:00+00:00` + // equality with different offsets not defined in partiql + // Datum.timestampz(OffsetDateTime.of(2017, 1, 1, 1, 0, 0, 0, ZoneOffset.ofHours(1)), 6), // `2017-01-01T01:00+01` + // Datum.timestampz(OffsetDateTime.of(2017, 1, 1, 1, 0, 0, 0, ZoneOffset.ofHoursMinutes(-1, 0)), 6), // `2017-01-01T01:00+01:00` ), EquivValues( Datum.string(""), From ee42115642406caef883648e2f948793b56c8045 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 24 Dec 2024 13:11:51 -0800 Subject: [PATCH 05/12] Updates CAST and connversions --- .../eval/internal/operator/rex/CastTable.kt | 76 +++++------- .../java/org/partiql/spi/value/Datum.java | 5 - .../partiql/spi/value/ion/IonDatumReader.kt | 2 +- .../org/partiql/value/datetime/DateTime.kt | 2 +- .../datetime/DateTimePrecisionChanger.kt | 1 + .../partiql/value/datetime/DateTimeUtil.kt | 52 --------- .../partiql/value/datetime/DateTimeValue.kt | 4 +- .../org/partiql/value/datetime/TimeZone.kt | 6 +- .../datetime/impl/LocalTimeHighPrecision.kt | 4 +- .../datetime/impl/LocalTimeLowPrecision.kt | 2 +- .../datetime/impl/OffsetTimeHighPrecision.kt | 8 +- .../datetime/impl/OffsetTimeLowPrecision.kt | 2 +- .../impl/OffsetTimestampHighPrecision.kt | 8 +- .../impl/OffsetTimestampLowPrecision.kt | 3 +- .../org/partiql/spi/value/ValueUtils.java | 29 ++--- .../org/partiql/value/impl/Int16ValueImpl.kt | 2 +- .../org/partiql/value/impl/Int32ValueImpl.kt | 2 +- .../org/partiql/value/impl/Int64ValueImpl.kt | 2 +- .../org/partiql/value/impl/Int8ValueImpl.kt | 2 +- .../org/partiql/value/util/DateTimeUtil.kt | 108 ++++++++++++++++++ .../PartiQLParserDateTimeRandomizedTests.kt | 18 --- .../org/partiql/runner/io/DatumIonReader.kt | 59 +++++++--- 22 files changed, 220 insertions(+), 177 deletions(-) delete mode 100644 partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeUtil.kt create mode 100644 partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt index 8f994fa1c7..b11071eb28 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt @@ -30,10 +30,12 @@ import org.partiql.types.PType.TIMEZ import org.partiql.types.PType.TINYINT import org.partiql.types.PType.VARCHAR import org.partiql.types.PType.VARIANT -import org.partiql.value.datetime.DateTimeValue import java.math.BigDecimal import java.math.BigInteger import java.math.RoundingMode +import java.time.LocalDate +import java.time.LocalTime +import java.time.ZoneOffset /** * Represent the cast operation. This casts an input [Datum] to the target [PType] (returning a potentially new [Datum]). @@ -103,9 +105,9 @@ internal object CastTable { registerString() registerBag() registerList() - registerTimestamp() registerDate() registerTime() + registerTimestamp() registerVariant() } @@ -442,57 +444,39 @@ internal object CastTable { register(ARRAY, ARRAY) { x, _ -> x } } - /** - * TODO: Flush this out. - */ - private fun registerTimestamp() { - // WITHOUT TZ - register(TIMESTAMP, VARCHAR) { x, t -> Datum.varchar(x.timestamp.toString(), t.length) } - register(TIMESTAMP, CHAR) { x, t -> Datum.character(x.timestamp.toString(), t.length) } - register(TIMESTAMP, CLOB) { x, t -> Datum.clob(x.timestamp.toString().toByteArray(), t.length) } - register(TIMESTAMP, STRING) { x, _ -> Datum.string(x.timestamp.toString()) } - register(TIMESTAMP, TIMESTAMP) { x, _ -> Datum.timestamp(x.timestamp) } - register(TIMESTAMP, TIMESTAMPZ) { x, _ -> Datum.timestamp(x.timestamp) } - register(TIMESTAMP, TIME) { x, _ -> Datum.time(x.timestamp.toTime()) } - register(TIMESTAMP, DATE) { x, _ -> Datum.date(x.timestamp.toDate()) } - // WITH TZ - register(TIMESTAMPZ, VARCHAR) { x, t -> Datum.varchar(x.timestamp.toString(), t.length) } - register(TIMESTAMPZ, CHAR) { x, t -> Datum.character(x.timestamp.toString(), t.length) } - register(TIMESTAMPZ, CLOB) { x, t -> Datum.clob(x.timestamp.toString().toByteArray(), t.length) } - register(TIMESTAMPZ, STRING) { x, _ -> Datum.string(x.timestamp.toString()) } - register(TIMESTAMPZ, TIMESTAMP) { x, _ -> Datum.timestamp(x.timestamp) } - register(TIMESTAMPZ, TIMESTAMPZ) { x, _ -> Datum.timestamp(x.timestamp) } - register(TIMESTAMPZ, TIME) { x, _ -> Datum.time(x.timestamp.toTime()) } - register(TIMESTAMPZ, DATE) { x, _ -> Datum.date(x.timestamp.toDate()) } - } private fun registerDate() { - register(DATE, VARCHAR) { x, t -> Datum.varchar(x.date.toString(), t.length) } - register(DATE, CHAR) { x, t -> Datum.character(x.date.toString(), t.length) } - register(DATE, CLOB) { x, t -> Datum.clob(x.date.toString().toByteArray(), t.length) } - register(DATE, STRING) { x, _ -> Datum.string(x.date.toString()) } - register(DATE, DATE) { x, _ -> Datum.date(x.date) } - register(DATE, TIMESTAMP) { x, _ -> Datum.timestamp(DateTimeValue.timestamp(x.date, DateTimeValue.time(0, 0, 0))) } - register(DATE, TIMESTAMPZ) { x, _ -> Datum.timestamp(DateTimeValue.timestamp(x.date, DateTimeValue.time(0, 0, 0))) } + register(DATE, STRING) { x, _ -> Datum.string(x.localDate.toString()) } + register(DATE, DATE) { x, _ -> Datum.date(x.localDate) } + register(DATE, TIMESTAMP) { x, _ -> Datum.timestamp(x.localDate.atTime(LocalTime.MIN), 0) } + register(DATE, TIMESTAMPZ) { x, _ -> Datum.timestampz(x.localDate.atTime(LocalTime.MIN).atOffset(ZoneOffset.UTC), 0) } } private fun registerTime() { // WITHOUT TZ - register(TIME, VARCHAR) { x, t -> Datum.varchar(x.time.toString(), t.length) } - register(TIME, CHAR) { x, t -> Datum.character(x.time.toString(), t.length) } - register(TIME, CLOB) { x, t -> Datum.clob(x.time.toString().toByteArray(), t.length) } - register(TIME, STRING) { x, _ -> Datum.string(x.time.toString()) } - register(TIME, TIME) { x, _ -> Datum.time(x.time) } - register(TIME, TIMESTAMP) { x, _ -> Datum.timestamp(DateTimeValue.timestamp(DateTimeValue.date(1970, 1, 1), x.time)) } - register(TIME, TIMESTAMPZ) { x, _ -> Datum.timestamp(DateTimeValue.timestamp(DateTimeValue.date(1970, 1, 1), x.time)) } + register(TIME, STRING) { x, _ -> Datum.string(x.localTime.toString()) } + register(TIME, TIME) { x, t -> Datum.time(x.localTime, t.precision) } + register(TIME, TIMESTAMP) { x, t -> Datum.timestamp(x.localTime.atDate(LocalDate.now()), t.precision) } + register(TIME, TIMESTAMPZ) { x, t -> Datum.timestampz(x.localTime.atDate(LocalDate.now()).atOffset(ZoneOffset.UTC), t.precision) } + // WITH TZ + register(TIMEZ, STRING) { x, _ -> Datum.string(x.offsetTime.toString()) } + register(TIMEZ, TIME) { x, t -> Datum.time(x.localTime, t.precision) } + register(TIMEZ, TIMESTAMP) { x, t -> Datum.timestamp(x.localTime.atDate(LocalDate.now()), t.precision) } + register(TIMEZ, TIMESTAMPZ) { x, t -> Datum.timestampz(x.offsetTime.atDate(LocalDate.now()), t.precision) } + } + private fun registerTimestamp() { + // WITHOUT TZ + register(TIMESTAMP, STRING) { x, _ -> Datum.string(x.localDateTime.toString()) } + register(TIMESTAMP, TIMESTAMP) { x, t -> Datum.timestamp(x.localDateTime, t.precision) } + register(TIMESTAMP, TIMESTAMPZ) { x, t -> Datum.timestampz(x.localDateTime.atOffset(ZoneOffset.UTC), t.precision) } + register(TIMESTAMP, TIME) { x, t -> Datum.time(x.localTime, t.precision) } + register(TIMESTAMP, DATE) { x, _ -> Datum.date(x.localDate) } // WITH TZ - register(TIMEZ, VARCHAR) { x, t -> Datum.varchar(x.time.toString(), t.length) } - register(TIMEZ, CHAR) { x, t -> Datum.character(x.time.toString(), t.length) } - register(TIMEZ, CLOB) { x, t -> Datum.clob(x.time.toString().toByteArray(), t.length) } - register(TIMEZ, STRING) { x, _ -> Datum.string(x.time.toString()) } - register(TIMEZ, TIME) { x, _ -> Datum.time(x.time) } - register(TIMEZ, TIMESTAMP) { x, _ -> Datum.timestamp(DateTimeValue.timestamp(DateTimeValue.date(1970, 1, 1), x.time)) } - register(TIMEZ, TIMESTAMPZ) { x, _ -> Datum.timestamp(DateTimeValue.timestamp(DateTimeValue.date(1970, 1, 1), x.time)) } + register(TIMESTAMPZ, STRING) { x, _ -> Datum.string(x.localDateTime.toString()) } + register(TIMESTAMPZ, TIMESTAMP) { x, t -> Datum.timestamp(x.localDateTime, t.precision) } + register(TIMESTAMPZ, TIMESTAMPZ) { x, t -> Datum.timestampz(x.offsetDateTime, t.precision) } + register(TIMESTAMPZ, TIME) { x, t -> Datum.time(x.localTime, t.precision) } + register(TIMESTAMPZ, DATE) { x, _ -> Datum.date(x.localDate) } } private fun registerVariant() { diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java b/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java index fe4aa5e38f..76470b361b 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/Datum.java @@ -8,11 +8,6 @@ import org.partiql.errors.DataException; import org.partiql.spi.value.ion.IonVariant; import org.partiql.types.PType; -import org.partiql.value.datetime.Date; -import org.partiql.value.datetime.Time; -import org.partiql.value.datetime.Timestamp; - -import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonDatumReader.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonDatumReader.kt index 085be8d3ec..2dcbe5aa43 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonDatumReader.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/value/ion/IonDatumReader.kt @@ -10,7 +10,7 @@ import org.partiql.spi.value.Datum import org.partiql.spi.value.DatumReader import org.partiql.spi.value.Encoding import org.partiql.spi.value.Field -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import java.io.IOException import java.io.InputStream diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTime.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTime.kt index 34a2859597..d868519d6c 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTime.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTime.kt @@ -15,7 +15,7 @@ package org.partiql.value.datetime -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.datetime.impl.OffsetTimestampLowPrecision import java.math.BigDecimal import kotlin.jvm.Throws diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimePrecisionChanger.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimePrecisionChanger.kt index 60717e4cc5..a593224c1b 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimePrecisionChanger.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimePrecisionChanger.kt @@ -15,6 +15,7 @@ package org.partiql.value.datetime +import org.partiql.spi.value.DateTimeUtil import org.partiql.value.datetime.DateTimeValue.time import org.partiql.value.datetime.DateTimeValue.timestamp import java.math.BigDecimal diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeUtil.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeUtil.kt deleted file mode 100644 index ef1e4b2996..0000000000 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeUtil.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at: - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - */ - -package org.partiql.value.datetime - -import java.math.BigDecimal -import java.util.regex.Pattern - -internal object DateTimeUtil { - internal val DATETIME_PATTERN = Pattern.compile( - "(?[-+]?\\d{4,})-(?\\d{1,2})-(?\\d{1,2})" + - "(?: (?\\d{1,2}):(?\\d{1,2})(?::(?\\d{1,2})(?:\\.(?\\d+))?)?)?" + - "\\s*(?[+-]\\d\\d:\\d\\d)?" - ) - - internal val DATE_PATTERN = Pattern.compile("(?\\d{4,})-(?\\d{2,})-(?\\d{2,})") - - internal val TIME_PATTERN = - Pattern.compile("(?\\d{2,}):(?\\d{2,}):(?\\d{2,})(?:\\.(?\\d+))?\\s*(?[+-]\\d\\d:\\d\\d)?") - - internal const val MILLIS_IN_SECOND: Long = 1000 - internal const val MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND - internal const val MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE - internal const val MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR - internal const val SECONDS_IN_MINUTE = 60L - internal const val SECONDS_IN_HOUR = 60 * SECONDS_IN_MINUTE - internal const val SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR - internal const val MAX_TIME_ZONE_HOURS: Int = 23 - internal const val MAX_TIME_ZONE_MINUTES: Int = 59 - internal const val MAX_TOTAL_OFFSET_MINUTES: Int = MAX_TIME_ZONE_HOURS * 60 + MAX_TIME_ZONE_MINUTES - internal const val NANOS_IN_SECOND: Long = 1_000_000_000L - internal const val JAVA_MAX_OFFSET: Int = 18 * 60 // java offset valid range -18:00 to 18:00 - - // In date time, we should only concern with BigDecimal, Int, and Long - internal fun Number.toBigDecimal(): BigDecimal = when (this) { - is BigDecimal -> this - is Long -> BigDecimal.valueOf(this) - is Int -> BigDecimal.valueOf(this.toLong()) - else -> throw IllegalArgumentException("can not convert $this to BigDecimal") - } -} diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeValue.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeValue.kt index 291f5f98d8..d0bc00934f 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeValue.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/DateTimeValue.kt @@ -15,8 +15,8 @@ package org.partiql.value.datetime -import org.partiql.value.datetime.DateTimeUtil.JAVA_MAX_OFFSET -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.JAVA_MAX_OFFSET +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.datetime.impl.LocalTimeHighPrecision import org.partiql.value.datetime.impl.LocalTimeLowPrecision import org.partiql.value.datetime.impl.LocalTimestampHighPrecision diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/TimeZone.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/TimeZone.kt index 04aa978e5c..8219a20d3d 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/TimeZone.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/TimeZone.kt @@ -14,9 +14,9 @@ package org.partiql.value.datetime -import org.partiql.value.datetime.DateTimeUtil.MAX_TIME_ZONE_HOURS -import org.partiql.value.datetime.DateTimeUtil.MAX_TIME_ZONE_MINUTES -import org.partiql.value.datetime.DateTimeUtil.MAX_TOTAL_OFFSET_MINUTES +import org.partiql.spi.value.DateTimeUtil.MAX_TIME_ZONE_HOURS +import org.partiql.spi.value.DateTimeUtil.MAX_TIME_ZONE_MINUTES +import org.partiql.spi.value.DateTimeUtil.MAX_TOTAL_OFFSET_MINUTES import kotlin.math.abs public sealed class TimeZone { diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeHighPrecision.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeHighPrecision.kt index 964e370796..2dc9dd7447 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeHighPrecision.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeHighPrecision.kt @@ -17,8 +17,8 @@ package org.partiql.value.datetime.impl import org.partiql.value.datetime.Date import org.partiql.value.datetime.DateTimeException -import org.partiql.value.datetime.DateTimeUtil -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.datetime.TimeWithoutTimeZone import org.partiql.value.datetime.TimeZone import java.math.BigDecimal diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeLowPrecision.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeLowPrecision.kt index cdda78e358..644f596acb 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeLowPrecision.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/LocalTimeLowPrecision.kt @@ -17,7 +17,7 @@ package org.partiql.value.datetime.impl import org.partiql.value.datetime.Date import org.partiql.value.datetime.DateTimeException -import org.partiql.value.datetime.DateTimeUtil +import org.partiql.spi.value.DateTimeUtil import org.partiql.value.datetime.TimeWithTimeZone import org.partiql.value.datetime.TimeWithoutTimeZone import org.partiql.value.datetime.TimeZone diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeHighPrecision.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeHighPrecision.kt index 040396a9e1..5be4627278 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeHighPrecision.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeHighPrecision.kt @@ -16,10 +16,10 @@ package org.partiql.value.datetime.impl import org.partiql.value.datetime.Date -import org.partiql.value.datetime.DateTimeUtil -import org.partiql.value.datetime.DateTimeUtil.SECONDS_IN_DAY -import org.partiql.value.datetime.DateTimeUtil.SECONDS_IN_HOUR -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil +import org.partiql.spi.value.DateTimeUtil.SECONDS_IN_DAY +import org.partiql.spi.value.DateTimeUtil.SECONDS_IN_HOUR +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.datetime.TimeWithTimeZone import org.partiql.value.datetime.TimeZone import java.math.BigDecimal diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeLowPrecision.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeLowPrecision.kt index 0591de31ed..4a95f7ea5f 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeLowPrecision.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimeLowPrecision.kt @@ -17,7 +17,7 @@ package org.partiql.value.datetime.impl import org.partiql.value.datetime.Date import org.partiql.value.datetime.DateTimeException -import org.partiql.value.datetime.DateTimeUtil +import org.partiql.spi.value.DateTimeUtil import org.partiql.value.datetime.TimeWithTimeZone import org.partiql.value.datetime.TimeZone import java.math.BigDecimal diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampHighPrecision.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampHighPrecision.kt index 138a63c2e9..811fb3ca21 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampHighPrecision.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampHighPrecision.kt @@ -16,10 +16,10 @@ package org.partiql.value.datetime.impl import org.partiql.value.datetime.Date -import org.partiql.value.datetime.DateTimeUtil.SECONDS_IN_DAY -import org.partiql.value.datetime.DateTimeUtil.SECONDS_IN_HOUR -import org.partiql.value.datetime.DateTimeUtil.SECONDS_IN_MINUTE -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.SECONDS_IN_DAY +import org.partiql.spi.value.DateTimeUtil.SECONDS_IN_HOUR +import org.partiql.spi.value.DateTimeUtil.SECONDS_IN_MINUTE +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.datetime.TimeWithTimeZone import org.partiql.value.datetime.TimeZone import org.partiql.value.datetime.TimestampWithTimeZone diff --git a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampLowPrecision.kt b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampLowPrecision.kt index f20971de89..de8505a0d3 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampLowPrecision.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/value/datetime/impl/OffsetTimestampLowPrecision.kt @@ -16,9 +16,8 @@ package org.partiql.value.datetime.impl import org.partiql.value.datetime.Date -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.datetime.TimeZone -import org.partiql.value.datetime.Timestamp import org.partiql.value.datetime.TimestampWithTimeZone import java.math.BigDecimal import java.math.RoundingMode diff --git a/partiql-spi/src/testFixtures/java/org/partiql/spi/value/ValueUtils.java b/partiql-spi/src/testFixtures/java/org/partiql/spi/value/ValueUtils.java index 32d40b7b39..491ac5181a 100644 --- a/partiql-spi/src/testFixtures/java/org/partiql/spi/value/ValueUtils.java +++ b/partiql-spi/src/testFixtures/java/org/partiql/spi/value/ValueUtils.java @@ -7,6 +7,8 @@ import org.partiql.value.PartiQL; import org.partiql.value.PartiQLValue; import org.partiql.value.PartiQLValueType; +import org.partiql.value.util.DateTimeUtil; + import java.math.BigDecimal; import java.util.Objects; import static org.partiql.types.PType.ARRAY; @@ -78,13 +80,15 @@ public static PartiQLValue newPartiQLValue(@NotNull Datum datum) { case CLOB: return datum.isNull() ? PartiQL.clobValue(null) : PartiQL.clobValue(datum.getBytes()); case DATE: - return datum.isNull() ? PartiQL.dateValue(null) : PartiQL.dateValue(datum.getDate()); + return datum.isNull() ? PartiQL.dateValue(null) : PartiQL.dateValue(DateTimeUtil.toDate(datum.getLocalDate())); + case TIME: + return datum.isNull() ? PartiQL.timeValue(null) : PartiQL.timeValue(DateTimeUtil.toTime(datum.getLocalTime())); case TIMEZ: - case TIME: // TODO - return datum.isNull() ? PartiQL.timeValue(null) : PartiQL.timeValue(datum.getTime()); - case TIMESTAMPZ: + return datum.isNull() ? PartiQL.timeValue(null) : PartiQL.timeValue(DateTimeUtil.toTime(datum.getOffsetTime())); case TIMESTAMP: - return datum.isNull() ? PartiQL.timestampValue(null) : PartiQL.timestampValue(datum.getTimestamp()); + return datum.isNull() ? PartiQL.timestampValue(null) : PartiQL.timestampValue(DateTimeUtil.toTimestamp(datum.getLocalDateTime())); + case TIMESTAMPZ: + return datum.isNull() ? PartiQL.timestampValue(null) : PartiQL.timestampValue(DateTimeUtil.toTimestamp(datum.getOffsetDateTime())); case BAG: return datum.isNull() ? PartiQL.bagValue((Iterable) null) : PartiQL.bagValue(new PQLToPartiQLIterable(datum)); case ARRAY: @@ -158,16 +162,15 @@ public static Datum newDatum(PartiQLValue value) { throw new UnsupportedOperationException(); case DATE: org.partiql.value.DateValue DATEValue = (org.partiql.value.DateValue) value; - return new DatumDate(Objects.requireNonNull(DATEValue.getValue())); - case INTERVAL: - org.partiql.value.IntervalValue INTERVALValue = (org.partiql.value.IntervalValue) value; - return new DatumInterval(Objects.requireNonNull(INTERVALValue.getValue())); - case TIMESTAMP: - org.partiql.value.TimestampValue TIMESTAMPValue = (org.partiql.value.TimestampValue) value; - return new DatumTimestamp(Objects.requireNonNull(TIMESTAMPValue.getValue())); + return DateTimeUtil.toDatumDate(Objects.requireNonNull(DATEValue.getValue())); case TIME: org.partiql.value.TimeValue TIMEValue = (org.partiql.value.TimeValue) value; - return new DatumTime(Objects.requireNonNull(TIMEValue.getValue())); + return DateTimeUtil.toDatumTime(Objects.requireNonNull(TIMEValue.getValue())); + case TIMESTAMP: + org.partiql.value.TimestampValue TIMESTAMPValue = (org.partiql.value.TimestampValue) value; + return DateTimeUtil.toDatumTimestamp(Objects.requireNonNull(TIMESTAMPValue.getValue())); + case INTERVAL: + throw new UnsupportedOperationException("interval not supported"); case FLOAT32: org.partiql.value.Float32Value FLOAT32Value = (org.partiql.value.Float32Value) value; return new DatumFloat(Objects.requireNonNull(FLOAT32Value.getValue())); diff --git a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int16ValueImpl.kt b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int16ValueImpl.kt index 73abcb979f..6e1a446fb8 100644 --- a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int16ValueImpl.kt +++ b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int16ValueImpl.kt @@ -26,7 +26,7 @@ import org.partiql.value.Int32Value import org.partiql.value.Int64Value import org.partiql.value.Int8Value import org.partiql.value.IntValue -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.decimalValue import org.partiql.value.float32Value import org.partiql.value.float64Value diff --git a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int32ValueImpl.kt b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int32ValueImpl.kt index f917dfabfa..001461397e 100644 --- a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int32ValueImpl.kt +++ b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int32ValueImpl.kt @@ -26,7 +26,7 @@ import org.partiql.value.Int32Value import org.partiql.value.Int64Value import org.partiql.value.Int8Value import org.partiql.value.IntValue -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.decimalValue import org.partiql.value.float32Value import org.partiql.value.float64Value diff --git a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int64ValueImpl.kt b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int64ValueImpl.kt index a0a33615ae..bd600e0306 100644 --- a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int64ValueImpl.kt +++ b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int64ValueImpl.kt @@ -26,7 +26,7 @@ import org.partiql.value.Int32Value import org.partiql.value.Int64Value import org.partiql.value.Int8Value import org.partiql.value.IntValue -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.decimalValue import org.partiql.value.float32Value import org.partiql.value.float64Value diff --git a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int8ValueImpl.kt b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int8ValueImpl.kt index 533f247236..c249505b8a 100644 --- a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int8ValueImpl.kt +++ b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/impl/Int8ValueImpl.kt @@ -25,7 +25,7 @@ import org.partiql.value.Int32Value import org.partiql.value.Int64Value import org.partiql.value.Int8Value import org.partiql.value.IntValue -import org.partiql.value.datetime.DateTimeUtil.toBigDecimal +import org.partiql.spi.value.DateTimeUtil.toBigDecimal import org.partiql.value.decimalValue import org.partiql.value.float32Value import org.partiql.value.float64Value diff --git a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt new file mode 100644 index 0000000000..3c58dfa950 --- /dev/null +++ b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt @@ -0,0 +1,108 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.value.util + +import org.partiql.spi.value.Datum +import org.partiql.value.datetime.Date +import org.partiql.value.datetime.Time +import org.partiql.value.datetime.TimeZone +import org.partiql.value.datetime.Timestamp +import org.partiql.value.datetime.impl.LocalTimeLowPrecision +import org.partiql.value.datetime.impl.LocalTimeLowPrecision.Companion.forNano +import org.partiql.value.datetime.impl.LocalTimestampLowPrecision.Companion.forDateTime +import org.partiql.value.datetime.impl.OffsetTimeLowPrecision +import org.partiql.value.datetime.impl.OffsetTimeLowPrecision.Companion.of +import org.partiql.value.datetime.impl.OffsetTimestampLowPrecision.Companion.forDateTime +import org.partiql.value.datetime.impl.SqlDate +import java.math.BigDecimal +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.OffsetTime + +internal object DateTimeUtil { + + internal const val MILLIS_IN_SECOND: Long = 1000 + internal const val MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND + internal const val MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE + internal const val MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR + internal const val SECONDS_IN_MINUTE = 60L + internal const val SECONDS_IN_HOUR = 60 * SECONDS_IN_MINUTE + internal const val SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR + internal const val MAX_TIME_ZONE_HOURS: Int = 23 + internal const val MAX_TIME_ZONE_MINUTES: Int = 59 + internal const val MAX_TOTAL_OFFSET_MINUTES: Int = MAX_TIME_ZONE_HOURS * 60 + MAX_TIME_ZONE_MINUTES + internal const val NANOS_IN_SECOND: Long = 1_000_000_000L + internal const val JAVA_MAX_OFFSET: Int = 18 * 60 // java offset valid range -18:00 to 18:00 + + // In date time, we should only concern with BigDecimal, Int, and Long + internal fun Number.toBigDecimal(): BigDecimal = when (this) { + is BigDecimal -> this + is Long -> BigDecimal.valueOf(this) + is Int -> BigDecimal.valueOf(this.toLong()) + else -> throw IllegalArgumentException("can not convert $this to BigDecimal") + } + + @JvmStatic + fun toDate(date: LocalDate): Date { + return SqlDate.of(date.year, date.monthValue, date.dayOfMonth) + } + + @JvmStatic + fun toTime(time: LocalTime): Time { + return forNano(time.hour, time.minute, time.second, time.nano) + } + + @JvmStatic + fun toTime(time: OffsetTime): Time { + val offset = time.offset.totalSeconds + val zone: TimeZone = TimeZone.UtcOffset.of(offset / 60, offset % 60) + return of(time.hour, time.minute, time.second, time.nano, zone) + } + + @JvmStatic + fun toTimestamp(timestamp: LocalDateTime): Timestamp { + val date = toDate(timestamp.toLocalDate()) + val time = toTime(timestamp.toLocalTime()) + return forDateTime( + (date as SqlDate), (time as LocalTimeLowPrecision) + ) + } + + @JvmStatic + fun toTimestamp(timestamp: OffsetDateTime): Timestamp { + val date = toDate(timestamp.toLocalDate()) + val time = toTime(timestamp.toOffsetTime()) + return forDateTime( + date, (time as OffsetTimeLowPrecision) + ) + } + + @JvmStatic + fun toDatumDate(date: Date): Datum { + return Datum.date(LocalDate.of(date.year, date.month, date.day)) + } + + @JvmStatic + fun toDatumTime(time: Time): Datum { + TODO("see if we can avoid this..") + } + + @JvmStatic + fun toDatumTimestamp(timestamp: Timestamp): Datum { + TODO("see if we can avoid this..") + } +} diff --git a/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt b/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt index 5405942461..24e1d32b19 100644 --- a/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt +++ b/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt @@ -15,11 +15,6 @@ package org.partiql.lang.randomized.syntax -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.partiql.lang.randomized.eval.assertExpression -import org.partiql.spi.value.Datum -import org.partiql.value.datetime.DateTimeValue import java.util.Random class PartiQLParserDateTimeRandomizedTests { @@ -51,17 +46,4 @@ class PartiQLParserDateTimeRandomizedTests { } + 1 return Date(year, month, day) } - - @Test - @Disabled("The planner does not return the v1 plans right now. See assertExpression.") // TODO - fun testRandomDates() { - randomDates.map { date -> - val yearStr = date.year.toString().padStart(4, '0') - val monthStr = date.month.toString().padStart(2, '0') - val dayStr = date.day.toString().padStart(2, '0') - assertExpression("DATE '$yearStr-$monthStr-$dayStr'") { - Datum.date(DateTimeValue.date(date.year, date.month, date.day)) - } - } - } } diff --git a/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/io/DatumIonReader.kt b/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/io/DatumIonReader.kt index 67fa93c5b6..fd5f62806f 100644 --- a/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/io/DatumIonReader.kt +++ b/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/io/DatumIonReader.kt @@ -8,12 +8,16 @@ import com.amazon.ionelement.api.IonElement import org.partiql.spi.value.Datum import org.partiql.spi.value.Field import org.partiql.types.PType -import org.partiql.value.datetime.DateTimeValue -import org.partiql.value.datetime.TimeZone import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.IOException import java.io.InputStream +import java.math.BigDecimal +import java.time.LocalDate +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.OffsetTime +import java.time.ZoneOffset /** * Make an arbitrary call on partiql value read @@ -22,7 +26,6 @@ import java.io.InputStream * For example: * In `IonForPartiQL` mode: if the input is $time::$day::$time{...} * The reader will attempt to create a time value - * */ class DatumIonReader( private val ionReader: IonReader, @@ -106,8 +109,19 @@ class DatumIonReader( Datum.decimal(d, d.precision(), d.scale()) } IonType.TIMESTAMP -> { - val ts = DateTimeValue.timestamp(reader.timestampValue()) - Datum.timestamp(ts) + val ts = reader.timestampValue() + val tz = when (ts.localOffset) { + null -> ZoneOffset.UTC + else -> ZoneOffset.ofHoursMinutes(ts.zHour, ts.zMinute) + } + // [0-59].000_000_000 + val ds = ts.decimalSecond + val second: Int = ds.toInt() + val nanoOfSecond: Int = ds.remainder(BigDecimal.ONE).movePointRight(9).toInt() + // date/time pair + val date = LocalDate.of(ts.year, ts.month, ts.day) + val time = LocalTime.of(ts.hour, ts.minute, second, nanoOfSecond) + return Datum.timestampz(OffsetDateTime.of(date, time, tz), 9) } IonType.STRING, IonType.SYMBOL -> Datum.string(reader.stringValue()) IonType.CLOB -> Datum.clob(reader.newBytes()) @@ -225,11 +239,10 @@ class DatumIonReader( throw IllegalArgumentException("excess field in struct") } reader.stepOut() - Datum.date(DateTimeValue.date(year.int, month.int, day.int)) + Datum.date(LocalDate.of(year.int, month.int, day.int)) } PARTIQL_ANNOTATION.TIME_ANNOTATION -> { reader.stepIn() - val map = mutableMapOf() val hour = getRequiredFieldName(reader, "hour") val minute = getRequiredFieldName(reader, "minute") val second = getRequiredFieldName(reader, "second") @@ -240,11 +253,15 @@ class DatumIonReader( } reader.stepOut() val offsetTz = when { - offset == null -> null - offset.isNull -> TimeZone.UnknownTimeZone - else -> TimeZone.UtcOffset.of(offset.int) + offset == null || offset.isNull -> ZoneOffset.UTC + else -> ZoneOffset.ofHoursMinutes(offset.int / 60, offset.int % 60) } - Datum.time(DateTimeValue.time(hour.int, minute.int, second.bigDecimal, offsetTz)) + // calculate second/nanos + val ds = second.bigDecimal + val seconds: Int = ds.toInt() + val nanoOfSecond: Int = ds.remainder(BigDecimal.ONE).movePointRight(9).toInt() + + Datum.timez(OffsetTime.of(hour.int, minute.int, seconds, nanoOfSecond, offsetTz), 9) } PARTIQL_ANNOTATION.TIMESTAMP_ANNOTATION -> { reader.stepIn() @@ -255,18 +272,24 @@ class DatumIonReader( val hour = getRequiredFieldName(reader, "hour") val minute = getRequiredFieldName(reader, "minute") val second = getRequiredFieldName(reader, "second") + val offset: Datum? = getOptionalFieldName(reader, "offset") // check remaining if (reader.next() != null) { throw IllegalArgumentException("excess field in struct") } reader.stepOut() - Datum.timestamp( - DateTimeValue.timestamp( - year.int, month.int, day.int, - hour.int, minute.int, second.bigDecimal, - null - ) - ) + val offsetTz = when { + offset == null || offset.isNull -> ZoneOffset.UTC + else -> ZoneOffset.ofHoursMinutes(offset.int / 60, offset.int % 60) + } + // calculate second/nanos + val ds = second.bigDecimal + val seconds: Int = ds.toInt() + val nanoOfSecond: Int = ds.remainder(BigDecimal.ONE).movePointRight(9).toInt() + // date/time + val date = LocalDate.of(year.int, month.int, day.int) + val time = LocalTime.of(hour.int, minute.int, seconds, nanoOfSecond) + Datum.timestampz(OffsetDateTime.of(date, time, offsetTz), 9) } null -> fromIonGeneric(reader) else -> error("Unsupported annotation.") From 4606824d4e574a8ef1b623c196bec68381ba4e97 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 24 Dec 2024 13:36:11 -0800 Subject: [PATCH 06/12] Adds old datetime to datum conversions --- .../org/partiql/value/util/DateTimeUtil.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt index 3c58dfa950..b52123b71c 100644 --- a/partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt +++ b/partiql-spi/src/testFixtures/kotlin/org/partiql/value/util/DateTimeUtil.kt @@ -19,6 +19,7 @@ import org.partiql.value.datetime.Date import org.partiql.value.datetime.Time import org.partiql.value.datetime.TimeZone import org.partiql.value.datetime.Timestamp +import org.partiql.types.PType import org.partiql.value.datetime.impl.LocalTimeLowPrecision import org.partiql.value.datetime.impl.LocalTimeLowPrecision.Companion.forNano import org.partiql.value.datetime.impl.LocalTimestampLowPrecision.Companion.forDateTime @@ -32,6 +33,7 @@ import java.time.LocalDateTime import java.time.LocalTime import java.time.OffsetDateTime import java.time.OffsetTime +import java.time.ZoneOffset internal object DateTimeUtil { @@ -98,11 +100,29 @@ internal object DateTimeUtil { @JvmStatic fun toDatumTime(time: Time): Datum { - TODO("see if we can avoid this..") + // [0-59].000_000_000 + val ds = time.decimalSecond + val second: Int = ds.toInt() + val nanoOfSecond: Int = ds.remainder(BigDecimal.ONE).movePointRight(9).toInt() + // local + val local = LocalTime.of(time.hour, time.minute, second, nanoOfSecond) + // check offset + if (time.timeZone != null && time.timeZone is TimeZone.UtcOffset) { + val zone = time.timeZone as TimeZone.UtcOffset + val offset = ZoneOffset.ofHoursMinutes(zone.tzHour, zone.tzMinute) + return Datum.timez(local.atOffset(offset), 9) + } + return Datum.time(local, 9) } @JvmStatic fun toDatumTimestamp(timestamp: Timestamp): Datum { - TODO("see if we can avoid this..") + val date = toDatumDate(timestamp.toDate()).localDate + val time = toDatumTime(timestamp.toTime()) + return when (time.type.code()) { + PType.TIME -> Datum.timestamp(LocalDateTime.of(date, time.localTime), 9) + PType.TIMEZ -> Datum.timestampz(OffsetDateTime.of(date, time.localTime, time.offsetTime.offset), 9) + else -> throw IllegalArgumentException("unsupported timestamp type") + } } } From 5ad6d8b5bb8f9a3705ef5c0099200bf4c361eea8 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 24 Dec 2024 13:40:55 -0800 Subject: [PATCH 07/12] Adds missing CASTS for time/timez --- .../kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt index b11071eb28..b7709866b5 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/CastTable.kt @@ -455,11 +455,13 @@ internal object CastTable { // WITHOUT TZ register(TIME, STRING) { x, _ -> Datum.string(x.localTime.toString()) } register(TIME, TIME) { x, t -> Datum.time(x.localTime, t.precision) } + register(TIME, TIMEZ) { x, t -> Datum.timez(x.localTime.atOffset(ZoneOffset.UTC), t.precision) } register(TIME, TIMESTAMP) { x, t -> Datum.timestamp(x.localTime.atDate(LocalDate.now()), t.precision) } register(TIME, TIMESTAMPZ) { x, t -> Datum.timestampz(x.localTime.atDate(LocalDate.now()).atOffset(ZoneOffset.UTC), t.precision) } // WITH TZ register(TIMEZ, STRING) { x, _ -> Datum.string(x.offsetTime.toString()) } register(TIMEZ, TIME) { x, t -> Datum.time(x.localTime, t.precision) } + register(TIMEZ, TIMEZ) { x, t -> Datum.timez(x.offsetTime, t.precision) } register(TIMEZ, TIMESTAMP) { x, t -> Datum.timestamp(x.localTime.atDate(LocalDate.now()), t.precision) } register(TIMEZ, TIMESTAMPZ) { x, t -> Datum.timestampz(x.offsetTime.atDate(LocalDate.now()), t.precision) } } From d51a78f244a234de60587716c761022ffd7071e7 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Mon, 6 Jan 2025 10:55:18 -0800 Subject: [PATCH 08/12] Address PR feedback --- .../main/java/org/partiql/spi/value/DatumNull.java | 6 +++++- .../java/org/partiql/spi/value/DatumTimestamp.java | 7 ++++++- .../java/org/partiql/spi/value/DatumTimestampz.java | 6 +++++- .../org/partiql/spi/function/builtins/FnUtcnow.kt | 9 +++++---- .../syntax/PartiQLParserDateTimeRandomizedTests.kt | 13 +++++++++++++ 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java index c34e82d7f1..bc4d5fa794 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumNull.java @@ -5,7 +5,11 @@ import java.math.BigDecimal; import java.math.BigInteger; -import java.time.*; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; import java.util.Iterator; /** diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java index 0a1fe584e5..dcb1de412a 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestamp.java @@ -4,7 +4,12 @@ import org.jetbrains.annotations.NotNull; import org.partiql.types.PType; -import java.time.*; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; /** * Today we wrap a {@link LocalDateTime}, in the future we do a 7-byte array to avoid double references. diff --git a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java index 7a8a760b14..0169814e9d 100644 --- a/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java +++ b/partiql-spi/src/main/java/org/partiql/spi/value/DatumTimestampz.java @@ -4,7 +4,11 @@ import org.jetbrains.annotations.NotNull; import org.partiql.types.PType; -import java.time.*; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; /** * Today we wrap an {@link OffsetDateTime}, in the future we do an 8-byte array to avoid double references. diff --git a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt index a009a254da..a18a9d5755 100644 --- a/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt +++ b/partiql-spi/src/main/kotlin/org/partiql/spi/function/builtins/FnUtcnow.kt @@ -6,13 +6,14 @@ package org.partiql.spi.function.builtins import org.partiql.spi.function.Function import org.partiql.spi.value.Datum import org.partiql.types.PType -import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneOffset internal val Fn_UTCNOW____TIMESTAMP = Function.static( name = "utcnow", - returns = PType.timestamp(6), + returns = PType.timestampz(6), parameters = arrayOf(), ) { - val now = LocalDateTime.now() - Datum.timestamp(now, 6) + val now = OffsetDateTime.now(ZoneOffset.UTC) + Datum.timestampz(now, 6) } diff --git a/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt b/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt index 24e1d32b19..4217aa150a 100644 --- a/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt +++ b/test/partiql-randomized-tests/src/test/kotlin/org/partiql/lang/randomized/syntax/PartiQLParserDateTimeRandomizedTests.kt @@ -15,6 +15,7 @@ package org.partiql.lang.randomized.syntax +import org.junit.jupiter.api.Test import java.util.Random class PartiQLParserDateTimeRandomizedTests { @@ -46,4 +47,16 @@ class PartiQLParserDateTimeRandomizedTests { } + 1 return Date(year, month, day) } + + @Test + fun testRandomDates() { + // randomDates.map { date -> val y = date.year.toString().padStart(4, '0') + // val m = date.month.toString().padStart(2, '0') + // val d = date.day.toString().padStart(2, '0') + // assertExpression() + // assertExpression("DATE '$yearStr-$monthStr-$dayStr'") { + // Datum.date(DateTimeValue.date(date.year, date.month, date.day)) + // } + // } + } } From ecf8e28cfea861f45092365b17022f02c03242dc Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Mon, 6 Jan 2025 11:24:28 -0800 Subject: [PATCH 09/12] Removes PartiQLValue datetime --- .../planner/internal/utils/DateTimeUtils.kt | 76 ----- partiql-spi/api/partiql-spi.api | 266 ------------------ .../partiql/spi/value/ion/IonDatumReader.kt | 7 +- .../org/partiql/spi/value/ValueUtils.java | 2 +- .../org/partiql/value/datetime/DateTime.kt | 8 +- .../value/datetime/DateTimeComparator.kt | 0 .../value/datetime/DateTimeException.kt | 0 .../datetime/DateTimePrecisionChanger.kt | 1 - .../value/{util => datetime}/DateTimeUtil.kt | 6 +- .../partiql/value/datetime/DateTimeValue.kt | 3 +- .../org/partiql/value/datetime/TimeZone.kt | 6 +- .../datetime/impl/LocalTimeHighPrecision.kt | 10 +- .../datetime/impl/LocalTimeLowPrecision.kt | 5 +- .../impl/LocalTimestampHighPrecision.kt | 0 .../impl/LocalTimestampLowPrecision.kt | 3 +- .../datetime/impl/OffsetTimeHighPrecision.kt | 7 +- .../datetime/impl/OffsetTimeLowPrecision.kt | 5 +- .../impl/OffsetTimestampHighPrecision.kt | 8 +- .../impl/OffsetTimestampLowPrecision.kt | 18 +- .../partiql/value/datetime/impl/SqlDate.kt | 0 .../org/partiql/value/datetime/impl/Utils.kt | 0 .../org/partiql/value/impl/Int16ValueImpl.kt | 2 +- .../org/partiql/value/impl/Int32ValueImpl.kt | 1 - .../org/partiql/value/impl/Int64ValueImpl.kt | 1 - .../org/partiql/value/impl/Int8ValueImpl.kt | 2 +- 25 files changed, 51 insertions(+), 386 deletions(-) delete mode 100644 partiql-planner/src/main/kotlin/org/partiql/planner/internal/utils/DateTimeUtils.kt rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/DateTime.kt (99%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/DateTimeComparator.kt (100%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/DateTimeException.kt (100%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/DateTimePrecisionChanger.kt (99%) rename partiql-spi/src/testFixtures/kotlin/org/partiql/value/{util => datetime}/DateTimeUtil.kt (96%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/DateTimeValue.kt (98%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/TimeZone.kt (92%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/LocalTimeHighPrecision.kt (92%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/LocalTimeLowPrecision.kt (96%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/LocalTimestampHighPrecision.kt (100%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/LocalTimestampLowPrecision.kt (97%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/OffsetTimeHighPrecision.kt (95%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/OffsetTimeLowPrecision.kt (96%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/OffsetTimestampHighPrecision.kt (97%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/OffsetTimestampLowPrecision.kt (95%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/SqlDate.kt (100%) rename partiql-spi/src/{main => testFixtures}/kotlin/org/partiql/value/datetime/impl/Utils.kt (100%) diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/utils/DateTimeUtils.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/utils/DateTimeUtils.kt deleted file mode 100644 index 1cd4dabc05..0000000000 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/utils/DateTimeUtils.kt +++ /dev/null @@ -1,76 +0,0 @@ -package org.partiql.planner.internal.utils - -import org.partiql.value.datetime.Date -import org.partiql.value.datetime.DateTimeException -import org.partiql.value.datetime.DateTimeValue -import org.partiql.value.datetime.Time -import org.partiql.value.datetime.TimeZone -import org.partiql.value.datetime.Timestamp -import java.math.BigDecimal -import java.util.regex.Matcher -import java.util.regex.Pattern - -internal object DateTimeUtils { - private val DATE_PATTERN: Pattern = Pattern.compile("(?\\d{4,})-(?\\d{2,})-(?\\d{2,})") - private val TIME_PATTERN: Pattern = Pattern.compile("(?\\d{2,}):(?\\d{2,}):(?\\d{2,})(?:\\.(?\\d+))?\\s*(?([+-]\\d\\d:\\d\\d)|(?[Zz]))?") - private val SQL_TIMESTAMP_DATE_TIME_DELIMITER = "\\s+".toRegex() - private val RFC8889_TIMESTAMP_DATE_TIME_DELIMITER = "[Tt]".toRegex() - private val TIMESTAMP_PATTERN = "(?$DATE_PATTERN)($SQL_TIMESTAMP_DATE_TIME_DELIMITER|$RFC8889_TIMESTAMP_DATE_TIME_DELIMITER)(?