Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 3 additions & 17 deletions crates/polars-sql/src/sql_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,23 +403,9 @@ impl SQLExprVisitor<'_> {
uses_odbc_syntax: _,
}) => {
let dtype = self.resolve_typed_literal_dtype(data_type, v)?;
match dtype {
DataType::Date => Ok(lit(v.as_str()).cast(DataType::Date)),
DataType::Time => Ok(lit(v.as_str()).str().to_time(StrptimeOptions {
strict: true,
..Default::default()
})),
DataType::Datetime(_, _) => Ok(lit(v.as_str()).str().to_datetime(
None,
None,
StrptimeOptions {
strict: true,
..Default::default()
},
lit("latest"),
)),
_ => unreachable!(),
}
parse_string_as_temporal(lit(v.as_str()), &dtype, true).ok_or_else(
|| polars_err!(SQLInterface: "invalid temporal literal type {}", dtype),
)
},
SQLExpr::UnaryOp { op, expr } => self.visit_unary_op(op, expr),
SQLExpr::Value(ValueWithSpan { value, .. }) => self.visit_literal(value),
Expand Down
48 changes: 48 additions & 0 deletions py-polars/tests/unit/sql/test_temporal.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import polars as pl
from polars.exceptions import InvalidOperationError, SQLInterfaceError, SQLSyntaxError
from polars.testing import assert_frame_equal
from tests.unit.sql import assert_sql_matches


def test_date_func() -> None:
Expand Down Expand Up @@ -482,3 +483,50 @@ def test_timestamp_time_unit_errors() -> None:
match="sql parser error: Expected: literal int, found: - ",
):
ctx.execute("SELECT ts::timestamp(-3) FROM frame_data")


def test_typed_temporal_literal_comparison() -> None:
df = pl.DataFrame(
{
"d": [date(2019, 6, 1), date(2020, 1, 1), date(2021, 1, 1)],
"ts": [
datetime(2019, 6, 1, 12),
datetime(2020, 1, 1, 8),
datetime(2021, 1, 1, 0),
],
}
)
for query in (
"SELECT d FROM self WHERE d > DATE '2019-12-31' ORDER BY d",
"SELECT d FROM self WHERE d BETWEEN DATE '2019-01-01' AND DATE '2020-06-01' ORDER BY d",
"SELECT ts FROM self WHERE ts > TIMESTAMP '2019-12-31 00:00:00' ORDER BY ts",
):
assert_sql_matches(df, query=query, compare_with="duckdb")


@pytest.mark.parametrize(
("literal", "expected"),
[
("DATE '2020-02-29'", date(2020, 2, 29)),
("TIME '12:30:05'", time(12, 30, 5)),
("TIMESTAMP '2020-01-01 08:00:00'", datetime(2020, 1, 1, 8)),
],
)
def test_typed_temporal_literal(literal: str, expected: Any) -> None:
df = pl.DataFrame({"a": [1]})
with pl.SQLContext(frames={"tbl": df}, eager=True) as ctx:
assert ctx.execute(f"SELECT {literal} AS x FROM tbl").item() == expected


@pytest.mark.parametrize(
("precision", "time_unit"),
[(3, "ms"), (6, "us"), (9, "ns")],
)
def test_typed_timestamp_literal_precision(precision: int, time_unit: str) -> None:
# the declared precision selects the time unit
df = pl.DataFrame({"a": [1]})
with pl.SQLContext(frames={"tbl": df}, eager=True) as ctx:
res = ctx.execute(
f"SELECT TIMESTAMP({precision}) '2020-01-01 08:00:00.123' AS x FROM tbl"
)
assert res.schema["x"] == pl.Datetime(time_unit) # type: ignore[arg-type]
Loading