A cast to five bytes and a two-character word
CAST('中文' AS VARCHAR2(5)) asks for five bytes of a value that takes six. Each of the two characters is three bytes long in a UTF-8 database, so the fifth byte falls inside the second character. Oracle, PostgreSQL and Paritas each answer differently, and until this month Paritas had the worst answer of the three.
| Expression | Oracle Database 21c | PostgreSQL 18.6, nearest form | Paritas |
|---|---|---|---|
CAST('中文' AS VARCHAR2(5)) | 中, 3 bytes | varchar(5): 中文, 6 bytes | 中, 3 bytes |
CAST('中文' AS VARCHAR2(2)) | NULL | varchar(2): 中文, 6 bytes | NULL |
CAST('中文' AS CHAR(5)) | 中, 3 bytes | char(5): 中文 and three blanks, 9 bytes | 中 and two blanks, 5 bytes |
PostgreSQL has no VARCHAR2 and no lengths in bytes. varchar(5 byte) is a syntax error, and varchar(n) counts characters, so a column converted from VARCHAR2(5) to varchar(5) can hold up to 20 bytes of UTF-8 where Oracle's held five.
What our build did
Until 6 November a cast in Paritas cut at the fifth byte wherever that fell, so the value kept the first character and two bytes of the second. The cast itself raised nothing. An INSERT stored the broken text, LENGTH refused to read it, pg_dump wrote it out and the restore lost the row.
Oracle stops before the character the size would cut, and gives NULL when no whole character fits. Since 6 November 2026 both VARCHAR2 and CHAR in Paritas do that. In UTF-8 the byte at the cut says where to stop, so a long value costs no walk from its beginning.
The idea for the VARCHAR2 half came from a fix in the open-source base Paritas is built on. That version answers an empty string where Oracle answers NULL, and it leaves CHAR as it was.
How it was measured
The Oracle column is Oracle Database 21c. The regression test ora_byte_cast holds 294 of its answers: seven strings of one- to four-byte characters, cast to VARCHAR2 and CHAR at each size, by bytes, by the default and by characters, read back as LENGTHB, LENGTH and the value. Paritas runs the same 294 statements. On 6 November 2026, 274 of them matched.
The PostgreSQL column is a stock PostgreSQL 18.6 with a UTF-8 database, run on 10 November 2026.
What is still different
All 20 cells that differ are CHAR casts that stopped short, and they differ in LENGTHB and LENGTH alone. Paritas pads such a value to its size, so CAST('中文' AS CHAR(5)) is the first character and two blanks. Oracle pads only when the value is stored in a CHAR of that size or more, and leaves it short everywhere else. A stopped value and a padded one are therefore a single value to DISTINCT in Paritas.
EUC_JP and LATIN1 follow the same rule in the tests, but we have no Oracle instance in those character sets, so nothing checks them against Oracle's own answers.
Paritas is an Oracle-compatible database built on PostgreSQL, from Tech Style. It starts from an open-source base on PostgreSQL 18.6. We are building tools around it for migration, development and connecting applications. pgrecon, our free assessment tool, is out today, and the development tools and drivers are not available yet. Paritas is still in development and we are aiming to release it next quarter. More at tech-style.co/product-paritas.
Comments
Post a Comment