Repository: tobymao/sqlglot

Issue:
SQL Server Rowversion/Timestamp not parsed correctly
In MS SQL Server, there is a funny type called `rowversion` and has an alias `timestamp`. It has nothing in common with timestamp types in other databases. It's basically an `binary(8)` type which stores an incrementing number

https://learn.microsoft.com/en-us/sql/t-sql/data-types/rowversion-transact-sql?view=sql-server-ver16 

Sqlglot does not seem to recognize this type. It would be nice if sqlglot would transpile it correctly to binary types. 

```python

import sqlglot.expressions as ex
import sqlglot

print(  # transpiled type timestamp as is, should be binary
    sqlglot.parse_one("create table a (b timestamp)", dialect="tsql").sql("databricks")
)

print(  # prints ROWVERSION instead of BINARY
    sqlglot.parse_one("create table a (b rowversion)", dialect="tsql").sql("databricks")
)

print(  # good, this works! databricks timestamp is datetime2 in ms sql
    sqlglot.parse_one("create table a (b timestamp)", dialect="databricks").sql("tsql")
)


```

Discussion:

Patch:
diff --git a/README.md b/README.md
index 738fa1b1..34be0117 100644
--- a/README.md
+++ b/README.md
@@ -239,7 +239,7 @@ except sqlglot.errors.ParseError as e:
 
 ### Unsupported Errors
 
-It may not be possible to translate some queries between certain dialects. For these cases, SQLGlot emits a warning and proceeds to do a best-effort translation by default:
+It may not be possible to translate some queries between certain dialects. For these cases, SQLGlot may emit a warning and proceeds to do a best-effort translation by default. Transpilation is difficult and not all permutations are supported. If transpilation does not work, it may not be implemented yet. Well documented / tested PRs / issues are appreciated. Some transpilation cases that require db schemas are made possible through the optimizer but are not included in base transpilation:
 
 ```python
 import sqlglot
diff --git a/sqlglot/dialects/bigquery.py b/sqlglot/dialects/bigquery.py
index 87ac14bf..3d2fb3d9 100644
--- a/sqlglot/dialects/bigquery.py
+++ b/sqlglot/dialects/bigquery.py
@@ -689,6 +689,7 @@ class BigQuery(Dialect):
             exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
             exp.DataType.Type.TINYINT: "INT64",
             exp.DataType.Type.VARBINARY: "BYTES",
+            exp.DataType.Type.ROWVERSION: "BYTES",
             exp.DataType.Type.VARCHAR: "STRING",
             exp.DataType.Type.VARIANT: "ANY TYPE",
         }
diff --git a/sqlglot/dialects/duckdb.py b/sqlglot/dialects/duckdb.py
index 6486ddac..00ce1a0c 100644
--- a/sqlglot/dialects/duckdb.py
+++ b/sqlglot/dialects/duckdb.py
@@ -499,6 +499,7 @@ class DuckDB(Dialect):
             exp.DataType.Type.NVARCHAR: "TEXT",
             exp.DataType.Type.UINT: "UINTEGER",
             exp.DataType.Type.VARBINARY: "BLOB",
+            exp.DataType.Type.ROWVERSION: "BLOB",
             exp.DataType.Type.VARCHAR: "TEXT",
             exp.DataType.Type.TIMESTAMP_S: "TIMESTAMP_S",
             exp.DataType.Type.TIMESTAMP_MS: "TIMESTAMP_MS",
diff --git a/sqlglot/dialects/hive.py b/sqlglot/dialects/hive.py
index cc7debb6..d86691e4 100644
--- a/sqlglot/dialects/hive.py
+++ b/sqlglot/dialects/hive.py
@@ -457,6 +457,7 @@ class Hive(Dialect):
             exp.DataType.Type.TIME: "TIMESTAMP",
             exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
             exp.DataType.Type.VARBINARY: "BINARY",
+            exp.DataType.Type.ROWVERSION: "BINARY",
         }
 
         TRANSFORMS = {
diff --git a/sqlglot/dialects/oracle.py b/sqlglot/dialects/oracle.py
index e038400e..13f86ac7 100644
--- a/sqlglot/dialects/oracle.py
+++ b/sqlglot/dialects/oracle.py
@@ -222,6 +222,7 @@ class Oracle(Dialect):
             exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
             exp.DataType.Type.BINARY: "BLOB",
             exp.DataType.Type.VARBINARY: "BLOB",
+            exp.DataType.Type.ROWVERSION: "BLOB",
         }
 
         TRANSFORMS = {
diff --git a/sqlglot/dialects/postgres.py b/sqlglot/dialects/postgres.py
index 7cbcc233..71339b88 100644
--- a/sqlglot/dialects/postgres.py
+++ b/sqlglot/dialects/postgres.py
@@ -431,6 +431,7 @@ class Postgres(Dialect):
             exp.DataType.Type.DOUBLE: "DOUBLE PRECISION",
             exp.DataType.Type.BINARY: "BYTEA",
             exp.DataType.Type.VARBINARY: "BYTEA",
+            exp.DataType.Type.ROWVERSION: "BYTEA",
             exp.DataType.Type.DATETIME: "TIMESTAMP",
         }
 
diff --git a/sqlglot/dialects/redshift.py b/sqlglot/dialects/redshift.py
index e4ee1f1b..7b98ed45 100644
--- a/sqlglot/dialects/redshift.py
+++ b/sqlglot/dialects/redshift.py
@@ -146,6 +146,7 @@ class Redshift(Postgres):
             exp.DataType.Type.TIMETZ: "TIME",
             exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
             exp.DataType.Type.VARBINARY: "VARBYTE",
+            exp.DataType.Type.ROWVERSION: "VARBYTE",
         }
 
         TRANSFORMS = {
diff --git a/sqlglot/dialects/tsql.py b/sqlglot/dialects/tsql.py
index 4b7e6dbc..a699f2b3 100644
--- a/sqlglot/dialects/tsql.py
+++ b/sqlglot/dialects/tsql.py
@@ -464,6 +464,7 @@ class TSQL(Dialect):
             "SMALLMONEY": TokenType.SMALLMONEY,
             "SQL_VARIANT": TokenType.VARIANT,
             "TOP": TokenType.TOP,
+            "TIMESTAMP": TokenType.ROWVERSION,
             "UNIQUEIDENTIFIER": TokenType.UNIQUEIDENTIFIER,
             "UPDATE STATISTICS": TokenType.COMMAND,
             "XML": TokenType.XML,
@@ -755,6 +756,7 @@ class TSQL(Dialect):
             exp.DataType.Type.TIMESTAMP: "DATETIME2",
             exp.DataType.Type.TIMESTAMPTZ: "DATETIMEOFFSET",
             exp.DataType.Type.VARIANT: "SQL_VARIANT",
+            exp.DataType.Type.ROWVERSION: "ROWVERSION",
         }
 
         TYPE_MAPPING.pop(exp.DataType.Type.NCHAR)
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
index 77c8dac7..e5465029 100644
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -349,6 +349,7 @@ class Generator(metaclass=_Generator):
         exp.DataType.Type.LONGBLOB: "BLOB",
         exp.DataType.Type.TINYBLOB: "BLOB",
         exp.DataType.Type.INET: "INET",
+        exp.DataType.Type.ROWVERSION: "VARBINARY",
     }
 
     STAR_MAPPING = {


Test patch:
diff --git a/tests/dialects/test_tsql.py b/tests/dialects/test_tsql.py
index aefd8575..4a475f63 100644
--- a/tests/dialects/test_tsql.py
+++ b/tests/dialects/test_tsql.py
@@ -455,7 +455,6 @@ class TestTSQL(Validator):
         self.validate_identity("CAST(x AS UNIQUEIDENTIFIER)")
         self.validate_identity("CAST(x AS MONEY)")
         self.validate_identity("CAST(x AS SMALLMONEY)")
-        self.validate_identity("CAST(x AS ROWVERSION)")
         self.validate_identity("CAST(x AS IMAGE)")
         self.validate_identity("CAST(x AS SQL_VARIANT)")
         self.validate_identity("CAST(x AS BIT)")
@@ -475,6 +474,16 @@ class TestTSQL(Validator):
                 "hive": "CAST(x AS TIMESTAMP)",
             },
         )
+        self.validate_all(
+            "CAST(x AS ROWVERSION)",
+            read={
+                "tsql": "CAST(x AS TIMESTAMP)",
+            },
+            write={
+                "tsql": "CAST(x AS ROWVERSION)",
+                "hive": "CAST(x AS BINARY)",
+            },
+        )
 
     def test__types_ints(self):
         self.validate_all(