diff --git a/sqlglot-integration-tests b/sqlglot-integration-tests index 520efdb573..9816f9b42d 160000 --- a/sqlglot-integration-tests +++ b/sqlglot-integration-tests @@ -1 +1 @@ -Subproject commit 520efdb573b6da4d4aa5ea372bb3d49af6a3ddc6 +Subproject commit 9816f9b42dd90d60243a55b3ceae2f7f6db2c79e diff --git a/sqlglot/expressions/functions.py b/sqlglot/expressions/functions.py index e0442205b7..2d33343466 100644 --- a/sqlglot/expressions/functions.py +++ b/sqlglot/expressions/functions.py @@ -70,7 +70,7 @@ def is_type(self, *dtypes: DATA_TYPE) -> bool: class TryCast(Cast): - arg_types = {**Cast.arg_types, "requires_string": False} + arg_types = {**Cast.arg_types, "requires_string": False, "dialect_cast": False} class JSONCast(Cast): diff --git a/sqlglot/generators/duckdb.py b/sqlglot/generators/duckdb.py index 49a4d486b5..4d51ecc216 100644 --- a/sqlglot/generators/duckdb.py +++ b/sqlglot/generators/duckdb.py @@ -4326,6 +4326,28 @@ def round_sql(self, expression: exp.Round) -> str: return self.func(func, this, decimals, truncate) + def trycast_sql(self, expression: exp.TryCast) -> str: + if not expression.args.get("dialect_cast"): + return super().trycast_sql(expression) + + src = expression.this + to = expression.to + to_type = to.this + + if to_type == exp.DType.BOOLEAN: + return _to_boolean_sql(self, exp.ToBoolean(this=src, safe=True)) + elif to_type in exp.DataType.TEXT_TYPES and to.expressions: + return self.sql( + exp.case() + .when( + exp.LTE(this=exp.func("LENGTH", src), expression=to.expressions[0].this), + exp.cast(src, "TEXT"), + ) + .else_(exp.Null()) + ) + + return super().trycast_sql(expression) + def strtok_sql(self, expression: exp.Strtok) -> str: string_arg = expression.this delimiter_arg = expression.args.get("delimiter") diff --git a/sqlglot/parser.py b/sqlglot/parser.py index 73e0520b56..262f2f698b 100644 --- a/sqlglot/parser.py +++ b/sqlglot/parser.py @@ -9928,6 +9928,10 @@ def build_cast(self, strict: bool, **kwargs) -> exp.Cast: if exp_class == exp.TryCast: kwargs["requires_string"] = self.dialect.TRY_CAST_REQUIRES_STRING + if self.dialect.TRY_CAST_REQUIRES_STRING and (to := kwargs.get("to")): + kwargs["dialect_cast"] = to.this == exp.DataType.Type.BOOLEAN or ( + to.this in exp.DataType.TEXT_TYPES and bool(to.expressions) + ) return self.expression(exp_class(**kwargs))