diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-04-19 00:02:30 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-04-19 00:02:30 +0000 |
commit | bd8d4417757b1f3edd9ef36897cf47fe96b6e37a (patch) | |
tree | 82da2e02e8b0b4ae5f3c19370bce7f7e74cd9136 /src/backend/commands/copy.c | |
parent | 54b38d293eb8ab925b3acc7270847fcf35caf912 (diff) | |
download | postgresql-bd8d4417757b1f3edd9ef36897cf47fe96b6e37a.tar.gz postgresql-bd8d4417757b1f3edd9ef36897cf47fe96b6e37a.zip |
Second round of FE/BE protocol changes. Frontend->backend messages now
have length counts, and COPY IN data is packetized into messages.
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r-- | src/backend/commands/copy.c | 560 |
1 files changed, 371 insertions, 189 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 0f20bfb2aea..fd85f48b592 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -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" @@ -50,6 +51,17 @@ #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() */ typedef enum CopyReadResult @@ -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 - * - * CopySendString does the same for null-terminated strings - * CopySendChar does the same for single characters - * - * NB: no data conversion is applied by these functions + * Send copy start/stop messages for frontend copies. These have changed + * in past protocol redesigns. */ static void -CopySendData(void *databuf, int datasize, FILE *fp) +SendCopyBegin(bool binary) { - if (!fp) + 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) { - if (pq_putbytes((char *) databuf, datasize)) - fe_eof = true; + pq_putbytes("H", 1); /* old way */ + /* grottiness needed for old protocol */ + pq_startcopyout(); + copy_dest = COPY_OLD_FE; } else { - fwrite(databuf, datasize, 1, fp); - if (ferror(fp)) - elog(ERROR, "CopySendData: %m"); + pq_putbytes("B", 1); /* very old way */ + /* grottiness needed for old protocol */ + pq_startcopyout(); + copy_dest = COPY_OLD_FE; } } static void -CopySendString(const char *str, FILE *fp) +ReceiveCopyBegin(bool binary) { - CopySendData((void *) str, strlen(str), fp); + 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 -CopySendChar(char c, FILE *fp) +SendCopyEnd(bool binary) { - CopySendData(&c, 1, fp); + if (!binary) + CopySendData("\\.\n", 3); + pq_endcopyout(false); } /* - * CopyGetData reads output data either from the file - * specified by fp or, if fp is NULL, using the standard - * backend->frontend functions - * - * CopyGetChar does the same for single characters - * CopyGetEof checks if it's EOF on the input (or, check for EOF result - * from CopyGetChar) + * 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 -CopyGetData(void *databuf, int datasize, FILE *fp) +CopySendData(void *databuf, int datasize) { - if (!fp) + switch (copy_dest) { - if (pq_getbytes((char *) databuf, datasize)) - fe_eof = true; + 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; } - else - fread(databuf, datasize, 1, fp); } -static int -CopyGetChar(FILE *fp) +static void +CopySendString(const char *str) +{ + CopySendData((void *) str, strlen(str)); +} + +static void +CopySendChar(char c) +{ + CopySendData(&c, 1); +} + +/* + * CopyGetData reads data from the source (file or frontend) + * CopyGetChar does the same for single characters + * + * 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) { - if (!fp) + switch (copy_dest) { - int ch = pq_getbyte(); + 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; - if (ch == EOF) - fe_eof = true; - return ch; + 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 - return getc(fp); } static int -CopyGetEof(FILE *fp) +CopyGetChar(void) { - if (!fp) - return fe_eof; - else - return feof(fp); + int ch; + + switch (copy_dest) + { + 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; + + CopyGetData(&cc, 1); + if (fe_eof) + ch = EOF; + else + ch = cc; + break; + } + default: + ch = EOF; + break; + } + 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; + + switch (copy_dest) { - int ch = pq_peekbyte(); + 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; - 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); + 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 (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 (fe_eof) + return; /* can't unget an EOF */ + switch (copy_dest) { - 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; } |