convert_to/convert_from/convert performing a real encoding conversion return zero rows and permanently corrupt the instance
Environment: PGlite 0.5.4 (PostgreSQL 18.3, wasm32), Node 18, in-memory database, UTF8 encoding.
Reproduction
const pg = await PGlite.create();
await pg.query(`SELECT convert_to('abc', 'LATIN1')`); // resolves with ZERO rows, no error
await pg.query(`SELECT 1`); // fails — backend unusable
Deterministic; a single call on a fresh instance suffices.
Observed behavior
SELECT convert_to('abc', <encoding>):
| encoding |
result |
backend afterwards |
'nonsense' |
clean error: invalid destination encoding name |
healthy |
'UTF8' (identity), 'SQL_ASCII' |
correct value |
healthy |
'LATIN1' (real conversion) |
"success" with zero rows |
broken |
convert_from(bytea, name) and convert(bytea, name, name) behave identically whenever an actual conversion would run.
The corruption depends on call context. Direct call — everything fails afterwards:
await pg.query(`SELECT convert_to('abc', 'LATIN1')`); // zero rows
await pg.query(`SELECT 1`); // throws
Inside a plpgsql EXCEPTION block — the backend keeps answering, but lies:
await pg.exec(`
CREATE FUNCTION probe(expr text) RETURNS text LANGUAGE plpgsql AS $$
DECLARE r boolean;
BEGIN
EXECUTE 'SELECT (' || expr || ') IS NULL' INTO r;
RETURN CASE WHEN r THEN 'NULL' ELSE 'value' END;
EXCEPTION WHEN OTHERS THEN RETURN 'error';
END $$;`);
await pg.query(`SELECT probe('convert_to(''abc'', ''LATIN1'')')`); // SHORT result (0 rows)
await pg.query(`SELECT 1`); // still works!
await pg.query(`SELECT probe('1')`); // ERRORDATA_STACK_SIZE exceeded
await pg.query(`SELECT x, probe(x::text) FROM generate_series(1, 100) x`);
// can return PARTIAL or empty row sets with no error
The state persists indefinitely; only discarding the instance recovers. The second mode passes SELECT 1-style liveness checks while silently returning wrong results.
convert_to/convert_from/convertperforming a real encoding conversion return zero rows and permanently corrupt the instanceEnvironment: PGlite 0.5.4 (PostgreSQL 18.3, wasm32), Node 18, in-memory database, UTF8 encoding.
Reproduction
Deterministic; a single call on a fresh instance suffices.
Observed behavior
SELECT convert_to('abc', <encoding>):'nonsense'invalid destination encoding name'UTF8'(identity),'SQL_ASCII''LATIN1'(real conversion)convert_from(bytea, name)andconvert(bytea, name, name)behave identically whenever an actual conversion would run.The corruption depends on call context. Direct call — everything fails afterwards:
Inside a plpgsql
EXCEPTIONblock — the backend keeps answering, but lies:The state persists indefinitely; only discarding the instance recovers. The second mode passes
SELECT 1-style liveness checks while silently returning wrong results.