Skip to content

lightning: fix corrupted DECIMAL values in dictionary-encoded parquet files (#70436) - #70461

Merged
ti-chi-bot[bot] merged 1 commit into
pingcap:release-8.5from
ti-chi-bot:cherry-pick-70436-to-release-8.5
Aug 12, 2026
Merged

ti-chi-bot[bot] merged 1 commit into
pingcap:release-8.5from
ti-chi-bot:cherry-pick-70436-to-release-8.5

Conversation

@ti-chi-bot

@ti-chi-bot ti-chi-bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Member

This started as an automated cherry-pick of #70436, but it is not a clean cherry-pick: on master the code lives in pkg/dumpformat/parquetfile and converts through MyDecimal.FromParquetArray, neither of which exists on release-8.5. The bot's version added two orphan files under a package that does not exist on this branch and left the actual 8.5 code path untouched, so it fixed nothing. This PR replaces it with the equivalent fix for the code that is actually on release-8.5.

What problem does this PR solve?

Issue Number: close #70365

Problem Summary:

IMPORT INTO silently writes wrong values for repeated dictionary-encoded Parquet DECIMAL columns stored as BYTE_ARRAY / FIXED_LEN_BYTE_ARRAY. Only the first occurrence of a dictionary entry is correct; every later row referencing the same entry decodes from bytes that were already consumed. The job reports success and ADMIN CHECK TABLE passes, because both validate the KVs produced after the value was corrupted.

Root cause is buffer ownership:

  1. binaryToDecimalStr derives the absolute value from the two's-complement representation by negating the byte slice in place (rawBytes[i] = ^rawBytes[i], then the carry loop).
  2. arrow-go's dictConverter.Fill/Copy fill decoded values by assigning dict[idx], i.e. only the slice header. Every row referencing the same dictionary entry shares one backing array.
  3. The DECIMAL setters passed the decoded slice straight into the conversion, so converting the first row rewrote the dictionary entry.

On this branch the corruption is narrower than on master: the negation only runs for negative values, and the positive path just calls big.Int.SetBytes, which does not touch its input. So the witness is a repeated negative decimal, and it comes out with the wrong sign — -123.45 becomes 123.45 from the second row on.

Master is worse because #65624 replaced big.Int with MyDecimal.FromParquetArray, whose long division writes into the input for positive values too; that is why #70436 describes a different root cause and a different call path.

What changed and how does it work?

Copy each value into a buffer owned by the setter before converting. The column iterator drives setters sequentially, so one reused buffer per column keeps the copy allocation-free — no per-row allocation is added. Both byte-array DECIMAL setters (BYTE_ARRAY and FIXED_LEN_BYTE_ARRAY) go through the shared helper.

The regression test appends a dictionary-encoded case to TestParquetVariousTypes: 256 rows repeating one value per column, asserting HasDictionaryPage() so the case cannot go vacuous if the writer ever falls back to PLAIN. Each of the two negative columns fails independently without the fix. WriteParquetFile gained a FixedLenByteArrayColumnChunkWriter case, which it needs to emit the fixed-length column.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Fix the issue that `IMPORT INTO` silently writes wrong values for repeated dictionary-encoded Parquet DECIMAL columns.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed incorrect decimal values when reading dictionary-encoded Parquet data.
    • Prevented source data from being modified during decimal conversion.
    • Added support for writing fixed-length byte-array columns in Parquet files.
  • Tests
    • Added coverage for positive and negative decimal values using variable- and fixed-length byte arrays.

@ti-chi-bot ti-chi-bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR. labels Aug 12, 2026
@ti-chi-bot ti-chi-bot Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 12, 2026
@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 96e0048e-bbb6-4a56-9ab5-f589372d33ea

📥 Commits

Reviewing files that changed from the base of the PR and between 369e9c1 and f3290ed.

📒 Files selected for processing (3)
  • pkg/lightning/mydump/parquet_parser_test.go
  • pkg/lightning/mydump/parquet_type_converter.go
  • pkg/lightning/mydump/parquet_writer.go

📝 Walkthrough

Walkthrough

The change prevents decimal conversion from mutating Parquet-backed byte arrays. It adds fixed-length byte-array writing support and regression coverage for repeated dictionary-encoded decimal values.

Changes

Parquet decimal safety

Layer / File(s) Summary
Decimal buffer isolation
pkg/lightning/mydump/parquet_type_converter.go
A shared setter copies variable-length and fixed-length decimal bytes before conversion.
Dictionary regression and fixed-length writing
pkg/lightning/mydump/parquet_writer.go, pkg/lightning/mydump/parquet_parser_test.go
Parquet writing handles fixed-length byte arrays. Tests verify repeated dictionary-encoded decimal values across 256 rows.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

  • pingcap/tidb#70436: Directly addresses dictionary-encoded Parquet DECIMAL buffer corruption.
  • pingcap/tidb#70459: Changes the same decimal byte-array conversion logic and adds equivalent regression coverage.

Poem

A rabbit found bytes in a dictionary lair,
Reused by each row and altered in air.
Now copies keep every decimal bright,
Fixed-length values write cleanly and right.
“Hop!” says the rabbit, “No data takes flight.”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address issue #70365 by protecting shared dictionary buffers and covering both variable- and fixed-length DECIMAL columns.
Out of Scope Changes check ✅ Passed All changes support the linked issue, including the fixed-length writer support required by the regression test.
Description check ✅ Passed The description includes the required issue reference, problem summary, implementation details, test checklist, side effects, documentation checks, and release note.
Title check ✅ Passed The title clearly identifies the affected lightning functionality and the main fix for corrupted dictionary-encoded Parquet DECIMAL values.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
pkg/dumpformat/parquetfile/type_converter.go (1)

53-57: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document that this function can mutate val in place.

setDatumFromDecimalByte passes val to getStringFromParquetByte on the fallback path. That function inverts and decrements the bytes in place, and then destroys them during base-256 division. The only note about this contract is on getDecimalByteSetter at Line 387. A future caller that reads this signature alone can pass a shared or dictionary-backed slice and reintroduce the exact corruption this PR fixes.

Add the constraint to the function comment.

♻️ Proposed documentation
+// setDatumFromDecimalByte converts a parquet two's complement decimal value
+// into d.
+//
+// The caller must own val: on the string fallback path the conversion
+// consumes val in place, so a shared or dictionary-backed slice is corrupted.
 func setDatumFromDecimalByte(d *types.Datum, val []byte, scale int) error {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dumpformat/parquetfile/type_converter.go` around lines 53 - 57, Add a
function comment for setDatumFromDecimalByte explicitly stating that it may
mutate the supplied val byte slice in place, so callers must not pass shared or
dictionary-backed data. Keep the implementation unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/dumpformat/parquetfile/parser_test.go`:
- Around line 151-153: Update every testutils.WriteParquetFile call in
pkg/dumpformat/parquetfile/parser_test.go at lines 151-153, 421-423, 1072-1074,
1204-1206, and 1383-1389 to pass its returned error to require.NoError using the
test instance. Ensure all five fixture writes fail immediately with actionable
context instead of discarding errors; the surrounding parser tests require no
other changes.
- Around line 1860-1864: Correct the argument order in the ErrorIs assertion for
dec.FromParquetArray: pass its returned error as the actual error and
types.ErrOverflow as the target sentinel, preserving the overflow test’s intent
and allowing wrapped errors.
- Around line 1289-1294: Replace assert.NoError with require.NoError for each
ReadRow call in the affected test loops, including the corresponding patterns
near the other referenced locations, so execution stops before parser.LastRow()
is accessed when reading fails.
- Line 116: Add the missing parquet fixtures aurora_snapshot.parquet and
hive_dump.parquet under the testfiles directory referenced by TestParquetParser,
then run make bazel_prepare to generate and commit the BUILD.bazel metadata for
pkg/dumpformat/parquetfile.

---

Nitpick comments:
In `@pkg/dumpformat/parquetfile/type_converter.go`:
- Around line 53-57: Add a function comment for setDatumFromDecimalByte
explicitly stating that it may mutate the supplied val byte slice in place, so
callers must not pass shared or dictionary-backed data. Keep the implementation
unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1459e43f-c9d8-4c32-96fb-63621f9ab199

📥 Commits

Reviewing files that changed from the base of the PR and between f5fa13c and 369e9c1.

📒 Files selected for processing (2)
  • pkg/dumpformat/parquetfile/parser_test.go
  • pkg/dumpformat/parquetfile/type_converter.go

return parquet.Int96(b)
}

func TestParquetParser(t *testing.T) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify the package BUILD.bazel lists the new sources and test fixtures.
set -euo pipefail

fd -t f 'BUILD.bazel' pkg/dumpformat/parquetfile --exec cat {}

# Confirm the checked-in fixtures referenced by the tests exist.
fd -t f -e parquet . pkg/dumpformat/parquetfile

Repository: pingcap/tidb

Length of output: 150


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- package files ---'
git ls-files pkg/dumpformat/parquetfile

printf '%s\n' '--- BUILD files under pkg/dumpformat ---'
fd -t f 'BUILD.bazel' pkg/dumpformat -x sh -c 'echo "--- $1"; cat -n "$1"' sh {}

printf '%s\n' '--- parquet fixtures under repository ---'
fd -t f -e parquet . | sed -n '1,120p'

printf '%s\n' '--- relevant repository changes ---'
git diff --stat
git status --short

Repository: pingcap/tidb

Length of output: 1867


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- dumpformat tree ---'
find pkg/dumpformat -maxdepth 3 -type f -print | sort

printf '%s\n' '--- references to pkg/dumpformat/parquetfile ---'
rg -n --hidden --glob '!vendor/**' --glob '!node_modules/**' \
  'pkg/dumpformat/parquetfile|dumpformat/parquetfile|type_converter.go|parser_test.go' \
  . | sed -n '1,240p'

printf '%s\n' '--- nearby Bazel metadata ---'
fd -t f -g 'BUILD.bazel' -g 'BUILD' pkg | rg 'dumpformat|parquet|lightning' | sed -n '1,160p'

printf '%s\n' '--- applicable instructions ---'
fd -t f 'AGENTS.md' -x sh -c 'echo "--- $1"; cat "$1"' sh {}

Repository: pingcap/tidb

Length of output: 1889


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Bazel preparation rules ---'
rg -n -C 4 'bazel_prepare|BUILD\.bazel' Makefile build .github 2>/dev/null | sed -n '1,240p'

printf '%s\n' '--- all Bazel files that mention dumpformat or broad Go globs ---'
fd -t f 'BUILD.bazel' . -x sh -c '
  if rg -q "dumpformat|glob\\(.*\\.go|go_library|go_test" "$1"; then
    echo "--- $1"
    rg -n -C 2 "dumpformat|glob\\(.*\\.go|go_library|go_test" "$1" | sed -n "1,180p"
  fi
' sh {}

printf '%s\n' '--- parser test file structure and fixture references ---'
ast-grep outline pkg/dumpformat/parquetfile/parser_test.go
rg -n -C 3 'testfiles|testdata|\.parquet|Test[A-Za-z0-9_]+\s*\(|Benchmark[A-Za-z0-9_]+' \
  pkg/dumpformat/parquetfile/parser_test.go | sed -n '1,280p'

printf '%s\n' '--- Go file headers and imports ---'
sed -n '1,70p' pkg/dumpformat/parquetfile/type_converter.go
sed -n '1,70p' pkg/dumpformat/parquetfile/parser_test.go

Repository: pingcap/tidb

Length of output: 50369


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- bazel_prepare implementation ---'
sed -n '581,600p' Makefile

printf '%s\n' '--- top-level tests and benchmark declarations ---'
python3 - <<'PY'
import re
from pathlib import Path

for path in sorted(Path("pkg/dumpformat/parquetfile").glob("*.go")):
    text = path.read_text()
    print(f"--- {path}")
    for match in re.finditer(r"^func\s+(Test\w+|Benchmark\w+)\s*\(", text, re.M):
        print(f"{match.group(1)}:{text.count(chr(10), 0, match.start()) + 1}")
PY

printf '%s\n' '--- fixture and generated-file references in parser_test.go ---'
rg -n -C 2 'testfiles|testdata|\.parquet|os\.|embed|ReadFile|OpenFile' \
  pkg/dumpformat/parquetfile/parser_test.go | sed -n '1,240p'

printf '%s\n' '--- package metadata existence ---'
for path in pkg/dumpformat/BUILD.bazel pkg/dumpformat/parquetfile/BUILD.bazel \
            pkg/dumpformat/parquetfile/testfiles; do
  if [ -e "$path" ]; then
    echo "exists: $path"
  else
    echo "missing: $path"
  fi
done

Repository: pingcap/tidb

Length of output: 7682


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- fixture call sites and helper implementation ---'
sed -n '70,125p' pkg/dumpformat/parquetfile/parser_test.go
sed -n '1248,1335p' pkg/dumpformat/parquetfile/parser_test.go

printf '%s\n' '--- referenced fixture names in the repository ---'
rg -n --hidden --glob '!vendor/**' \
  'aurora_snapshot\.parquet|hive_dump\.parquet|newParquetParserForTest\(.*testfiles' . \
  | sed -n '1,160p'

printf '%s\n' '--- exact filesystem checks ---'
python3 - <<'PY'
from pathlib import Path

root = Path("pkg/dumpformat/parquetfile")
for path in (
    root / "testfiles",
    root / "testfiles" / "aurora_snapshot.parquet",
    root / "testfiles" / "hive_dump.parquet",
):
    print(f"{path}: {'exists' if path.exists() else 'missing'}")
PY

Repository: pingcap/tidb

Length of output: 5112


Regenerate Bazel metadata and add the missing test fixtures.

pkg/dumpformat/parquetfile has no BUILD.bazel. Run make bazel_prepare and commit the generated metadata. Add testfiles/aurora_snapshot.parquet and testfiles/hive_dump.parquet; both tests open these missing files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dumpformat/parquetfile/parser_test.go` at line 116, Add the missing
parquet fixtures aurora_snapshot.parquet and hive_dump.parquet under the
testfiles directory referenced by TestParquetParser, then run make bazel_prepare
to generate and commit the BUILD.bazel metadata for pkg/dumpformat/parquetfile.

Source: Coding guidelines

Comment on lines +151 to +153
testutils.WriteParquetFile(dir, name, pc, 100)

reader := newParquetParserForTest(context.Background(), t, dir, name, 0, FileMeta{})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Five call sites discard the error from testutils.WriteParquetFile. The shared root cause is inconsistent error checking on the same helper. Other call sites in this file check it, for example Line 234, Line 509, and Line 1162. When a discarded write fails, the test fails later inside the parser with an unrelated open or parse error, which hides the real cause.

Wrap each call in require.NoError.

  • pkg/dumpformat/parquetfile/parser_test.go#L151-L153: wrap the TestParquetParser fixture write in require.NoError.
  • pkg/dumpformat/parquetfile/parser_test.go#L421-L423: wrap the timestamp_and_decimal fixture write in require.NoError.
  • pkg/dumpformat/parquetfile/parser_test.go#L1072-L1074: wrap the decimal_with_nulls fixture write in require.NoError.
  • pkg/dumpformat/parquetfile/parser_test.go#L1204-L1206: wrap the boolean fixture write in require.NoError.
  • pkg/dumpformat/parquetfile/parser_test.go#L1383-L1389: wrap the TestBasicReadFile multi-page fixture write in require.NoError.

The coding guidelines state: "Keep error handling actionable and contextual; do not silently swallow errors."

📍 Affects 1 file
  • pkg/dumpformat/parquetfile/parser_test.go#L151-L153 (this comment)
  • pkg/dumpformat/parquetfile/parser_test.go#L421-L423
  • pkg/dumpformat/parquetfile/parser_test.go#L1072-L1074
  • pkg/dumpformat/parquetfile/parser_test.go#L1204-L1206
  • pkg/dumpformat/parquetfile/parser_test.go#L1383-L1389
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dumpformat/parquetfile/parser_test.go` around lines 151 - 153, Update
every testutils.WriteParquetFile call in
pkg/dumpformat/parquetfile/parser_test.go at lines 151-153, 421-423, 1072-1074,
1204-1206, and 1383-1389 to pass its returned error to require.NoError using the
test instance. Ensure all five fixture writes fail immediately with actionable
context instead of discarding errors; the surrounding parser tests require no
other changes.

Source: Coding guidelines

Comment on lines +1289 to +1294
for i := range expectedRes {
err := parser.ReadRow()
assert.NoError(t, err)
expectedValues := expectedRes[i]
row := parser.LastRow().Row
assert.Len(t, expectedValues, len(row))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use require.NoError before you read LastRow.

assert.NoError records the failure and continues. If ReadRow fails, the loop still calls parser.LastRow() and indexes row, so the test reports a confusing secondary failure, or panics on a short row. The same pattern appears at Line 1079 and Line 1212.

🐛 Proposed fix
 	for i := range expectedRes {
 		err := parser.ReadRow()
-		assert.NoError(t, err)
+		require.NoError(t, err)
 		expectedValues := expectedRes[i]
 		row := parser.LastRow().Row
-		assert.Len(t, expectedValues, len(row))
+		require.Len(t, expectedValues, len(row))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for i := range expectedRes {
err := parser.ReadRow()
assert.NoError(t, err)
expectedValues := expectedRes[i]
row := parser.LastRow().Row
assert.Len(t, expectedValues, len(row))
for i := range expectedRes {
err := parser.ReadRow()
require.NoError(t, err)
expectedValues := expectedRes[i]
row := parser.LastRow().Row
require.Len(t, expectedValues, len(row))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dumpformat/parquetfile/parser_test.go` around lines 1289 - 1294, Replace
assert.NoError with require.NoError for each ReadRow call in the affected test
loops, including the corresponding patterns near the other referenced locations,
so execution stops before parser.LastRow() is accessed when reading fails.

Comment on lines +1860 to +1864
// Test overflow
var dec types.MyDecimal
raw := bytes.Repeat([]byte{0x7f}, 40)
require.ErrorIs(t, types.ErrOverflow, dec.FromParquetArray(raw, 0))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The require.ErrorIs arguments are reversed.

The signature is require.ErrorIs(t, err, target). This call passes types.ErrOverflow as err and the value returned by FromParquetArray as target. The assertion therefore evaluates errors.Is(types.ErrOverflow, returnedErr), which is the opposite of the intent.

The call passes only when the returned error is identical to types.ErrOverflow. If FromParquetArray wraps or annotates the error, the assertion fails even though the behavior is correct. It also does not verify the returned error against the sentinel in the general case.

🐛 Proposed fix
 	// Test overflow
 	var dec types.MyDecimal
 	raw := bytes.Repeat([]byte{0x7f}, 40)
-	require.ErrorIs(t, types.ErrOverflow, dec.FromParquetArray(raw, 0))
+	require.ErrorIs(t, dec.FromParquetArray(raw, 0), types.ErrOverflow)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Test overflow
var dec types.MyDecimal
raw := bytes.Repeat([]byte{0x7f}, 40)
require.ErrorIs(t, types.ErrOverflow, dec.FromParquetArray(raw, 0))
}
// Test overflow
var dec types.MyDecimal
raw := bytes.Repeat([]byte{0x7f}, 40)
require.ErrorIs(t, dec.FromParquetArray(raw, 0), types.ErrOverflow)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dumpformat/parquetfile/parser_test.go` around lines 1860 - 1864, Correct
the argument order in the ErrorIs assertion for dec.FromParquetArray: pass its
returned error as the actual error and types.ErrOverflow as the target sentinel,
preserving the overflow test’s intent and allowing wrapped errors.

@codecov

codecov Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (release-8.5@f5fa13c). Learn more about missing BASE report.

Additional details and impacted files
@@               Coverage Diff                @@
##             release-8.5     #70461   +/-   ##
================================================
  Coverage               ?   55.1391%           
================================================
  Files                  ?       1852           
  Lines                  ?     666989           
  Branches               ?          0           
================================================
  Hits                   ?     367772           
  Misses                 ?     271833           
  Partials               ?      27384           
Flag Coverage Δ
integration 38.2062% <63.6363%> (?)
unit 65.1153% <100.0000%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 55.3108% <0.0000%> (?)
parser ∅ <0.0000%> (?)
br 54.8011% <0.0000%> (?)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

… files (pingcap#70436)

The automated cherry-pick of pingcap#70436 dropped two files into
pkg/dumpformat/parquetfile, a package that does not exist on this
branch, and left the actual 8.5 code path untouched. This replaces it
with the equivalent fix for release-8.5.

Here the byte-array DECIMAL setters live in pkg/lightning/mydump and
convert through binaryToDecimalStr, which rewrites its input in place
when the value is negative. arrow-go's dictionary decoder assigns
dict[idx] to every row referencing an entry, so all those rows share one
backing array: converting the first occurrence negated the dictionary
entry, and later rows decoded the already-negated bytes as a positive
value. Positive values are unaffected on this branch because that path
only calls big.Int.SetBytes, which does not touch the input.

Copy each value into a buffer owned by the setter before converting. The
column iterator drives setters sequentially, so one reused buffer per
column keeps the copy allocation-free.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@joechenrh
joechenrh force-pushed the cherry-pick-70436-to-release-8.5 branch from 369e9c1 to f3290ed Compare August 12, 2026 05:31
@ti-chi-bot ti-chi-bot Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Aug 12, 2026
@joechenrh joechenrh changed the title dumpformat: fix corrupted DECIMAL values in dictionary-encoded parquet files (#70436) lightning: fix corrupted DECIMAL values in dictionary-encoded parquet files (#70436) Aug 12, 2026
@ti-chi-bot ti-chi-bot Bot added the needs-1-more-lgtm Indicates a PR needs 1 more LGTM. label Aug 12, 2026
@joechenrh

Copy link
Copy Markdown
Contributor

/retest

@ti-chi-bot

ti-chi-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: D3Hunter, joechenrh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added approved lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Aug 12, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-08-12 05:36:24.781369381 +0000 UTC m=+3197570.817464437: ☑️ agreed by joechenrh.
  • 2026-08-12 07:38:41.96352268 +0000 UTC m=+3204907.999617735: ☑️ agreed by D3Hunter.

@ti-chi-bot ti-chi-bot Bot added cherry-pick-approved Cherry pick PR approved by release team. and removed do-not-merge/cherry-pick-not-approved labels Aug 12, 2026
@ti-chi-bot
ti-chi-bot Bot merged commit 98ce2a8 into pingcap:release-8.5 Aug 12, 2026
19 checks passed
@ti-chi-bot
ti-chi-bot Bot deleted the cherry-pick-70436-to-release-8.5 branch August 12, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved cherry-pick-approved Cherry pick PR approved by release team. lgtm release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants