提交 ca869e25 编写于 作者: J Jim Doty 提交者: Jacob Champion

COPY: fix transfer of "unknown" data type

The "unknown" type has an attlen of -2, which signifies that the actual
length is determined by strlen(). We weren't handling this case, so
handle it now.
Co-authored-by: NJacob Champion <pchampion@pivotal.io>
上级 fdd878ea
...@@ -5025,10 +5025,8 @@ retry: ...@@ -5025,10 +5025,8 @@ retry:
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
errmsg("unexpected EOF in COPY data"))); errmsg("unexpected EOF in COPY data")));
} }
else else if (attr[attnum - 1]->attlen == -1)
{ {
Assert (attr[attnum - 1]->attlen == -1);
/* For simplicity, varlen's are always transmitted in "long" format */ /* For simplicity, varlen's are always transmitted in "long" format */
if (CopyGetData(cstate, &len, sizeof(len)) != sizeof(len)) if (CopyGetData(cstate, &len, sizeof(len)) != sizeof(len))
ereport(ERROR, ereport(ERROR,
...@@ -5043,6 +5041,29 @@ retry: ...@@ -5043,6 +5041,29 @@ retry:
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
errmsg("unexpected EOF in COPY data"))); errmsg("unexpected EOF in COPY data")));
} }
else if (attr[attnum - 1]->attlen == -2)
{
/*
* Like the varlen case above, cstrings are sent with a length
* prefix and no terminator, so we have to NULL-terminate in
* memory after reading them in.
*/
if (CopyGetData(cstate, &len, sizeof(len)) != sizeof(len))
ereport(ERROR,
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
errmsg("unexpected EOF in COPY data")));
p = palloc(len + 1);
if (CopyGetData(cstate, p, len) != len)
ereport(ERROR,
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
errmsg("unexpected EOF in COPY data")));
p[len] = '\0';
}
else
{
elog(ERROR, "attribute %d has invalid length %d",
attnum, attr[attnum - 1]->attlen);
}
value = PointerGetDatum(p); value = PointerGetDatum(p);
} }
...@@ -5165,7 +5186,7 @@ SendCopyFromForwardedTuple(CopyState cstate, ...@@ -5165,7 +5186,7 @@ SendCopyFromForwardedTuple(CopyState cstate,
{ {
appendBinaryStringInfo(msgbuf, DatumGetPointer(values[i]), attr[i]->attlen); appendBinaryStringInfo(msgbuf, DatumGetPointer(values[i]), attr[i]->attlen);
} }
else else if (attr[attnum - 1]->attlen == -1)
{ {
int32 len; int32 len;
char *ptr; char *ptr;
...@@ -5176,7 +5197,6 @@ SendCopyFromForwardedTuple(CopyState cstate, ...@@ -5176,7 +5197,6 @@ SendCopyFromForwardedTuple(CopyState cstate,
* in the master, and the default value comes from another table as a toast * in the master, and the default value comes from another table as a toast
* pointer. * pointer.
*/ */
Assert (attr[attnum - 1]->attlen == -1);
/* For simplicity, varlen's are always transmitted in "long" format */ /* For simplicity, varlen's are always transmitted in "long" format */
len = VARSIZE(values[i]); len = VARSIZE(values[i]);
...@@ -5185,6 +5205,36 @@ SendCopyFromForwardedTuple(CopyState cstate, ...@@ -5185,6 +5205,36 @@ SendCopyFromForwardedTuple(CopyState cstate,
appendBinaryStringInfo(msgbuf, &len, sizeof(int32)); appendBinaryStringInfo(msgbuf, &len, sizeof(int32));
appendBinaryStringInfo(msgbuf, ptr, len - VARHDRSZ); appendBinaryStringInfo(msgbuf, ptr, len - VARHDRSZ);
} }
else if (attr[attnum - 1]->attlen == -2)
{
/*
* These attrs are NULL-terminated in memory, but we send
* them length-prefixed (like the varlen case above) so that
* the receiver can preallocate a data buffer.
*/
int32 len;
size_t slen;
char *ptr;
ptr = DatumGetPointer(values[i]);
slen = strlen(ptr);
if (slen > PG_INT32_MAX)
{
elog(ERROR, "attribute %d is too long (%lld bytes)",
attnum, (long long) slen);
}
len = (int32) slen;
appendBinaryStringInfo(msgbuf, &len, sizeof(len));
appendBinaryStringInfo(msgbuf, ptr, len);
}
else
{
elog(ERROR, "attribute %d has invalid length %d",
attnum, attr[attnum - 1]->attlen);
}
} }
num_sent_fields++; num_sent_fields++;
......
...@@ -177,6 +177,15 @@ SELECT * FROM testnull; ...@@ -177,6 +177,15 @@ SELECT * FROM testnull;
| |
(4 rows) (4 rows)
-- "unknown" types can be dumped and restored: these attributes are
-- NULL-terminated in memory (attlen == -2), so the COPY code needs to handle
-- them explicitly.
CREATE TEMP TABLE type_unknown ( a unknown );
WARNING: column "a" has type "unknown"
DETAIL: Proceeding with relation creation anyway.
COPY type_unknown FROM stdin;
COPY type_unknown TO stdout;
unknown
DROP TABLE x, y; DROP TABLE x, y;
DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_before();
DROP FUNCTION fn_x_after(); DROP FUNCTION fn_x_after();
...@@ -178,6 +178,16 @@ COPY testnull FROM stdin WITH NULL AS E'\\0'; ...@@ -178,6 +178,16 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
SELECT * FROM testnull; SELECT * FROM testnull;
-- "unknown" types can be dumped and restored: these attributes are
-- NULL-terminated in memory (attlen == -2), so the COPY code needs to handle
-- them explicitly.
CREATE TEMP TABLE type_unknown ( a unknown );
COPY type_unknown FROM stdin;
unknown
\.
COPY type_unknown TO stdout;
DROP TABLE x, y; DROP TABLE x, y;
DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_before();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册