<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.10 1999/10/29 23:52:20 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.11 1999/12/14 00:08:12 momjian Exp $
Postgres documentation
-->
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
- <date>1999-07-20</date>
+ <date>1999-12-11</date>
</refsynopsisdivinfo>
<synopsis>
COPY [ BINARY ] <replaceable class="parameter">table</replaceable> [ WITH OIDS ]
FROM { '<replaceable class="parameter">filename</replaceable>' | <filename>stdin</filename> }
[ [USING] DELIMITERS '<replaceable class="parameter">delimiter</replaceable>' ]
+ [ WITH NULL AS '<replaceable class="parameter">null string</replaceable>' ]
COPY [ BINARY ] <replaceable class="parameter">table</replaceable> [ WITH OIDS ]
TO { '<replaceable class="parameter">filename</replaceable>' | <filename>stdout</filename> }
[ [USING] DELIMITERS '<replaceable class="parameter">delimiter</replaceable>' ]
+ [ WITH NULL AS '<replaceable class="parameter">null string</replaceable>' ]
</synopsis>
<refsect2 id="R2-SQL-COPY-1">
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">null print</replaceable></term>
+ <listitem>
+ <para>
+ A string to represent NULL values. The default is
+ <quote><literal>\N</literal></quote> (backslash-N), for historical
+ reasons. You might prefer an empty string, for example.
+ </para>
+ <note>
+ <para>
+ 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.
+ </para>
+ </hote>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</refsect2>
encountered before this special end-of-file pattern is found.
</para>
<para>
- 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 <acronym>Postgres</acronym>,
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".)
</para>
</refsect2>
*
*
* 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 <relname>, depending on <from>.
Iff <binary>, 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 <delim>.
+ If in the text format, delimit columns with delimiter <delim> and print
+ NULL values as <null_print>.
<fileumask> 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 <backslash-N>
+ 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 <str> TriggerEvents, TriggerFuncArg
-%type <str> relation_name, copy_file_name, copy_delimiter, def_name,
+%type <str> 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"; }
/*****************************************************************************
*