diff --git a/sqlglot/dialects/oracle.py b/sqlglot/dialects/oracle.py index f79496e2af..f2af012238 100644 --- a/sqlglot/dialects/oracle.py +++ b/sqlglot/dialects/oracle.py @@ -172,7 +172,14 @@ class Parser(parser.Parser): TYPE_LITERAL_PARSERS = { exp.DataType.Type.DATE: lambda self, this, _: self.expression( exp.DateStrToDate, this=this - ) + ), + exp.DataType.Type.TIMESTAMP: lambda self, this, _: self.expression( + exp.StrToTime, + this=this, + format=exp.Literal.string( + "%Y-%m-%d %H:%M:%S.%f" if "." in this.name else "%Y-%m-%d %H:%M:%S" + ), + ), } # SELECT UNIQUE .. is old-style Oracle syntax for SELECT DISTINCT .. @@ -275,6 +282,25 @@ def _parse_into(self) -> t.Optional[exp.Into]: def _parse_connect_with_prior(self): return self._parse_assignment() + def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]: + this = super()._parse_column_ops(this) + + if not this: + return this + + index = self._index + unit = self._parse_function() or self._parse_var(any_token=True, upper=True) + + if unit and self._match_text_seq("TO"): + to_unit = self._parse_function() or self._parse_var(any_token=True, upper=True) + + if to_unit: + unit = exp.IntervalSpan(this=unit, expression=to_unit) + return self.expression(exp.Interval, this=this, unit=unit) + + self._retreat(index) + return this + def _parse_insert_table(self) -> t.Optional[exp.Expression]: # Oracle does not use AS for INSERT INTO alias # https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/INSERT.html @@ -420,3 +446,6 @@ def hint_sql(self, expression: exp.Hint) -> str: def isascii_sql(self, expression: exp.IsAscii) -> str: return f"NVL(REGEXP_LIKE({self.sql(expression.this)}, '^[' || CHR(1) || '-' || CHR(127) || ']*$'), TRUE)" + + def interval_sql(self, expression: exp.Interval) -> str: + return f"{'INTERVAL ' if isinstance(expression.this, exp.Literal) else ''}{self.sql(expression, 'this')} {self.sql(expression, 'unit')}" diff --git a/tests/dialects/test_oracle.py b/tests/dialects/test_oracle.py index 038ca8e566..ce5620563e 100644 --- a/tests/dialects/test_oracle.py +++ b/tests/dialects/test_oracle.py @@ -53,6 +53,12 @@ def test_oracle(self): self.validate_identity("SELECT * FROM V$SESSION") self.validate_identity("SELECT TO_DATE('January 15, 1989, 11:00 A.M.')") self.validate_identity("SELECT INSTR(haystack, needle)") + self.validate_identity( + "SELECT (TIMESTAMP '2025-12-30 20:00:00' - TIMESTAMP '2025-12-29 14:30:00') DAY TO SECOND", + "SELECT (TO_TIMESTAMP('2025-12-30 20:00:00', 'YYYY-MM-DD HH24:MI:SS') - TO_TIMESTAMP('2025-12-29 14:30:00', 'YYYY-MM-DD HH24:MI:SS')) DAY TO SECOND", + ) + self.validate_identity("SELECT (SYSTIMESTAMP - order_date) DAY(9) TO SECOND FROM orders") + self.validate_identity("SELECT (SYSTIMESTAMP - order_date) DAY(9) TO SECOND(3) FROM orders") self.validate_identity( "SELECT * FROM consumer LEFT JOIN groceries ON consumer.groceries_id = consumer.id PIVOT(MAX(type_id) FOR consumer_type IN (1, 2, 3, 4))" )