- 1999-07-20
+ 1999-12-11
COPY [ BINARY ] table [ WITH OIDS ]
FROM { 'filename' | stdin }
[ [USING] DELIMITERS 'delimiter' ]
+ [ WITH NULL AS 'null string' ]
COPY [ BINARY ] table [ WITH OIDS ]
TO { 'filename' | stdout }
[ [USING] DELIMITERS 'delimiter' ]
+ [ WITH NULL AS 'null string' ]
+
+
+ null print
+
+ A string to represent NULL values. The default is
+ \N
(backslash-N), for historical
+ reasons. You might prefer an empty string, for example.
+
+
+ On a copy in, any data item that matches this string will be stored as
+ a NULL value, so you should make sure that you use the same string
+ as you used on copy out.
+
+
+
+
+
encountered before this special end-of-file pattern is found.
- The backslash character has other special meanings. NULL attributes are
- represented as "\N". A literal backslash character is represented as two
+ The backslash character has other special meanings. A literal backslash
+ character is represented as two
consecutive backslashes ("\\"). A literal tab character is represented
as a backslash and a tab. A literal newline character is
represented as a backslash and a newline. When loading text data
not generated by
Postgres,
you will need to convert backslash
characters ("\") to double-backslashes ("\\") to ensure that they are loaded
- properly.
+ properly. (The sequence "\N" will always be interpreted as a backslash and
+ an "N", for compatibility. The more general solution is "\\N".)
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.92 1999/11/27 21:52:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.93 1999/12/14 00:08:13 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* non-export function prototypes */
-static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
-static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
+static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
+static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
static Oid GetOutputFunction(Oid type);
static Oid GetTypeElement(Oid type);
static Oid GetInputFunction(Oid type);
Relation **index_rels);
static void CopyReadNewline(FILE *fp, int *newline);
-static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline);
+static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print);
static void CopyAttributeOut(FILE *fp, char *string, char *delim);
static int CountTuples(Relation relation);
void
DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
- char *filename, char *delim, int fileumask)
+ char *filename, char *delim, char *null_print, int fileumask)
{
/*----------------------------------------------------------------------------
Either unload or reload contents of class , depending on .
Iff , unload or reload in the binary format, as opposed to the
more wasteful but more robust and portable text format.
- If in the text format, delimit columns with delimiter .
+ If in the text format, delimit columns with delimiter and print
+ NULL values as .
is the umask(2) setting to use while creating an output file.
This should usually be more liberal than the backend's normal 077 umask,
"reading. Errno = %s (%d).",
geteuid(), filename, strerror(errno), errno);
}
- CopyFrom(rel, binary, oids, fp, delim);
+ CopyFrom(rel, binary, oids, fp, delim, null_print);
}
else
{ /* copy from database to file */
"writing. Errno = %s (%d).",
geteuid(), filename, strerror(errno), errno);
}
- CopyTo(rel, binary, oids, fp, delim);
+ CopyTo(rel, binary, oids, fp, delim, null_print);
}
if (!pipe)
{
static void
-CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
+CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print)
{
HeapTuple tuple;
HeapScanDesc scandesc;
pfree(string);
}
else
- CopySendString("\\N", fp); /* null indicator */
+ CopySendString(null_print, fp); /* null indicator */
if (i == attr_count - 1)
CopySendChar('\n', fp);
}
static void
-CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
+CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print)
{
HeapTuple tuple;
AttrNumber attr_count;
lineno++;
if (oids)
{
- string = CopyReadAttribute(fp, &isnull, delim, &newline);
+ string = CopyReadAttribute(fp, &isnull, delim, &newline, null_print);
if (string == NULL)
done = 1;
else
}
for (i = 0; i < attr_count && !done; i++)
{
- string = CopyReadAttribute(fp, &isnull, delim, &newline);
+ string = CopyReadAttribute(fp, &isnull, delim, &newline, null_print);
if (isnull)
{
values[i] = PointerGetDatum(NULL);
*
* delim is the string of acceptable delimiter characters(s).
* *newline remembers whether we've seen a newline ending this tuple.
+ * null_print says how NULL values are represented
*/
static char *
-CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline)
+CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print)
{
StringInfoData attribute_buf;
char c;
c = val & 0377;
}
break;
+ /* This is a special hack to parse `\N' as
+ rather then just 'N' to provide compatibility with
+ the default NULL output. -- pe */
+ case 'N':
+ appendStringInfoChar(&attribute_buf, '\\');
+ c = 'N';
+ break;
case 'b':
c = '\b';
break;
case 'v':
c = '\v';
break;
- case 'N':
- *isnull = (bool) true;
- break;
case '.':
c = CopyGetChar(fp);
if (c != '\n')
return cvt;
}
#endif
+ if (strcmp(attribute_buf.data, null_print)==0)
+ *isnull = true;
+
return attribute_buf.data;
endOfFile:
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.121 1999/12/10 07:37:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.122 1999/12/14 00:08:15 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
%type TriggerEvents, TriggerFuncArg
-%type relation_name, copy_file_name, copy_delimiter, def_name,
+%type relation_name, copy_file_name, copy_delimiter, copy_null, def_name,
database_name, access_method_clause, access_method, attr_name,
class, index_name, name, func_name, file_name, aggr_argtype
*
*****************************************************************************/
-CopyStmt: COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter
+CopyStmt: COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null
{
CopyStmt *n = makeNode(CopyStmt);
n->binary = $2;
n->direction = $5;
n->filename = $6;
n->delimiter = $7;
+ n->null_print = $8;
$$ = (Node *)n;
}
;
| /*EMPTY*/ { $$ = TRUE; }
;
+copy_null: WITH NULL_P AS Sconst { $$ = $4; }
+ | /*EMPTY*/ { $$ = "\\N"; }
/*****************************************************************************
*