Skip to content

Commit

Permalink
Fixed RD-10923
Browse files Browse the repository at this point in the history
  • Loading branch information
bgaidioz committed May 29, 2024
1 parent ff0cf7b commit e46db25
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ trait MySQLPackageTest extends CompilerTestContext with CredentialsTestContext w
| CAST(3.14 AS DOUBLE) AS doublecol,
| CAST(1200000000 AS DECIMAL) AS decimalcol,
| '120' AS stringcol,
| CAST('12:23:34' AS TIME) AS timecol,
| CAST('12:23:34.123' AS TIME) AS timecol,
| CAST('2020-01-01' AS DATE) AS datecol,
| CAST('2020-01-01 12:23:34' AS DATETIME) AS timestampcol,
| CAST('2020-01-01 12:23:34.123' AS DATETIME) AS timestampcol,
| 1 = 0 AS boolcol,
| convert('Olala!' using utf8) AS binarycol$ttt, type collection(
| record(
Expand Down Expand Up @@ -65,9 +65,9 @@ trait MySQLPackageTest extends CompilerTestContext with CredentialsTestContext w
| doublecol: 3.14,
| decimalcol: Decimal.From(1200000000),
| stringcol: "120",
| timecol: Time.Build(12, 23, seconds=34),
| timecol: Time.Build(12, 23, seconds=34, milliseconds=123),
| datecol: Date.Build(2020, 1, 1),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34, milliseconds=123),
| boolcol: false,
| binarycol: Binary.FromString("Olala!")
|}]""".stripMargin)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ trait PostgreSQLPackageTest extends CompilerTestContext with CredentialsTestCont
| CAST('3.14' AS DOUBLE PRECISION) AS doublecol,
| CAST('12000000' AS DECIMAL) AS decimalcol,
| CAST('120' AS VARCHAR) AS stringcol,
| CAST('12:23:34' AS TIME) AS timecol,
| CAST('12:23:34.123' AS TIME) AS timecol,
| CAST('2020-01-01' AS DATE) AS datecol,
| CAST('2020-01-01 12:23:34' AS TIMESTAMP) AS timestampcol,
| CAST('2020-01-01 12:23:34.123' AS TIMESTAMP) AS timestampcol,
| CAST('false' AS BOOL) AS boolcol,
| decode('T2xhbGEh', 'base64') as binarycol$ttt, type collection(
| record(
Expand Down Expand Up @@ -65,9 +65,9 @@ trait PostgreSQLPackageTest extends CompilerTestContext with CredentialsTestCont
| doublecol: 3.14,
| decimalcol: Decimal.From(12000000),
| stringcol: "120",
| timecol: Time.Build(12, 23, seconds=34),
| timecol: Time.Build(12, 23, seconds=34, milliseconds=123),
| datecol: Date.Build(2020, 1, 1),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34, milliseconds=123),
| boolcol: false,
| binarycol: Binary.FromString("Olala!")
|}]""".stripMargin)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ trait SnowflakePackageTest extends CompilerTestContext with CredentialsTestConte
| CAST('3.14' AS FLOAT8) AS "doublecol",
| CAST('12000000' AS DECIMAL) AS "decimalcol",
| CAST('120' AS VARCHAR) AS "stringcol",
| CAST('12:23:34' AS TIME) AS "timecol",
| CAST('12:23:34.123' AS TIME) AS "timecol",
| CAST('2020-01-01' AS DATE) AS "datecol",
| CAST('2020-01-01 12:23:34' AS DATETIME) AS "timestampcol",
| CAST('2020-01-01 12:23:34.123' AS DATETIME) AS "timestampcol",
| 1 = 0 AS "boolcol",
| to_binary('tralala', 'utf-8') AS "binarycol" $ttt, type collection(
| record(
Expand Down Expand Up @@ -67,9 +67,9 @@ trait SnowflakePackageTest extends CompilerTestContext with CredentialsTestConte
| doublecol: 3.14,
| decimalcol: Decimal.From(12000000),
| stringcol: "120",
| timecol: Time.Build(12, 23, seconds=34),
| timecol: Time.Build(12, 23, seconds=34, milliseconds=123),
| datecol: Date.Build(2020, 1, 1),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34, milliseconds=123),
| boolcol: false,
| binarycol: String.Encode("tralala", "utf-8")
|}]""".stripMargin)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ trait SqlServerPackageTest extends CompilerTestContext with CredentialsTestConte
| CAST('3.14' AS DOUBLE PRECISION) AS doublecol,
| CAST('12000000' AS DECIMAL) AS decimalcol,
| CAST('120' AS VARCHAR) AS stringcol,
| CAST('12:23:34' AS TIME) AS timecol,
| CAST('12:23:34.123' AS TIME) AS timecol,
| CAST('2020-01-01' AS DATE) AS datecol,
| CAST('2020-01-01 12:23:34' AS DATETIME) AS timestampcol,
| CAST('2020-01-01 12:23:34.123' AS DATETIME) AS timestampcol,
| CAST('Olala!' AS VARBINARY(MAX)) AS binarycol $ttt)""".stripMargin) { it =>
it should typeAs("""collection(
| record(
Expand All @@ -64,9 +64,9 @@ trait SqlServerPackageTest extends CompilerTestContext with CredentialsTestConte
| doublecol: 3.14,
| decimalcol: Decimal.From(12000000),
| stringcol: "120",
| timecol: Time.Build(12, 23, seconds=34),
| timecol: Time.Build(12, 23, seconds=34, milliseconds=123),
| datecol: Date.Build(2020, 1, 1),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34),
| timestampcol: Timestamp.Build(2020, 1, 1, 12, 23, seconds=34, milliseconds=123),
| binarycol: Binary.FromString("Olala!")
|}]""".stripMargin)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import raw.client.api._
import raw.client.sql.antlr4._

import java.sql.{Connection, ResultSet, ResultSetMetaData}
import java.time.{LocalTime, ZoneId}
import java.util.{Calendar, TimeZone}
import scala.collection.mutable

/* This class is wrapping the PreparedStatement class from the JDBC API.
Expand Down Expand Up @@ -425,7 +427,7 @@ class NamedParametersPreparedStatement(conn: Connection, parsedTree: ParseProgra
case RawString(v) => setString(paramName, v)
case RawDecimal(v) => setBigDecimal(paramName, v)
case RawDate(v) => setDate(paramName, java.sql.Date.valueOf(v))
case RawTime(v) => setTime(paramName, java.sql.Time.valueOf(v))
case RawTime(v) => setTime(paramName, new java.sql.Time(v.toNanoOfDay / 1000000))
case RawTimestamp(v) => setTimestamp(paramName, java.sql.Timestamp.valueOf(v))
case RawInterval(years, months, weeks, days, hours, minutes, seconds, millis) => ???
case RawBinary(v) => setBytes(paramName, v)
Expand Down Expand Up @@ -546,6 +548,9 @@ class NamedParametersPreparedStatement(conn: Connection, parsedTree: ParseProgra
}
}

private val timezone = ZoneId.of("UTC")
private val zonedCalendar = Calendar.getInstance(TimeZone.getTimeZone(timezone))

private def getDefaultValue(rs: ResultSet, postgresType: PostgresType): DefaultValue = {
assert(rs.next(), "rs.next() was false")
val attempt = postgresType.jdbcType match {
Expand All @@ -556,8 +561,8 @@ class NamedParametersPreparedStatement(conn: Connection, parsedTree: ParseProgra
case java.sql.Types.FLOAT => RawFloat(rs.getFloat(1))
case java.sql.Types.DOUBLE => RawDouble(rs.getDouble(1))
case java.sql.Types.DATE => RawDate(rs.getDate(1).toLocalDate)
case java.sql.Types.TIME => RawTime(rs.getTime(1).toLocalTime)
case java.sql.Types.TIMESTAMP => RawTimestamp(rs.getTimestamp(1).toLocalDateTime)
case java.sql.Types.TIME => RawTime(LocalTime.ofNanoOfDay(rs.getTime(1, zonedCalendar).getTime * 1000000))
case java.sql.Types.TIMESTAMP => RawTimestamp(rs.getTimestamp(1, zonedCalendar).toLocalDateTime)
case java.sql.Types.BOOLEAN => RawBool(rs.getBoolean(1))
case java.sql.Types.VARCHAR => RawString(rs.getString(1))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ class SqlCompilerService(maybeClassLoader: Option[ClassLoader] = None)(implicit
syntaxAnalyzer.parse(prog)
}

private def treeErrors(tree: ParseProgramResult, messages: Seq[String]): Seq[ErrorMessage] = {
val start = tree.positions.getStart(tree).get
private def treeErrors(parsedTree: ParseProgramResult, messages: Seq[String]): Seq[ErrorMessage] = {
val start = parsedTree.positions.getStart(parsedTree.tree).get
val startPosition = ErrorPosition(start.line, start.column)
val end = tree.positions.getFinish(tree).get
val end = parsedTree.positions.getFinish(parsedTree.tree).get
val endPosition = ErrorPosition(end.line, end.column)
messages.map(message => ErrorMessage(message, List(ErrorRange(startPosition, endPosition)), ErrorCode.SqlErrorCode))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import raw.client.utils.RecordFieldsNaming

import java.io.{IOException, OutputStream}
import java.sql.ResultSet
import java.time.{LocalDateTime, LocalTime, ZoneId}
import java.time.format.DateTimeFormatter
import java.util.{Calendar, TimeZone}
import scala.annotation.tailrec

object TypedResultSetJsonWriter {
Expand Down Expand Up @@ -69,6 +71,9 @@ class TypedResultSetJsonWriter(os: OutputStream) {
gen.writeEndArray()
}

private val timezone = ZoneId.of("UTC")
private val zonedCalendar = Calendar.getInstance(TimeZone.getTimeZone(timezone))

@throws[IOException]
@tailrec
private def writeValue(v: ResultSet, i: Int, t: RawType): Unit = {
Expand Down Expand Up @@ -102,11 +107,11 @@ class TypedResultSetJsonWriter(os: OutputStream) {
val date = v.getDate(i).toLocalDate
gen.writeString(dateFormatter.format(date))
case _: RawTimeType =>
val time = v.getTime(i).toLocalTime
val time = LocalTime.ofNanoOfDay(v.getTime(i, zonedCalendar).getTime * 1000000)
val formatted = timeFormatter.format(time)
gen.writeString(formatted)
case _: RawTimestampType =>
val dateTime = v.getTimestamp(i).toLocalDateTime
val dateTime = LocalDateTime.ofInstant(v.getTimestamp(i, zonedCalendar).toInstant, timezone)
val formatted = timestampFormatter.format(dateTime)
gen.writeString(formatted)
case _: RawIntervalType =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -963,4 +963,123 @@ class TestSqlCompilerServiceAirports
assert(v.messages.exists(_.message contains "the input does not form a valid statement or expression"))
}

test("""SELECT pg_typeof(NOW())""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionFailure(errors2) = compilerService.getProgramDescription(t.q, asJson())
errors2.map(_.message).contains("unsupported type: regtype")
}

test("""SELECT CAST(pg_typeof(NOW()) AS VARCHAR)""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionSuccess(_) = compilerService.getProgramDescription(t.q, asJson())
val baos = new ByteArrayOutputStream()
baos.reset()
val noParam = ProgramEnvironment(
user,
None,
Set.empty,
Map("output-format" -> "json")
)
assert(compilerService.execute(t.q, noParam, None, baos) == ExecutionSuccess)
assert(baos.toString() == """[{"pg_typeof":"timestamp with time zone"}]""")

}

test("""SELECT NOW()""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionSuccess(description) = compilerService.getProgramDescription(t.q, asJson())
val baos = new ByteArrayOutputStream()
baos.reset()
val noParam = ProgramEnvironment(
user,
None,
Set.empty,
Map("output-format" -> "json")
)
assert(compilerService.execute(t.q, noParam, None, baos) == ExecutionSuccess)
}

test("""SELECT TIMESTAMP WITH TIME ZONE '2001-01-01 12:13:14.567 UTC' AS t""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionSuccess(description) = compilerService.getProgramDescription(t.q, asJson())
val baos = new ByteArrayOutputStream()
baos.reset()
val noParam = ProgramEnvironment(
user,
None,
Set.empty,
Map("output-format" -> "json")
)
assert(compilerService.execute(t.q, noParam, None, baos) == ExecutionSuccess)
assert(baos.toString() == """[{"t":"2001-01-01T12:13:14.567"}]""")
}

test("""SELECT TIMESTAMP WITHOUT TIME ZONE '2001-01-01 12:13:14.567' AS t""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionSuccess(description) = compilerService.getProgramDescription(t.q, asJson())
val baos = new ByteArrayOutputStream()
baos.reset()
val noParam = ProgramEnvironment(
user,
None,
Set.empty,
Map("output-format" -> "json")
)
assert(compilerService.execute(t.q, noParam, None, baos) == ExecutionSuccess)
assert(baos.toString() == """[{"t":"2001-01-01T12:13:14.567"}]""")
}

test("""SELECT TIME WITH TIME ZONE '12:13:14.567 UTC' AS t""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionSuccess(description) = compilerService.getProgramDescription(t.q, asJson())
val baos = new ByteArrayOutputStream()
baos.reset()
val noParam = ProgramEnvironment(
user,
None,
Set.empty,
Map("output-format" -> "json")
)
assert(compilerService.execute(t.q, noParam, None, baos) == ExecutionSuccess)
assert(baos.toString() == """[{"t":"12:13:14.567"}]""")
}

test("""SELECT TIME WITHOUT TIME ZONE '12:13:14.567' AS t""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionSuccess(description) = compilerService.getProgramDescription(t.q, asJson())
val baos = new ByteArrayOutputStream()
baos.reset()
val noParam = ProgramEnvironment(
user,
None,
Set.empty,
Map("output-format" -> "json")
)
assert(compilerService.execute(t.q, noParam, None, baos) == ExecutionSuccess)
assert(baos.toString() == """[{"t":"12:13:14.567"}]""")
}

test("""-- @default t TIME WITHOUT TIME ZONE '12:13:14.567'
|SELECT :t AS t""".stripMargin) { t =>
val ValidateResponse(errors) = compilerService.validate(t.q, asJson())
assert(errors.isEmpty)
val GetProgramDescriptionSuccess(description) = compilerService.getProgramDescription(t.q, asJson())
val baos = new ByteArrayOutputStream()
baos.reset()
val noParam = ProgramEnvironment(
user,
None,
Set.empty,
Map("output-format" -> "json")
)
assert(compilerService.execute(t.q, noParam, None, baos) == ExecutionSuccess)
assert(baos.toString() == """[{"t":"12:13:14.567"}]""")
}
}

0 comments on commit e46db25

Please sign in to comment.