Skip to content

feat(snowflake)!: Transpilation support for TO_DECIMAL, TO_NUMBER,NUMERIC#7315

Open
fivetran-ashashankar wants to merge 3 commits intomainfrom
RD-1069319_TO_NUMBER_DECIMAL_NUMERIC
Open

feat(snowflake)!: Transpilation support for TO_DECIMAL, TO_NUMBER,NUMERIC#7315
fivetran-ashashankar wants to merge 3 commits intomainfrom
RD-1069319_TO_NUMBER_DECIMAL_NUMERIC

Conversation

@fivetran-ashashankar
Copy link
Collaborator

No description provided.

@fivetran-ashashankar fivetran-ashashankar changed the title feat(snowflake)!: Transpilation support for TO_DECIMAL, TO_NUMBER, TO… feat(snowflake)!: Transpilation support for TO_DECIMAL, TO_NUMBER,NUMERIC Mar 17, 2026
join_cols = [col for col in cond.find_all(exp.Column) if col.args.get("join_mark")]

left_join_table = set(col.table for col in join_cols)
if not left_join_table:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make style formatter modified the transforms.py

@@ -4181,6 +4181,84 @@ def strtok_sql(self, expression: exp.Strtok) -> str:

return self.function_fallback_sql(expression)

Copy link
Collaborator Author

@fivetran-ashashankar fivetran-ashashankar Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Snowflake: TO_NUMBER(expr) defaults to NUMBER(38, 0) -> truncates decimals -> BIGINT
Oracle/others: TO_NUMBER(expr) defaults to NUMBER -> keeps decimals -> DOUBLE
Working on handling this difference. should I use is_snowflake here.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

SQLGlot Integration Test Results

Comparing:

  • this branch (sqlglot:RD-1069319_TO_NUMBER_DECIMAL_NUMERIC, sqlglot version: RD-1069319_TO_NUMBER_DECIMAL_NUMERIC)
  • baseline (main, sqlglot version: 0.0.1.dev1)

By Dialect

dialect main sqlglot:RD-1069319_TO_NUMBER_DECIMAL_NUMERIC transitions links
bigquery -> bigquery 23872/23877 passed (100.0%) 21252/21252 passed (100.0%) No change full result / delta
bigquery -> duckdb 2106/2624 passed (80.3%) 0/0 passed (0.0%) No change full result / delta
duckdb -> duckdb 4003/4003 passed (100.0%) 4003/4003 passed (100.0%) No change full result / delta
snowflake -> duckdb 1508/2674 passed (56.4%) 1513/2674 passed (56.6%) 8 fail -> pass
3 pass -> fail
full result / delta
snowflake -> snowflake 65910/65910 passed (100.0%) 62861/65910 passed (95.4%) 3049 pass -> fail full result / delta
databricks -> databricks 1364/1364 passed (100.0%) 1364/1364 passed (100.0%) No change full result / delta
postgres -> postgres 6040/6040 passed (100.0%) 6040/6040 passed (100.0%) No change full result / delta
redshift -> redshift 7059/7059 passed (100.0%) 7059/7059 passed (100.0%) No change full result / delta

Overall

main: 113551 total, 111862 passed (pass rate: 98.5%), sqlglot version: 0.0.1.dev1

sqlglot:RD-1069319_TO_NUMBER_DECIMAL_NUMERIC: 108302 total, 104092 passed (pass rate: 96.1%), sqlglot version: RD-1069319_TO_NUMBER_DECIMAL_NUMERIC

Transitions:
8 fail -> pass
3052 pass -> fail

✅ 1 test(s) passed

@fivetran-ashashankar fivetran-ashashankar force-pushed the RD-1069319_TO_NUMBER_DECIMAL_NUMERIC branch from 3264deb to b285974 Compare March 24, 2026 19:24
Copy link
Collaborator

@geooo109 geooo109 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the rest of the commetns / cases like #7315 (comment) ? (update(edit: no need to resolve these comments for now))

Comment on lines +739 to +752
# Convert CAST to DECIMAL/NUMERIC to TO_NUMBER
if expression.is_type(exp.DType.DECIMAL):
# Extract precision and scale from DECIMAL(p, s)
params = expression.to.expressions or []
precision = params[0].this if len(params) >= 1 and isinstance(params[0], exp.DataTypeParam) else None
scale = params[1].this if len(params) >= 2 and isinstance(params[1], exp.DataTypeParam) else None

to_number = exp.ToNumber(
this=expression.this,
precision=precision,
scale=scale,
safe=isinstance(expression, exp.TryCast),
)
return self.tonumber_sql(to_number)
Copy link
Collaborator

@geooo109 geooo109 Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we added logic here ?

Comment on lines +310 to +324
def _build_to_number(args: t.List[exp.Expr]) -> exp.ToNumber:
"""Build TO_NUMBER with Snowflake default precision/scale of (38, 0)."""
expr, arg1, arg2, arg3 = (seq_get(args, i) for i in range(4))

# Determine if arg1 is format (string) or precision (number)
has_format = arg1 and arg1.is_string
format_arg, precision, scale = (arg1, arg2, arg3) if has_format else (None, arg1, arg2)

# Set Snowflake defaults when not specified
if precision is None and scale is None:
precision, scale = exp.Literal.number(38), exp.Literal.number(0)
elif precision and scale is None:
scale = exp.Literal.number(0)

return exp.ToNumber(this=expr, format=format_arg, precision=precision, scale=scale)
Copy link
Collaborator

@geooo109 geooo109 Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this function needed ?

we can do precision=seq_get(args, 2) or exp.Literal.number(...) right ? and use this logic directly in the parser dict. (like the previous implementation)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants