GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Accept and return ordinary .NET numbers for DECFLOAT by fdcastel · Pull Request #1307 · FirebirdSQL/NETProvider

Conversation

@fdcastel

@fdcastel fdcastel commented Nov 7, 2026

Copy link
Copy Markdown
Member

Fixes #1300. Based on #1306.

Summary

DECFLOAT columns and parameters now work with the usual .NET numeric types. Values are never rounded silently: a value that does not fit exactly throws OverflowException.

Changes

Parameters (DbValue.GetDecFloat): decimal, double, float, the integral types and BigInteger are converted to FbDecFloat, using the rules of #1306. They used to throw InvalidCastException, also with AddWithValue.

Reader (DbValue getters, so GetFieldValue<T> too):

Accessor DECFLOAT value
GetDecimal exact, keeping the scale (1.10 becomes 1.10m); OverflowException when the value is not exact (too large, too many digits, NaN or infinity)
GetDouble, GetFloat nearest value, as on NUMERIC columns; NaN and infinities are mapped; overflow becomes infinity
GetInt16, GetInt32, GetInt64, GetByte nearest integer, ties to even (as Convert does for decimal columns); OverflowException when out of range, NaN or infinity

FbDecFloat gets the matching public explicit conversions to decimal, double and float. docs/decfloat.md documents the rules.

Writing is stricter than the server's own CAST. A double whose shortest exact form has 17 digits (e.g. 0.1 + 0.2) throws for a DECFLOAT(16) parameter, whereas CAST(0.1e0 + 0.2e0 AS DECFLOAT(16)) rounds to 0.3000000000000000. This is deliberate (see #1306): the provider does not round a value silently. Values that fit exactly are stored unchanged, as the round-trip tests below show.

Tests

  • FbDecFloatTypeTests (NoServer): the new conversions, including limits, NaN, infinities, negative zero and rounding to even.
  • FbDecFloat16SupportTests and FbDecFloat34SupportTests:
    • .NET values passed to DECFLOAT parameters; values that do not fit throw,
    • GetDecimal, GetDouble, GetFloat and GetInt*: exact, nearest, rounding and throwing cases.
  • Without the DbValue changes, 92 of the new tests fail. With them, the embedded + NoServer suite passes: 834 passed, 0 failed.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
fdcastel added 5 commits November 7, 2026 10:39
@fdcastel
Do not silently corrupt DECFLOAT values that do not fit the target fo…
c1cf2d2
…rmat

DecimalCodec.EncodeDecimal wrote coefficients with more digits than the
format allows, and exponents outside its range, without any check (only a
Debug.Assert). In Release builds the excess bits overflowed into the
combination/exponent fields and the server stored a different value, e.g.:

  12345678901234567890123456789012345 -> DECFLOAT(34) stored 8345678901234567890123456789012345
  30000000000000004E-17               -> DECFLOAT(16) stored 0.08000000000000004
  1E400                               -> DECFLOAT(16) stored 8.000000000000001E-353

The encoder now brings the value into the format's ranges without changing
its numeric value (dropping trailing zeros of the coefficient, folding the
exponent into the coefficient, clamping the exponent of zero), and throws
OverflowException when the value cannot be represented exactly (too many
significant digits, exponent overflow or underflow). Values that previously
got corrupted although representable (e.g. 1E384 in DECFLOAT(16)) now work.
@fdcastel
Fix FbDecFloat explicit conversions from decimal, double and float
1bb32cc
The conversions formatted the value with a fixed custom format and then
removed the decimal point, assuming one was present. This threw
ArgumentOutOfRangeException for every value without a fractional part,
e.g. (FbDecFloat)1m, (FbDecFloat)100m, (FbDecFloat)2.0, and for values
smaller than the format's decimal places, e.g. (FbDecFloat)1e-20. It also
dropped the scale of decimals (1.10m became 1.1) and digits beyond 15
decimal places of doubles (7 for floats).

- decimal: converted exactly from its 96-bit integer and scale, so the
  value and its scale are preserved (1.10m -> 110E-2), including -0.
- double/float: converted to the shortest decimal that round-trips to the
  same binary value ("R" format), e.g. 0.1 -> 1E-1, 0.1 + 0.2 ->
  30000000000000004E-17, 1e-20 -> 1E-20; -0.0 -> negative zero.

A converted double may have up to 17 significant digits; sending it to a
DECFLOAT(16) throws OverflowException instead of being silently rounded
(this relies on the encoder range check of the previous commit).
@fdcastel
Cover negative doubles in the FbDecFloat round-trip property test
d876f47
Random.NextInt64() never returns a negative value, so the random doubles
were all positive. Use the full long range and assert both signs are covered.
@fdcastel
Accept and return ordinary .NET numbers for DECFLOAT
2f9500e
Parameters: a DECFLOAT parameter only accepted FbDecFloat; any other value
(decimal, double, int, ...) threw InvalidCastException, even when the
parameter was created by AddWithValue with a decimal. Values of type
decimal, double, float, the integral types and BigInteger are now converted
to FbDecFloat (decimal exactly, double/float to the shortest round-trip
value). A value that does not fit the DECFLOAT precision exactly throws
OverflowException instead of being rounded.

Reader: GetDecimal, GetDouble, GetFloat, GetInt16/32/64 and GetByte (and
the matching GetFieldValue<T>) on a DECFLOAT column threw
InvalidCastException because FbDecFloat is not IConvertible. Now:

- GetDecimal: exact, keeping the scale (1.10 -> 1.10m); OverflowException
  when the value cannot be represented exactly (too large, too many digits,
  NaN, infinity).
- GetDouble/GetFloat: nearest value, like on NUMERIC columns; NaN and
  infinities are mapped, out-of-range values become infinity or zero.
- Integer getters: nearest integer, ties to even, as Convert does for
  decimal columns; OverflowException when out of range, NaN or infinity.

FbDecFloat gets the matching public explicit conversions to decimal, double
and float.
@fdcastel
Document DECFLOAT conversions from and to other .NET types
683cc93
@fdcastel fdcastel mentioned this pull request Nov 7, 2026
Support .NET 11 Decimal128/Decimal64/Decimal32 for DECFLOAT #1308
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

DECFLOAT columns and parameters do not work with decimal, double or integers

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@fdcastel
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.