Tomas Vondra wrote:
> My guess is this is a problem at the protocol level - the 'd' message is
> CopyData, and all the messages use int32 to define length. So if there's
> a 2GB row, it's likely to overflow.
Yes. Besides, the full message includes a negative length:
> postgres=# \copy big2 to /dev/null
> lost synchronization with server: got message type "d", length -1568669676
which happens to be the correct size if interpreted as an unsigned int32
-1568669676 = (int) (1300UL*1024*1024*2 + 3 + 3*4 + 1 + 4)
One interpretation would be that putting an unsigned length in
CopyData message is a protocol violation.
However it's not clear to me that Int32 in the doc necessarily designates
a signed integer.
Int32 is defined as: Intn(i)
An n-bit integer in network byte order (most significant byte first). If i is specified it is the exact value that
willappear, otherwise the value is variable. Eg. Int16, Int32(42).
There's a least one example when we use Int16 as unsigned:
the number of parameters in Bind (F) can be up to 65535.
This maximum is tested explicitly and refered to at several
places in fe-exec.
In some instances, Int32 is clearly signed, because -1 is accepted
to indicate NULLness, such as again in Bind (F) for the length of
the parameter value.
From this it seems to me that Intn is to be interpreted as
signed or unsigned on a case by case basis.
Back to CopyData (F & B), it's documented as:
Byte1('d') Identifies the message as COPY data.
Int32 Length of message contents in bytes, including self.
Byten Data that forms part of a COPY data stream. Messages sent from the backend will always correspond to single data
rows,but messages sent by frontends might divide the data stream arbitrarily.
I don't see any hint that this length is signed, nor any reason of having
it signed.
I guess before the patch it didn't matter, for the B case at least,
because the backend never sent more than 1GB.
Best regards,
--
Daniel Vérité
PostgreSQL-powered mailer: http://www.manitou-mail.org
Twitter: @DanielVerite