aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r--src/backend/commands/copy.c205
1 files changed, 154 insertions, 51 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 61151ef6aad..a9e22ec40be 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.65 1998/12/15 12:45:53 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.66 1999/01/11 03:56:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -36,6 +36,7 @@
#include <commands/copy.h>
#include "commands/trigger.h"
#include <storage/fd.h>
+#include <libpq/libpq.h>
#ifdef MULTIBYTE
#include "mb/pg_wchar.h"
@@ -67,11 +68,106 @@ static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim);
static void CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array);
static int CountTuples(Relation relation);
-extern FILE *Pfout,
- *Pfin;
-
static int lineno;
+/*
+ * Internal communications functions
+ */
+inline void CopySendData(void *databuf, int datasize, FILE *fp);
+inline void CopySendString(char *str, FILE *fp);
+inline void CopySendChar(char c, FILE *fp);
+inline void CopyGetData(void *databuf, int datasize, FILE *fp);
+inline int CopyGetChar(FILE *fp);
+inline int CopyGetEof(FILE *fp);
+inline int CopyPeekChar(FILE *fp);
+inline void CopyDonePeek(FILE *fp, int c, int 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
+ */
+inline void CopySendData(void *databuf, int datasize, FILE *fp) {
+ if (!fp)
+ pq_putnchar(databuf, datasize);
+ else
+ fwrite(databuf, datasize, 1, fp);
+}
+
+inline void CopySendString(char *str, FILE *fp) {
+ CopySendData(str,strlen(str),fp);
+}
+
+inline void CopySendChar(char c, FILE *fp) {
+ CopySendData(&c,1,fp);
+}
+
+/*
+ * 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
+ */
+inline void CopyGetData(void *databuf, int datasize, FILE *fp) {
+ if (!fp)
+ pq_getnchar(databuf, 0, datasize);
+ else
+ fread(databuf, datasize, 1, fp);
+}
+
+inline int CopyGetChar(FILE *fp) {
+ if (!fp)
+ return pq_getchar();
+ else
+ return getc(fp);
+}
+
+inline int CopyGetEof(FILE *fp) {
+ if (!fp)
+ return 0; /* Never return EOF when talking to frontend ? */
+ else
+ return feof(fp);
+}
+
+/*
+ * CopyPeekChar reads a byte in "peekable" mode.
+ * after each call to CopyPeekChar, a call to CopyDonePeek _must_
+ * follow.
+ * CopyDonePeek will either take the peeked char off the steam
+ * (if pickup is != 0) or leave it on the stream (if pickup == 0)
+ */
+inline int CopyPeekChar(FILE *fp) {
+ if (!fp)
+ return pq_peekchar();
+ else
+ return getc(fp);
+}
+
+inline void CopyDonePeek(FILE *fp, int c, int pickup) {
+ if (!fp) {
+ if (pickup) {
+ /* We want to pick it up - just receive again into dummy buffer */
+ char c;
+ pq_getnchar(&c, 0, 1);
+ }
+ /* 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 there */
+ }
+}
+
+
+
/*
* DoCopy executes a the SQL COPY statement.
*/
@@ -147,7 +243,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
if (IsUnderPostmaster)
{
ReceiveCopyBegin();
- fp = Pfin;
+ fp = NULL;
}
else
fp = stdin;
@@ -171,7 +267,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
if (IsUnderPostmaster)
{
SendCopyBegin();
- fp = Pfout;
+ fp = NULL;
}
else
fp = stdout;
@@ -199,9 +295,9 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
}
else if (!from && !binary)
{
- fputs("\\.\n", fp);
+ CopySendData("\\.\n",3,fp);
if (IsUnderPostmaster)
- fflush(Pfout);
+ pq_flush();
}
}
}
@@ -269,7 +365,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
/* XXX expensive */
ntuples = CountTuples(rel);
- fwrite(&ntuples, sizeof(int32), 1, fp);
+ CopySendData(&ntuples, sizeof(int32), fp);
}
while (HeapTupleIsValid(tuple = heap_getnext(scandesc, 0)))
@@ -277,8 +373,8 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
if (oids && !binary)
{
- fputs(oidout(tuple->t_data->t_oid), fp);
- fputc(delim[0], fp);
+ CopySendString(oidout(tuple->t_data->t_oid),fp);
+ CopySendChar(delim[0],fp);
}
for (i = 0; i < attr_count; i++)
@@ -294,10 +390,10 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
pfree(string);
}
else
- fputs("\\N", fp); /* null indicator */
+ CopySendString("\\N", fp); /* null indicator */
if (i == attr_count - 1)
- fputc('\n', fp);
+ CopySendChar('\n', fp);
else
{
@@ -305,7 +401,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
* when copying out, only use the first char of the
* delim string
*/
- fputc(delim[0], fp);
+ CopySendChar(delim[0], fp);
}
}
else
@@ -332,24 +428,24 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
}
length = tuple->t_len - tuple->t_data->t_hoff;
- fwrite(&length, sizeof(int32), 1, fp);
+ CopySendData(&length, sizeof(int32), fp);
if (oids)
- fwrite((char *) &tuple->t_data->t_oid, sizeof(int32), 1, fp);
+ CopySendData((char *) &tuple->t_data->t_oid, sizeof(int32), fp);
- fwrite(&null_ct, sizeof(int32), 1, fp);
+ CopySendData(&null_ct, sizeof(int32), fp);
if (null_ct > 0)
{
for (i = 0; i < attr_count; i++)
{
if (nulls[i] == 'n')
{
- fwrite(&i, sizeof(int32), 1, fp);
+ CopySendData(&i, sizeof(int32), fp);
nulls[i] = ' ';
}
}
}
- fwrite((char *) tuple->t_data + tuple->t_data->t_hoff,
- length, 1, fp);
+ CopySendData((char *) tuple->t_data + tuple->t_data->t_hoff,
+ length, fp);
}
}
@@ -527,7 +623,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
in_functions = NULL;
elements = NULL;
typmod = NULL;
- fread(&ntuples, sizeof(int32), 1, fp);
+ CopyGetData(&ntuples, sizeof(int32), fp);
if (ntuples != 0)
reading_to_eof = false;
}
@@ -544,10 +640,12 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
index_nulls[i] = ' ';
byval[i] = (bool) IsTypeByVal(attr[i]->atttypid);
}
+ values = (Datum *) palloc(sizeof(Datum) * attr_count);
lineno = 0;
while (!done)
{
+ values = (Datum *) palloc(sizeof(Datum) * attr_count);
if (!binary)
{
#ifdef COPY_PATCH
@@ -608,29 +706,29 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
}
else
{ /* binary */
- fread(&len, sizeof(int32), 1, fp);
- if (feof(fp))
+ CopyGetData(&len, sizeof(int32), fp);
+ if (CopyGetEof(fp))
done = 1;
else
{
if (oids)
{
- fread(&loaded_oid, sizeof(int32), 1, fp);
+ CopyGetData(&loaded_oid, sizeof(int32), fp);
if (loaded_oid < BootstrapObjectIdData)
elog(ERROR, "COPY BINARY: Invalid Oid line: %d", lineno);
}
- fread(&null_ct, sizeof(int32), 1, fp);
+ CopyGetData(&null_ct, sizeof(int32), fp);
if (null_ct > 0)
{
for (i = 0; i < null_ct; i++)
{
- fread(&null_id, sizeof(int32), 1, fp);
+ CopyGetData(&null_id, sizeof(int32), fp);
nulls[null_id] = 'n';
}
}
string = (char *) palloc(len);
- fread(string, len, 1, fp);
+ CopyGetData(string, len, fp);
ptr = string;
@@ -979,7 +1077,7 @@ CopyReadNewline(FILE *fp, int *newline)
if (!*newline)
{
elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored", lineno);
- while (!feof(fp) && (getc(fp) != '\n'));
+ while (!CopyGetEof(fp) && (CopyGetChar(fp) != '\n'));
}
*newline = 0;
}
@@ -1028,19 +1126,19 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
#endif
*isnull = (bool) false; /* set default */
- if (feof(fp))
+ if (CopyGetEof(fp))
return NULL;
while (!done)
{
- c = getc(fp);
+ c = CopyGetChar(fp);
- if (feof(fp))
+ if (CopyGetEof(fp))
return NULL;
else if (c == '\\')
{
- c = getc(fp);
- if (feof(fp))
+ c = CopyGetChar(fp);
+ if (CopyGetEof(fp))
return NULL;
switch (c)
{
@@ -1056,25 +1154,30 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
int val;
val = VALUE(c);
- c = getc(fp);
+ c = CopyPeekChar(fp);
if (ISOCTAL(c))
{
val = (val << 3) + VALUE(c);
- c = getc(fp);
- if (ISOCTAL(c))
+ CopyDonePeek(fp, c, 1); /* Pick up the character! */
+ c = CopyPeekChar(fp);
+ if (ISOCTAL(c)) {
+ CopyDonePeek(fp,c,1); /* pick up! */
val = (val << 3) + VALUE(c);
+ }
else
{
- if (feof(fp))
+ if (CopyGetEof(fp)) {
+ CopyDonePeek(fp,c,1); /* pick up */
return NULL;
- ungetc(c, fp);
+ }
+ CopyDonePeek(fp,c,0); /* Return to stream! */
}
}
else
{
- if (feof(fp))
+ if (CopyGetEof(fp))
return NULL;
- ungetc(c, fp);
+ CopyDonePeek(fp,c,0); /* Return to stream! */
}
c = val & 0377;
}
@@ -1102,7 +1205,7 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
*isnull = (bool) true;
break;
case '.':
- c = getc(fp);
+ c = CopyGetChar(fp);
if (c != '\n')
elog(ERROR, "CopyReadAttribute - end of record marker corrupted. line: %d", lineno);
return NULL;
@@ -1125,8 +1228,8 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
mblen--;
for (j = 0; j < mblen; j++)
{
- c = getc(fp);
- if (feof(fp))
+ c = CopyGetChar(fp);
+ if (CopyGetEof(fp))
return NULL;
attribute[i++] = c;
}
@@ -1171,29 +1274,29 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim, int is_array)
{
if (c == delim[0] || c == '\n' ||
(c == '\\' && !is_array))
- fputc('\\', fp);
+ CopySendChar('\\', fp);
else if (c == '\\' && is_array)
{
if (*(string + 1) == '\\')
{
/* translate \\ to \\\\ */
- fputc('\\', fp);
- fputc('\\', fp);
- fputc('\\', fp);
+ CopySendChar('\\', fp);
+ CopySendChar('\\', fp);
+ CopySendChar('\\', fp);
string++;
}
else if (*(string + 1) == '"')
{
/* translate \" to \\\" */
- fputc('\\', fp);
- fputc('\\', fp);
+ CopySendChar('\\', fp);
+ CopySendChar('\\', fp);
}
}
#ifdef MULTIBYTE
for (i = 0; i < mblen; i++)
- fputc(*(string + i), fp);
+ CopySendChar(*(string + i), fp);
#else
- fputc(*string, fp);
+ CopySendChar(*string, fp);
#endif
}
}