1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-08 11:42:09 +03:00

Second round of FE/BE protocol changes. Frontend->backend messages now

have length counts, and COPY IN data is packetized into messages.
This commit is contained in:
Tom Lane
2003-04-19 00:02:30 +00:00
parent 54b38d293e
commit bd8d441775
24 changed files with 1337 additions and 982 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.191 2003/04/04 20:42:11 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.192 2003/04/19 00:02:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -31,6 +31,7 @@
#include "commands/trigger.h"
#include "executor/executor.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
@ -49,6 +50,17 @@
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
#define OCTVALUE(c) ((c) - '0')
/*
* Represents the different source/dest cases we need to worry about at
* the bottom level
*/
typedef enum CopyDest
{
COPY_FILE, /* to/from file */
COPY_OLD_FE, /* to/from frontend (old protocol) */
COPY_NEW_FE /* to/from frontend (new protocol) */
} CopyDest;
/*
* Represents the type of data returned by CopyReadAttribute()
*/
@ -61,13 +73,13 @@ typedef enum CopyReadResult
/* non-export function prototypes */
static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print);
char *delim, char *null_print);
static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print);
char *delim, char *null_print);
static Oid GetInputFunction(Oid type);
static Oid GetTypeElement(Oid type);
static char *CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result);
static void CopyAttributeOut(FILE *fp, char *string, char *delim);
static char *CopyReadAttribute(const char *delim, CopyReadResult *result);
static void CopyAttributeOut(char *string, char *delim);
static List *CopyGetAttnums(Relation rel, List *attnamelist);
static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
@ -77,7 +89,11 @@ static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
* never been reentrant...
*/
int copy_lineno = 0; /* exported for use by elog() -- dz */
static bool fe_eof;
static CopyDest copy_dest;
static FILE *copy_file; /* if copy_dest == COPY_FILE */
static StringInfo copy_msgbuf; /* if copy_dest == COPY_NEW_FE */
static bool fe_eof; /* true if detected end of copy data */
/*
* These static variables are used to avoid incurring overhead for each
@ -96,98 +112,229 @@ static int server_encoding;
/*
* Internal communications functions
*/
static void CopySendData(void *databuf, int datasize, FILE *fp);
static void CopySendString(const char *str, FILE *fp);
static void CopySendChar(char c, FILE *fp);
static void CopyGetData(void *databuf, int datasize, FILE *fp);
static int CopyGetChar(FILE *fp);
static int CopyGetEof(FILE *fp);
static int CopyPeekChar(FILE *fp);
static void CopyDonePeek(FILE *fp, int c, bool pickup);
static void SendCopyBegin(bool binary);
static void ReceiveCopyBegin(bool binary);
static void SendCopyEnd(bool binary);
static void CopySendData(void *databuf, int datasize);
static void CopySendString(const char *str);
static void CopySendChar(char c);
static void CopyGetData(void *databuf, int datasize);
static int CopyGetChar(void);
#define CopyGetEof() (fe_eof)
static int CopyPeekChar(void);
static void CopyDonePeek(int c, bool pickup);
/*
* CopySendData sends output data either to the file
* specified by fp or, if fp is NULL, using the standard
* backend->frontend functions
*
* Send copy start/stop messages for frontend copies. These have changed
* in past protocol redesigns.
*/
static void
SendCopyBegin(bool binary)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
pq_putbytes("H", 1); /* new way */
/* XXX grottiness needed for old protocol */
pq_startcopyout();
copy_dest = COPY_NEW_FE;
}
else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
pq_putbytes("H", 1); /* old way */
/* grottiness needed for old protocol */
pq_startcopyout();
copy_dest = COPY_OLD_FE;
}
else
{
pq_putbytes("B", 1); /* very old way */
/* grottiness needed for old protocol */
pq_startcopyout();
copy_dest = COPY_OLD_FE;
}
}
static void
ReceiveCopyBegin(bool binary)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
pq_putbytes("G", 1); /* new way */
copy_dest = COPY_NEW_FE;
copy_msgbuf = makeStringInfo();
}
else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
pq_putbytes("G", 1); /* old way */
copy_dest = COPY_OLD_FE;
}
else
{
pq_putbytes("D", 1); /* very old way */
copy_dest = COPY_OLD_FE;
}
/* We *must* flush here to ensure FE knows it can send. */
pq_flush();
}
static void
SendCopyEnd(bool binary)
{
if (!binary)
CopySendData("\\.\n", 3);
pq_endcopyout(false);
}
/*
* CopySendData sends output data to the destination (file or frontend)
* CopySendString does the same for null-terminated strings
* CopySendChar does the same for single characters
*
* NB: no data conversion is applied by these functions
*/
static void
CopySendData(void *databuf, int datasize, FILE *fp)
CopySendData(void *databuf, int datasize)
{
if (!fp)
switch (copy_dest)
{
if (pq_putbytes((char *) databuf, datasize))
fe_eof = true;
}
else
{
fwrite(databuf, datasize, 1, fp);
if (ferror(fp))
elog(ERROR, "CopySendData: %m");
case COPY_FILE:
fwrite(databuf, datasize, 1, copy_file);
if (ferror(copy_file))
elog(ERROR, "CopySendData: %m");
break;
case COPY_OLD_FE:
if (pq_putbytes((char *) databuf, datasize))
fe_eof = true;
break;
case COPY_NEW_FE:
/* XXX fix later */
if (pq_putbytes((char *) databuf, datasize))
fe_eof = true;
break;
}
}
static void
CopySendString(const char *str, FILE *fp)
CopySendString(const char *str)
{
CopySendData((void *) str, strlen(str), fp);
CopySendData((void *) str, strlen(str));
}
static void
CopySendChar(char c, FILE *fp)
CopySendChar(char c)
{
CopySendData(&c, 1, fp);
CopySendData(&c, 1);
}
/*
* CopyGetData reads output data either from the file
* specified by fp or, if fp is NULL, using the standard
* backend->frontend functions
*
* CopyGetData reads data from the source (file or frontend)
* CopyGetChar does the same for single characters
* CopyGetEof checks if it's EOF on the input (or, check for EOF result
* from CopyGetChar)
*
* CopyGetEof checks if EOF was detected by previous Get operation.
*
* Note: when copying from the frontend, we expect a proper EOF mark per
* protocol; if the frontend simply drops the connection, we raise error.
* It seems unwise to allow the COPY IN to complete normally in that case.
*
* NB: no data conversion is applied by these functions
*/
static void
CopyGetData(void *databuf, int datasize, FILE *fp)
CopyGetData(void *databuf, int datasize)
{
if (!fp)
switch (copy_dest)
{
if (pq_getbytes((char *) databuf, datasize))
fe_eof = true;
case COPY_FILE:
fread(databuf, datasize, 1, copy_file);
if (feof(copy_file))
fe_eof = true;
break;
case COPY_OLD_FE:
if (pq_getbytes((char *) databuf, datasize))
{
/* Only a \. terminator is legal EOF in old protocol */
elog(ERROR, "unexpected EOF on client connection");
}
break;
case COPY_NEW_FE:
while (datasize > 0 && !fe_eof)
{
int avail;
while (copy_msgbuf->cursor >= copy_msgbuf->len)
{
/* Try to receive another message */
int mtype;
mtype = pq_getbyte();
if (mtype == EOF)
elog(ERROR, "unexpected EOF on client connection");
if (pq_getmessage(copy_msgbuf, 0))
elog(ERROR, "unexpected EOF on client connection");
switch (mtype)
{
case 'd': /* CopyData */
break;
case 'c': /* CopyDone */
/* COPY IN correctly terminated by frontend */
fe_eof = true;
return;
case 'f': /* CopyFail */
elog(ERROR, "COPY IN failed: %s",
pq_getmsgstring(copy_msgbuf));
break;
default:
elog(ERROR, "unexpected message type %c during COPY IN",
mtype);
break;
}
}
avail = copy_msgbuf->len - copy_msgbuf->cursor;
if (avail > datasize)
avail = datasize;
pq_copymsgbytes(copy_msgbuf, databuf, avail);
databuf = (void *) ((char *) databuf + avail);
datasize =- avail;
}
break;
}
else
fread(databuf, datasize, 1, fp);
}
static int
CopyGetChar(FILE *fp)
CopyGetChar(void)
{
if (!fp)
int ch;
switch (copy_dest)
{
int ch = pq_getbyte();
case COPY_FILE:
ch = getc(copy_file);
break;
case COPY_OLD_FE:
ch = pq_getbyte();
if (ch == EOF)
{
/* Only a \. terminator is legal EOF in old protocol */
elog(ERROR, "unexpected EOF on client connection");
}
break;
case COPY_NEW_FE:
{
unsigned char cc;
if (ch == EOF)
fe_eof = true;
return ch;
CopyGetData(&cc, 1);
if (fe_eof)
ch = EOF;
else
ch = cc;
break;
}
default:
ch = EOF;
break;
}
else
return getc(fp);
}
static int
CopyGetEof(FILE *fp)
{
if (!fp)
return fe_eof;
else
return feof(fp);
if (ch == EOF)
fe_eof = true;
return ch;
}
/*
@ -200,40 +347,74 @@ CopyGetEof(FILE *fp)
* (if pickup is true) or leave it on the stream (if pickup is false).
*/
static int
CopyPeekChar(FILE *fp)
CopyPeekChar(void)
{
if (!fp)
{
int ch = pq_peekbyte();
int ch;
if (ch == EOF)
fe_eof = true;
return ch;
switch (copy_dest)
{
case COPY_FILE:
ch = getc(copy_file);
break;
case COPY_OLD_FE:
ch = pq_peekbyte();
if (ch == EOF)
{
/* Only a \. terminator is legal EOF in old protocol */
elog(ERROR, "unexpected EOF on client connection");
}
break;
case COPY_NEW_FE:
{
unsigned char cc;
CopyGetData(&cc, 1);
if (fe_eof)
ch = EOF;
else
ch = cc;
break;
}
default:
ch = EOF;
break;
}
else
return getc(fp);
if (ch == EOF)
fe_eof = true;
return ch;
}
static void
CopyDonePeek(FILE *fp, int c, bool pickup)
CopyDonePeek(int c, bool pickup)
{
if (!fp)
if (fe_eof)
return; /* can't unget an EOF */
switch (copy_dest)
{
if (pickup)
{
/* We want to pick it up */
(void) pq_getbyte();
}
/* If we didn't want to pick it up, just leave it where it sits */
}
else
{
if (!pickup)
{
/* We don't want to pick it up - so put it back in there */
ungetc(c, fp);
}
/* If we wanted to pick it up, it's already done */
case COPY_FILE:
if (!pickup)
{
/* We don't want to pick it up - so put it back in there */
ungetc(c, copy_file);
}
/* If we wanted to pick it up, it's already done */
break;
case COPY_OLD_FE:
if (pickup)
{
/* We want to pick it up */
(void) pq_getbyte();
}
/* If we didn't want to pick it up, just leave it where it sits */
break;
case COPY_NEW_FE:
if (!pickup)
{
/* We don't want to pick it up - so put it back in there */
copy_msgbuf->cursor--;
}
/* If we wanted to pick it up, it's already done */
break;
}
}
@ -287,7 +468,6 @@ DoCopy(const CopyStmt *stmt)
bool oids = false;
char *delim = NULL;
char *null_print = NULL;
FILE *fp;
Relation rel;
AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT);
AclResult aclresult;
@ -397,6 +577,11 @@ DoCopy(const CopyStmt *stmt)
client_encoding = pg_get_client_encoding();
server_encoding = GetDatabaseEncoding();
copy_dest = COPY_FILE; /* default */
copy_file = NULL;
copy_msgbuf = NULL;
fe_eof = false;
if (is_from)
{ /* copy from file to database */
if (rel->rd_rel->relkind != RELKIND_RELATION)
@ -414,33 +599,30 @@ DoCopy(const CopyStmt *stmt)
if (pipe)
{
if (IsUnderPostmaster)
{
ReceiveCopyBegin();
fp = NULL;
}
ReceiveCopyBegin(binary);
else
fp = stdin;
copy_file = stdin;
}
else
{
struct stat st;
fp = AllocateFile(filename, PG_BINARY_R);
copy_file = AllocateFile(filename, PG_BINARY_R);
if (fp == NULL)
if (copy_file == NULL)
elog(ERROR, "COPY command, running in backend with "
"effective uid %d, could not open file '%s' for "
"reading. Errno = %s (%d).",
(int) geteuid(), filename, strerror(errno), errno);
fstat(fileno(fp), &st);
fstat(fileno(copy_file), &st);
if (S_ISDIR(st.st_mode))
{
FreeFile(fp);
FreeFile(copy_file);
elog(ERROR, "COPY: %s is a directory", filename);
}
}
CopyFrom(rel, attnumlist, binary, oids, fp, delim, null_print);
CopyFrom(rel, attnumlist, binary, oids, delim, null_print);
}
else
{ /* copy from database to file */
@ -459,13 +641,9 @@ DoCopy(const CopyStmt *stmt)
if (pipe)
{
if (IsUnderPostmaster)
{
SendCopyBegin();
pq_startcopyout();
fp = NULL;
}
SendCopyBegin(binary);
else
fp = stdout;
copy_file = stdout;
}
else
{
@ -481,33 +659,28 @@ DoCopy(const CopyStmt *stmt)
" COPY command");
oumask = umask((mode_t) 022);
fp = AllocateFile(filename, PG_BINARY_W);
copy_file = AllocateFile(filename, PG_BINARY_W);
umask(oumask);
if (fp == NULL)
if (copy_file == NULL)
elog(ERROR, "COPY command, running in backend with "
"effective uid %d, could not open file '%s' for "
"writing. Errno = %s (%d).",
(int) geteuid(), filename, strerror(errno), errno);
fstat(fileno(fp), &st);
fstat(fileno(copy_file), &st);
if (S_ISDIR(st.st_mode))
{
FreeFile(fp);
FreeFile(copy_file);
elog(ERROR, "COPY: %s is a directory", filename);
}
}
CopyTo(rel, attnumlist, binary, oids, fp, delim, null_print);
CopyTo(rel, attnumlist, binary, oids, delim, null_print);
}
if (!pipe)
FreeFile(fp);
else if (!is_from)
{
if (!binary)
CopySendData("\\.\n", 3, fp);
if (IsUnderPostmaster)
pq_endcopyout(false);
}
FreeFile(copy_file);
else if (IsUnderPostmaster && !is_from)
SendCopyEnd(binary);
pfree(attribute_buf.data);
/*
@ -525,7 +698,7 @@ DoCopy(const CopyStmt *stmt)
*/
static void
CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print)
char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
@ -589,18 +762,18 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
int32 tmp;
/* Signature */
CopySendData((char *) BinarySignature, 12, fp);
CopySendData((char *) BinarySignature, 12);
/* Integer layout field */
tmp = 0x01020304;
CopySendData(&tmp, sizeof(int32), fp);
CopySendData(&tmp, sizeof(int32));
/* Flags field */
tmp = 0;
if (oids)
tmp |= (1 << 16);
CopySendData(&tmp, sizeof(int32), fp);
CopySendData(&tmp, sizeof(int32));
/* No header extension */
tmp = 0;
CopySendData(&tmp, sizeof(int32), fp);
CopySendData(&tmp, sizeof(int32));
}
mySnapshot = CopyQuerySnapshot();
@ -621,15 +794,15 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
/* Binary per-tuple header */
int16 fld_count = attr_count;
CopySendData(&fld_count, sizeof(int16), fp);
CopySendData(&fld_count, sizeof(int16));
/* Send OID if wanted --- note fld_count doesn't include it */
if (oids)
{
Oid oid = HeapTupleGetOid(tuple);
fld_size = sizeof(Oid);
CopySendData(&fld_size, sizeof(int16), fp);
CopySendData(&oid, sizeof(Oid), fp);
CopySendData(&fld_size, sizeof(int16));
CopySendData(&oid, sizeof(Oid));
}
}
else
@ -639,7 +812,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
{
string = DatumGetCString(DirectFunctionCall1(oidout,
ObjectIdGetDatum(HeapTupleGetOid(tuple))));
CopySendString(string, fp);
CopySendString(string);
need_delim = true;
}
}
@ -655,7 +828,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
if (!binary)
{
if (need_delim)
CopySendChar(delim[0], fp);
CopySendChar(delim[0]);
need_delim = true;
}
@ -663,12 +836,12 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
{
if (!binary)
{
CopySendString(null_print, fp); /* null indicator */
CopySendString(null_print); /* null indicator */
}
else
{
fld_size = 0; /* null marker */
CopySendData(&fld_size, sizeof(int16), fp);
CopySendData(&fld_size, sizeof(int16));
}
}
else
@ -679,12 +852,12 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
value,
ObjectIdGetDatum(elements[attnum - 1]),
Int32GetDatum(attr[attnum - 1]->atttypmod)));
CopyAttributeOut(fp, string, delim);
CopyAttributeOut(string, delim);
}
else
{
fld_size = attr[attnum - 1]->attlen;
CopySendData(&fld_size, sizeof(int16), fp);
CopySendData(&fld_size, sizeof(int16));
if (isvarlena[attnum - 1])
{
/* varlena */
@ -694,16 +867,14 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
value = PointerGetDatum(PG_DETOAST_DATUM(value));
CopySendData(DatumGetPointer(value),
VARSIZE(value),
fp);
VARSIZE(value));
}
else if (!attr[attnum - 1]->attbyval)
{
/* fixed-length pass-by-reference */
Assert(fld_size > 0);
CopySendData(DatumGetPointer(value),
fld_size,
fp);
fld_size);
}
else
{
@ -717,15 +888,14 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
*/
store_att_byval(&datumBuf, value, fld_size);
CopySendData(&datumBuf,
fld_size,
fp);
fld_size);
}
}
}
}
if (!binary)
CopySendChar('\n', fp);
CopySendChar('\n');
MemoryContextSwitchTo(oldcontext);
}
@ -737,7 +907,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
/* Generate trailer for a binary copy */
int16 fld_count = -1;
CopySendData(&fld_count, sizeof(int16), fp);
CopySendData(&fld_count, sizeof(int16));
}
MemoryContextDelete(mycontext);
@ -753,7 +923,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
*/
static void
CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print)
char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
@ -905,30 +1075,30 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
int32 tmp;
/* Signature */
CopyGetData(readSig, 12, fp);
if (CopyGetEof(fp) || memcmp(readSig, BinarySignature, 12) != 0)
CopyGetData(readSig, 12);
if (CopyGetEof() || memcmp(readSig, BinarySignature, 12) != 0)
elog(ERROR, "COPY BINARY: file signature not recognized");
/* Integer layout field */
CopyGetData(&tmp, sizeof(int32), fp);
if (CopyGetEof(fp) || tmp != 0x01020304)
CopyGetData(&tmp, sizeof(int32));
if (CopyGetEof() || tmp != 0x01020304)
elog(ERROR, "COPY BINARY: incompatible integer layout");
/* Flags field */
CopyGetData(&tmp, sizeof(int32), fp);
if (CopyGetEof(fp))
CopyGetData(&tmp, sizeof(int32));
if (CopyGetEof())
elog(ERROR, "COPY BINARY: bogus file header (missing flags)");
file_has_oids = (tmp & (1 << 16)) != 0;
tmp &= ~(1 << 16);
if ((tmp >> 16) != 0)
elog(ERROR, "COPY BINARY: unrecognized critical flags in header");
/* Header extension length */
CopyGetData(&tmp, sizeof(int32), fp);
if (CopyGetEof(fp) || tmp < 0)
CopyGetData(&tmp, sizeof(int32));
if (CopyGetEof() || tmp < 0)
elog(ERROR, "COPY BINARY: bogus file header (missing length)");
/* Skip extension header, if present */
while (tmp-- > 0)
{
CopyGetData(readSig, 1, fp);
if (CopyGetEof(fp))
CopyGetData(readSig, 1);
if (CopyGetEof())
elog(ERROR, "COPY BINARY: bogus file header (wrong length)");
}
}
@ -936,6 +1106,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
nulls = (char *) palloc(num_phys_attrs * sizeof(char));
/* Initialize static variables */
copy_lineno = 0;
fe_eof = false;
@ -970,7 +1141,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
if (file_has_oids)
{
string = CopyReadAttribute(fp, delim, &result);
string = CopyReadAttribute(delim, &result);
if (result == END_OF_FILE && *string == '\0')
{
@ -1006,7 +1177,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
elog(ERROR, "Missing data for column \"%s\"",
NameStr(attr[m]->attname));
string = CopyReadAttribute(fp, delim, &result);
string = CopyReadAttribute(delim, &result);
if (result == END_OF_FILE && *string == '\0' &&
cur == attnumlist && !file_has_oids)
@ -1051,8 +1222,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
int16 fld_count,
fld_size;
CopyGetData(&fld_count, sizeof(int16), fp);
if (CopyGetEof(fp) || fld_count == -1)
CopyGetData(&fld_count, sizeof(int16));
if (CopyGetEof() || fld_count == -1)
{
done = true;
break;
@ -1064,14 +1235,14 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
if (file_has_oids)
{
CopyGetData(&fld_size, sizeof(int16), fp);
if (CopyGetEof(fp))
CopyGetData(&fld_size, sizeof(int16));
if (CopyGetEof())
elog(ERROR, "COPY BINARY: unexpected EOF");
if (fld_size != (int16) sizeof(Oid))
elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d",
(int) fld_size, (int) sizeof(Oid));
CopyGetData(&loaded_oid, sizeof(Oid), fp);
if (CopyGetEof(fp))
CopyGetData(&loaded_oid, sizeof(Oid));
if (CopyGetEof())
elog(ERROR, "COPY BINARY: unexpected EOF");
if (loaded_oid == InvalidOid)
elog(ERROR, "COPY BINARY: Invalid Oid");
@ -1085,8 +1256,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
i++;
CopyGetData(&fld_size, sizeof(int16), fp);
if (CopyGetEof(fp))
CopyGetData(&fld_size, sizeof(int16));
if (CopyGetEof())
elog(ERROR, "COPY BINARY: unexpected EOF");
if (fld_size == 0)
continue; /* it's NULL; nulls[attnum-1] already set */
@ -1099,17 +1270,16 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
int32 varlena_size;
Pointer varlena_ptr;
CopyGetData(&varlena_size, sizeof(int32), fp);
if (CopyGetEof(fp))
CopyGetData(&varlena_size, sizeof(int32));
if (CopyGetEof())
elog(ERROR, "COPY BINARY: unexpected EOF");
if (varlena_size < (int32) sizeof(int32))
elog(ERROR, "COPY BINARY: bogus varlena length");
varlena_ptr = (Pointer) palloc(varlena_size);
VARATT_SIZEP(varlena_ptr) = varlena_size;
CopyGetData(VARDATA(varlena_ptr),
varlena_size - sizeof(int32),
fp);
if (CopyGetEof(fp))
varlena_size - sizeof(int32));
if (CopyGetEof())
elog(ERROR, "COPY BINARY: unexpected EOF");
values[m] = PointerGetDatum(varlena_ptr);
}
@ -1120,8 +1290,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
Assert(fld_size > 0);
refval_ptr = (Pointer) palloc(fld_size);
CopyGetData(refval_ptr, fld_size, fp);
if (CopyGetEof(fp))
CopyGetData(refval_ptr, fld_size);
if (CopyGetEof())
elog(ERROR, "COPY BINARY: unexpected EOF");
values[m] = PointerGetDatum(refval_ptr);
}
@ -1135,8 +1305,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
* how shorter data values are aligned within a Datum.
*/
Assert(fld_size > 0 && fld_size <= sizeof(Datum));
CopyGetData(&datumBuf, fld_size, fp);
if (CopyGetEof(fp))
CopyGetData(&datumBuf, fld_size);
if (CopyGetEof())
elog(ERROR, "COPY BINARY: unexpected EOF");
values[m] = fetch_att(&datumBuf, true, fld_size);
}
@ -1324,7 +1494,7 @@ GetTypeElement(Oid type)
*/
static char *
CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
CopyReadAttribute(const char *delim, CopyReadResult *result)
{
int c;
int delimc = (unsigned char) delim[0];
@ -1344,7 +1514,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
for (;;)
{
c = CopyGetChar(fp);
c = CopyGetChar();
if (c == EOF)
{
*result = END_OF_FILE;
@ -1359,7 +1529,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
break;
if (c == '\\')
{
c = CopyGetChar(fp);
c = CopyGetChar();
if (c == EOF)
{
*result = END_OF_FILE;
@ -1379,16 +1549,16 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
int val;
val = OCTVALUE(c);
c = CopyPeekChar(fp);
c = CopyPeekChar();
if (ISOCTAL(c))
{
val = (val << 3) + OCTVALUE(c);
CopyDonePeek(fp, c, true /* pick up */ );
c = CopyPeekChar(fp);
CopyDonePeek(c, true /* pick up */ );
c = CopyPeekChar();
if (ISOCTAL(c))
{
val = (val << 3) + OCTVALUE(c);
CopyDonePeek(fp, c, true /* pick up */ );
CopyDonePeek(c, true /* pick up */ );
}
else
{
@ -1397,7 +1567,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
*result = END_OF_FILE;
goto copy_eof;
}
CopyDonePeek(fp, c, false /* put back */ );
CopyDonePeek(c, false /* put back */ );
}
}
else
@ -1407,7 +1577,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
*result = END_OF_FILE;
goto copy_eof;
}
CopyDonePeek(fp, c, false /* put back */ );
CopyDonePeek(c, false /* put back */ );
}
c = val & 0377;
}
@ -1441,9 +1611,21 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
c = '\v';
break;
case '.':
c = CopyGetChar(fp);
c = CopyGetChar();
if (c != '\n')
elog(ERROR, "CopyReadAttribute: end of record marker corrupted");
/*
* In protocol version 3, we should ignore anything after
* \. up to the protocol end of copy data. (XXX maybe
* better not to treat \. as special?)
*/
if (copy_dest == COPY_NEW_FE)
{
while (c != EOF)
{
c = CopyGetChar();
}
}
*result = END_OF_FILE;
goto copy_eof;
}
@ -1458,7 +1640,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
mblen = pg_encoding_mblen(client_encoding, s);
for (j = 1; j < mblen; j++)
{
c = CopyGetChar(fp);
c = CopyGetChar();
if (c == EOF)
{
*result = END_OF_FILE;
@ -1488,7 +1670,7 @@ copy_eof:
}
static void
CopyAttributeOut(FILE *fp, char *server_string, char *delim)
CopyAttributeOut(char *server_string, char *delim)
{
char *string;
char c;
@ -1511,30 +1693,30 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
switch (c)
{
case '\b':
CopySendString("\\b", fp);
CopySendString("\\b");
break;
case '\f':
CopySendString("\\f", fp);
CopySendString("\\f");
break;
case '\n':
CopySendString("\\n", fp);
CopySendString("\\n");
break;
case '\r':
CopySendString("\\r", fp);
CopySendString("\\r");
break;
case '\t':
CopySendString("\\t", fp);
CopySendString("\\t");
break;
case '\v':
CopySendString("\\v", fp);
CopySendString("\\v");
break;
case '\\':
CopySendString("\\\\", fp);
CopySendString("\\\\");
break;
default:
if (c == delimc)
CopySendChar('\\', fp);
CopySendChar(c, fp);
CopySendChar('\\');
CopySendChar(c);
/*
* We can skip pg_encoding_mblen() overhead when encoding
@ -1546,7 +1728,7 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
/* send additional bytes of the char, if any */
mblen = pg_encoding_mblen(client_encoding, string);
for (i = 1; i < mblen; i++)
CopySendChar(string[i], fp);
CopySendChar(string[i]);
}
break;
}