Fixed Issue #3326 - #3350
Fixed Issue #3326#3350Hydrocharged wants to merge 1 commit into
Conversation
|
SummaryThe run covers byte-to-text conversion and decoding across common formats and character sets, including valid inputs, malformed and boundary inputs, error classification, session recovery, and result types. Core valid behavior and most defensive handling are healthy, but one malformed multibyte-input edge case still produces incorrect replacement text instead of an error. Merge with caution — the PR has a medium-severity correctness issue where malformed multibyte input can be silently altered rather than rejected, although valid conversions and session stability remain intact. No unrelated findings are driving the verdict. Tests run by ItoTip Reply with @itoqa to send us feedback on this test run. |
| return nil, err | ||
| } | ||
|
|
||
| source := lookupPostgresEncoding(encodingName) |
There was a problem hiding this comment.
Truncated EUC-JP returns replacement text
What failed: The UTF-8 cases for bytes C3, E2 82, and FF correctly returned invalid byte sequence errors, and a valid query worked afterward. The truncated EUC_JP byte A4 returned the replacement character instead of failing as required for an incomplete multibyte sequence.
Impact · Steps · Stub / mock · Analysis · Why this is likely a bug
- Severity: Medium
- Impact: A user who submits truncated EUC-JP data can receive a replacement character instead of an error, so the converted text is silently wrong. The issue is limited to malformed multibyte input and does not affect valid conversions.
- Steps to Reproduce:
- Connect to the local Doltgres server as the postgres user.
- Run SELECT convert_from('\xa4'::bytea, 'EUC_JP');.
- Observe that the query returns a replacement character instead of an invalid byte sequence error.
- Run SELECT convert_from('\x6869'::bytea, 'UTF8'); afterward and confirm the connection still works.
- Stub / mock content: No stubs, mocks, or bypasses were applied for this test in the recorded run.
- Code Analysis: The PR adds server/functions/convert_from.go and registers it from server/functions/init.go. In convert_from_bytea_name.Callable, lines 50-65 resolve the requested PostgreSQL encoding and distinguish pass-through, unsupported, and decoder-backed encodings. For EUC_JP, server/functions/encoding.go lines 42-45 select japanese.EUCJP as the encoder. The decoder branch at server/functions/convert_from.go lines 67-72 calls source.encoder.NewDecoder().Bytes(input), discards the exact decoder output semantics, and returns string(converted) whenever Bytes returns no Go error. That behavior lets x/text produce a replacement character for the truncated input instead of converting the malformed sequence into the PostgreSQL CharacterNotInRepertoire error that the surrounding function promises. The smallest practical fix is to use strict malformed-input handling for decoder-backed source encodings, or explicitly detect incomplete/invalid source sequences before returning converted text, and return the existing invalid-byte-sequence error on rejection.
- Why this is likely a bug: The failure is reproducible through the normal SQL API with a user-supplied bytea value, not through a mock or test-only patch. The test’s UTF-8 cases demonstrate the intended contract: malformed bytes must fail, no replacement text may be returned, and the same session must remain usable. The EUC_JP result violates the same contract by silently changing malformed input into a visible character. Because the PR introduced both the EUC_JP decoder registration and the conversion branch that returns its output, the issue is a direct PR regression and can be fixed locally by making that branch reject malformed or truncated source sequences.
Relevant code
server/functions/convert_from.go:50-72
source := lookupPostgresEncoding(encodingName)
...
converted, err := source.encoder.NewDecoder().Bytes(input)
if err != nil {
return nil, pgerror.WithCandidateCode(fmt.Errorf(`invalid byte sequence for encoding "%s"`, source.name), pgcode.CharacterNotInRepertoire)
}
return string(converted), nilserver/functions/encoding.go:42-45
var postgresEncodings = []postgresEncoding{
{name: "SQL_ASCII", id: 0, aliases: []string{"SQLASCII"}, passThrough: true},
{name: "EUC_JP", id: 1, encoder: japanese.EUCJP},Evidence Package
Copy prompt for an agent
Ito QA identified the following failure during automated PR testing. Please investigate and propose a fix.
**Medium severity — Truncated EUC-JP returns replacement text**
**What failed:** The UTF-8 cases for bytes C3, E2 82, and FF correctly returned invalid byte sequence errors, and a valid query worked afterward. The truncated EUC_JP byte A4 returned the replacement character instead of failing as required for an incomplete multibyte sequence.
- **Impact:** A user who submits truncated EUC-JP data can receive a replacement character instead of an error, so the converted text is silently wrong. The issue is limited to malformed multibyte input and does not affect valid conversions.
- **Steps to reproduce:**
1. Connect to the local Doltgres server as the postgres user.
2. Run SELECT convert_from('\xa4'::bytea, 'EUC_JP');.
3. Observe that the query returns a replacement character instead of an invalid byte sequence error.
4. Run SELECT convert_from('\x6869'::bytea, 'UTF8'); afterward and confirm the connection still works.
- **Stub / mock content:** No stubs, mocks, or bypasses were applied for this test in the recorded run.
- **Code analysis:** The PR adds server/functions/convert_from.go and registers it from server/functions/init.go. In convert_from_bytea_name.Callable, lines 50-65 resolve the requested PostgreSQL encoding and distinguish pass-through, unsupported, and decoder-backed encodings. For EUC_JP, server/functions/encoding.go lines 42-45 select japanese.EUCJP as the encoder. The decoder branch at server/functions/convert_from.go lines 67-72 calls source.encoder.NewDecoder().Bytes(input), discards the exact decoder output semantics, and returns string(converted) whenever Bytes returns no Go error. That behavior lets x/text produce a replacement character for the truncated input instead of converting the malformed sequence into the PostgreSQL CharacterNotInRepertoire error that the surrounding function promises. The smallest practical fix is to use strict malformed-input handling for decoder-backed source encodings, or explicitly detect incomplete/invalid source sequences before returning converted text, and return the existing invalid-byte-sequence error on rejection.
- **Why this is likely a bug:** The failure is reproducible through the normal SQL API with a user-supplied bytea value, not through a mock or test-only patch. The test’s UTF-8 cases demonstrate the intended contract: malformed bytes must fail, no replacement text may be returned, and the same session must remain usable. The EUC_JP result violates the same contract by silently changing malformed input into a visible character. Because the PR introduced both the EUC_JP decoder registration and the conversion branch that returns its output, the issue is a direct PR regression and can be fixed locally by making that branch reject malformed or truncated source sequences.
**Relevant code:**
`server/functions/convert_from.go:50-72`
~~~go
source := lookupPostgresEncoding(encodingName)
...
converted, err := source.encoder.NewDecoder().Bytes(input)
if err != nil {
return nil, pgerror.WithCandidateCode(fmt.Errorf(`invalid byte sequence for encoding "%s"`, source.name), pgcode.CharacterNotInRepertoire)
}
return string(converted), nil
~~~
`server/functions/encoding.go:42-45`
~~~go
var postgresEncodings = []postgresEncoding{
{name: "SQL_ASCII", id: 0, aliases: []string{"SQLASCII"}, passThrough: true},
{name: "EUC_JP", id: 1, encoder: japanese.EUCJP},
~~~
|
|
@Hydrocharged DOLT
|
zachmu
left a comment
There was a problem hiding this comment.
Change itself looks good, but please change the PR description to describe what actually changed / is implemented rather than just an issue number. For this one, should be "Implements convert_from and decode"
| return nil, err | ||
| } | ||
|
|
||
| source := lookupPostgresEncoding(encodingName) |
| }, | ||
| }, | ||
| { | ||
| Name: "Issue #3326: convert_from and decode", |
There was a problem hiding this comment.
This test belongs in function_test


Fixes #3326.
Stacked on #3349.