Skip to content

fix(jinja): support negative exponents in ** operator#1433

Open
mani-dbt wants to merge 3 commits intomainfrom
fix/jinja-pow-negative-exponent
Open

fix(jinja): support negative exponents in ** operator#1433
mani-dbt wants to merge 3 commits intomainfrom
fix/jinja-pow-negative-exponent

Conversation

@mani-dbt
Copy link

@mani-dbt mani-dbt commented Mar 11, 2026

Fixes #1432

Summary

  • The ** (power) operator with negative integer exponents (e.g. 10 ** -9) was failing with dbt1501: Failed to render SQL invalid operation: unable to calculate 10 ** -9
  • Root cause: in value/ops.rs, the pow function's I128 branch attempted to convert the exponent to u32 for checked_pow, which fails for negative values
  • Fix: when the exponent is negative, promote to f64 arithmetic instead, matching Python/Jinja2 behavior (e.g. 10 ** -9 == 1e-9)
  • This unblocks dbt adapter macros that use conversion_factors dicts like {'nanosecond': 10**-9, 'microsecond': 10**-6, ...}

Test plan

  • New unit test test_pow_negative_exponent in value/ops.rs covering 10**-9, 10**-6, 10**-3
  • Guards that positive integer exponents still return integers and float exponents still work
  • Full minijinja test suite passes (250/250)
  • Validated end-to-end with dbt-sa-cli parse against a real dbt project using the affected macro

🤖 Generated with Claude Code

@mani-dbt mani-dbt requested a review from a team as a code owner March 11, 2026 22:57
@cla-bot
Copy link

cla-bot bot commented Mar 11, 2026

Thanks for your pull request, and welcome to our community! We require contributors to sign our Contributor License Agreement and we don't seem to have your signature on file. Check out this article for more information on why we have a CLA.

In order for us to review and merge your code, please submit the Individual Contributor License Agreement form attached above above. If you have questions about the CLA, or if you believe you've received this message in error, please reach out through a comment on this PR.

CLA has not been signed by users: @mani-dbt

@github-actions
Copy link

This repository enforces signed commits. Please sign your commits by following the docs here.

Negative integer exponents (e.g. 10 ** -9) were failing with
"unable to calculate 10 ** -9" because the I128 branch tried to
convert the exponent to u32 for checked_pow, which fails for
negative values.

Fix by promoting to f64 arithmetic when the exponent is negative,
matching Python/Jinja2 behavior. Adds unit tests covering the
exact conversion_factor values used in dbt adapter macros.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mani-dbt mani-dbt force-pushed the fix/jinja-pow-negative-exponent branch from 0e8ec95 to 46f37c0 Compare March 11, 2026 23:09
@cla-bot cla-bot bot added the cla:yes label Mar 11, 2026
if b < 0 {
// Negative exponents produce fractional results; promote to float
// to match Python/Jinja2 behavior (e.g. 10 ** -9 == 1e-9).
Ok((a as f64).powf(b as f64).into())
Copy link
Contributor

Choose a reason for hiding this comment

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

Use TryFrom to convert from a and b (128-bit integers) to f64 (64-bit floats) and Err(..) gracefully like in the else branch. Otherwise, the whole system crashes with a panic when a huge integer is passed.

Copy link
Author

Choose a reason for hiding this comment

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

@felipecrv - after some back and forth with Claude code, used the existing as_f64 to gracefully handle this scenario, and followed the same pattern as else branch. Please review. Revalidated end-to-end with dbt-sa-cli parse against my dbt project using the affected macro.

mani-dbt and others added 2 commits March 11, 2026 22:08
…ve exponent path

Replace bare `as f64` casts with `as_f64(lossy=false)` which round-trips
the conversion to catch precision loss on huge integers, returning Err
gracefully instead of silently producing incorrect results.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…xponent

i128::MAX - 1 rounds to the same f64 as i128::MAX (2^127), but the
round-trip check (n as f64 as i128 != n) catches the precision loss
and returns Err instead of panicking or silently corrupting the result.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Support power operator with negative exponents

2 participants