mzzz-zzm opened a new issue, #1028:
URL: https://github.com/apache/iceberg-go/issues/1028

   ### Apache Iceberg version
   
   main (development)
   
   ### Please describe the bug 🐞
   
   **Component**: `literals.go`
   **Affected version**: `main` (v0.5.0)
   **Severity**: Silent wrong-precision type metadata for any decimal literal 
read from a manifest
   
   ---
   
   `DecimalLiteral.Type()` always returns `decimal(9, scale)` regardless of the 
column's actual declared precision. Any code path that calls `.Type()` on a 
manifest-read decimal literal — type bounds checks, cast decisions, predicate 
projection — silently operates against the wrong precision.
   
   ---
   
   ## Affected code
   
   `literals.go`:
   
   ```go
   func (d DecimalLiteral) Type() Type { return DecimalTypeOf(9, d.Scale) }
   ```
   
   `DecimalLiteral` is defined as:
   
   ```go
   type DecimalLiteral Decimal
   
   // Decimal carries Val (*big.Int) and Scale (int32), but NOT precision.
   type Decimal struct {
       Val   *big.Int
       Scale int32
   }
   ```
   
   ---
   
   ## Root cause
   
   `DecimalLiteral` (and `Decimal`) do not store the column's declared 
precision — only the scale. When `Type()` needs to reconstruct the full 
`DecimalType`, it has no precision to use, so it hardcodes `9`.
   
   `9` is a valid precision for small decimal columns but is wrong for any 
column with precision ≠ 9. Common production types like `decimal(10,2)`, 
`decimal(18,4)`, or `decimal(38,10)` all silently get `decimal(9, scale)` 
instead.
   
   ---
   
   ## Impact
   
   All callers of `DecimalLiteral.Type()`:
   
   | Call site | Effect of wrong precision |
   |---|---|
   | Literal bounds/range checks | Upper bound calculated against 
`decimal(9,s)` range instead of actual column range |
   | `Literal.To(targetType)` cast path | Cast validity check uses wrong source 
type |
   | Predicate projection (`BoundPredicate`) | `Inclusive`/`Exclusive` bounds 
projected with wrong precision |
   | `validateAddedDataFilesMatchingFilter` partition evaluation | Partition 
equality compared against wrong type descriptor |
   
   ---
   
   ## Reproduction
   
   ```go
   // Column is decimal(18, 4).
   lit := iceberg.DecimalLiteral{Val: big.NewInt(12345678), Scale: 4}
   fmt.Println(lit.Type()) // prints: decimal(9, 4)  ← should be decimal(18, 4)
   ```
   
   ---
   
   ## Proposed fix
   
   Two options:
   
   **Option A — store precision in `DecimalLiteral`** (requires changing the 
type):
   
   ```go
   type DecimalLiteral struct {
       Decimal
       Precision int // declared column precision
   }
   
   func (d DecimalLiteral) Type() Type { return DecimalTypeOf(d.Precision, 
d.Scale) }
   ```
   
   This is a breaking change to the `DecimalLiteral` struct.
   
   **Option B — thread precision through construction sites** (narrower change):
   
   Ensure every constructor that produces a `DecimalLiteral` from a 
manifest-read value (e.g. `convertAvroValueToIcebergType` in `manifest.go`) 
also attaches the declared precision from the partition field's `DecimalType`. 
The precision is available at the call site and just needs to be plumbed 
through.
   
   Option B is lower-risk and can be done without breaking the public API, at 
the cost of requiring callers to supply precision explicitly.
   
   ---
   
   ## Related
   
   - Bug: `convertDecimalValue` passes string length instead of declared 
precision to `DecimalRequiredBytes` (companion bug in `manifest.go`)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to