Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
0e319c7a
Commit
0e319c7a
authored
Sep 29, 2003
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve context display for failures during COPY IN, as recently
discussed on pghackers.
parent
34c64955
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
311 additions
and
210 deletions
+311
-210
src/backend/commands/copy.c
src/backend/commands/copy.c
+302
-201
src/test/regress/expected/alter_table.out
src/test/regress/expected/alter_table.out
+1
-1
src/test/regress/expected/copy2.out
src/test/regress/expected/copy2.out
+4
-4
src/test/regress/expected/domain.out
src/test/regress/expected/domain.out
+3
-3
src/test/regress/output/constraints.source
src/test/regress/output/constraints.source
+1
-1
No files found.
src/backend/commands/copy.c
View file @
0e319c7a
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.21
1 2003/09/25 06:57:58 petere
Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.21
2 2003/09/29 22:06:40 tgl
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -59,22 +59,21 @@
...
@@ -59,22 +59,21 @@
typedef
enum
CopyDest
typedef
enum
CopyDest
{
{
COPY_FILE
,
/* to/from file */
COPY_FILE
,
/* to/from file */
COPY_OLD_FE
,
/* to/from frontend (
old
protocol) */
COPY_OLD_FE
,
/* to/from frontend (
2.0
protocol) */
COPY_NEW_FE
/* to/from frontend (
new
protocol) */
COPY_NEW_FE
/* to/from frontend (
3.0
protocol) */
}
CopyDest
;
}
CopyDest
;
/*
/*
*
Represents the type of data returned by
CopyReadAttribute()
*
State indicator showing what stopped
CopyReadAttribute()
*/
*/
typedef
enum
CopyReadResult
typedef
enum
CopyReadResult
{
{
NORMAL_ATTR
,
NORMAL_ATTR
,
END_OF_LINE
,
END_OF_LINE
END_OF_FILE
}
CopyReadResult
;
}
CopyReadResult
;
/*
/*
* Represents the end-of-line terminator of the input
* Represents the end-of-line terminator
type
of the input
*/
*/
typedef
enum
EolType
typedef
enum
EolType
{
{
...
@@ -85,17 +84,6 @@ typedef enum EolType
...
@@ -85,17 +84,6 @@ typedef enum EolType
}
EolType
;
}
EolType
;
/* non-export function prototypes */
static
void
CopyTo
(
Relation
rel
,
List
*
attnumlist
,
bool
binary
,
bool
oids
,
char
*
delim
,
char
*
null_print
);
static
void
CopyFrom
(
Relation
rel
,
List
*
attnumlist
,
bool
binary
,
bool
oids
,
char
*
delim
,
char
*
null_print
);
static
char
*
CopyReadAttribute
(
const
char
*
delim
,
CopyReadResult
*
result
);
static
Datum
CopyReadBinaryAttribute
(
int
column_no
,
FmgrInfo
*
flinfo
,
Oid
typelem
,
bool
*
isnull
);
static
void
CopyAttributeOut
(
char
*
string
,
char
*
delim
);
static
List
*
CopyGetAttnums
(
Relation
rel
,
List
*
attnamelist
);
static
const
char
BinarySignature
[
11
]
=
"PGCOPY
\n\377\r\n\0
"
;
static
const
char
BinarySignature
[
11
]
=
"PGCOPY
\n\377\r\n\0
"
;
/*
/*
...
@@ -103,11 +91,18 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
...
@@ -103,11 +91,18 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
* never been reentrant...
* never been reentrant...
*/
*/
static
CopyDest
copy_dest
;
static
CopyDest
copy_dest
;
static
FILE
*
copy_file
;
/* if copy_dest == COPY_FILE */
static
FILE
*
copy_file
;
/*
used
if copy_dest == COPY_FILE */
static
StringInfo
copy_msgbuf
;
/* if copy_dest == COPY_NEW_FE */
static
StringInfo
copy_msgbuf
;
/*
used
if copy_dest == COPY_NEW_FE */
static
bool
fe_eof
;
/* true if detected end of copy data */
static
bool
fe_eof
;
/* true if detected end of copy data */
static
EolType
eol_type
;
/* EOL type of input */
static
EolType
eol_type
;
/* EOL type of input */
static
int
client_encoding
;
/* remote side's character encoding */
static
int
server_encoding
;
/* local encoding */
/* these are just for error messages, see copy_in_error_callback */
static
bool
copy_binary
;
/* is it a binary copy? */
static
const
char
*
copy_relname
;
/* table name for error messages */
static
int
copy_lineno
;
/* line number for error messages */
static
int
copy_lineno
;
/* line number for error messages */
static
const
char
*
copy_attname
;
/* current att for error messages */
/*
/*
...
@@ -117,16 +112,34 @@ static int copy_lineno; /* line number for error messages */
...
@@ -117,16 +112,34 @@ static int copy_lineno; /* line number for error messages */
* grow to a suitable size, and then we will avoid palloc/pfree overhead
* grow to a suitable size, and then we will avoid palloc/pfree overhead
* for subsequent attributes. Note that CopyReadAttribute returns a pointer
* for subsequent attributes. Note that CopyReadAttribute returns a pointer
* to attribute_buf's data buffer!
* to attribute_buf's data buffer!
* encoding, if needed, can be set once at the start of the copy operation.
*/
*/
static
StringInfoData
attribute_buf
;
static
StringInfoData
attribute_buf
;
static
int
client_encoding
;
static
int
server_encoding
;
/*
/*
* Internal communications functions
* Similarly, line_buf holds the whole input line being processed (its
* cursor field points to the next character to be read by CopyReadAttribute).
* The input cycle is first to read the whole line into line_buf, convert it
* to server encoding, and then extract individual attribute fields into
* attribute_buf. (We used to have CopyReadAttribute read the input source
* directly, but that caused a lot of encoding issues and unnecessary logic
* complexity).
*/
*/
static
StringInfoData
line_buf
;
static
bool
line_buf_converted
;
/* non-export function prototypes */
static
void
CopyTo
(
Relation
rel
,
List
*
attnumlist
,
bool
binary
,
bool
oids
,
char
*
delim
,
char
*
null_print
);
static
void
CopyFrom
(
Relation
rel
,
List
*
attnumlist
,
bool
binary
,
bool
oids
,
char
*
delim
,
char
*
null_print
);
static
bool
CopyReadLine
(
void
);
static
char
*
CopyReadAttribute
(
const
char
*
delim
,
CopyReadResult
*
result
);
static
Datum
CopyReadBinaryAttribute
(
int
column_no
,
FmgrInfo
*
flinfo
,
Oid
typelem
,
bool
*
isnull
);
static
void
CopyAttributeOut
(
char
*
string
,
char
*
delim
);
static
List
*
CopyGetAttnums
(
Relation
rel
,
List
*
attnamelist
);
/* Internal communications functions */
static
void
SendCopyBegin
(
bool
binary
,
int
natts
);
static
void
SendCopyBegin
(
bool
binary
,
int
natts
);
static
void
ReceiveCopyBegin
(
bool
binary
,
int
natts
);
static
void
ReceiveCopyBegin
(
bool
binary
,
int
natts
);
static
void
SendCopyEnd
(
bool
binary
);
static
void
SendCopyEnd
(
bool
binary
);
...
@@ -145,6 +158,7 @@ static int32 CopyGetInt32(void);
...
@@ -145,6 +158,7 @@ static int32 CopyGetInt32(void);
static
void
CopySendInt16
(
int16
val
);
static
void
CopySendInt16
(
int16
val
);
static
int16
CopyGetInt16
(
void
);
static
int16
CopyGetInt16
(
void
);
/*
/*
* Send copy start/stop messages for frontend copies. These have changed
* Send copy start/stop messages for frontend copies. These have changed
* in past protocol redesigns.
* in past protocol redesigns.
...
@@ -780,6 +794,8 @@ DoCopy(const CopyStmt *stmt)
...
@@ -780,6 +794,8 @@ DoCopy(const CopyStmt *stmt)
* Set up variables to avoid per-attribute overhead.
* Set up variables to avoid per-attribute overhead.
*/
*/
initStringInfo
(
&
attribute_buf
);
initStringInfo
(
&
attribute_buf
);
initStringInfo
(
&
line_buf
);
line_buf_converted
=
false
;
client_encoding
=
pg_get_client_encoding
();
client_encoding
=
pg_get_client_encoding
();
server_encoding
=
GetDatabaseEncoding
();
server_encoding
=
GetDatabaseEncoding
();
...
@@ -907,6 +923,7 @@ DoCopy(const CopyStmt *stmt)
...
@@ -907,6 +923,7 @@ DoCopy(const CopyStmt *stmt)
else
if
(
IsUnderPostmaster
&&
!
is_from
)
else
if
(
IsUnderPostmaster
&&
!
is_from
)
SendCopyEnd
(
binary
);
SendCopyEnd
(
binary
);
pfree
(
attribute_buf
.
data
);
pfree
(
attribute_buf
.
data
);
pfree
(
line_buf
.
data
);
/*
/*
* Close the relation. If reading, we can release the AccessShareLock
* Close the relation. If reading, we can release the AccessShareLock
...
@@ -1111,7 +1128,55 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1111,7 +1128,55 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
static
void
static
void
copy_in_error_callback
(
void
*
arg
)
copy_in_error_callback
(
void
*
arg
)
{
{
errcontext
(
"COPY FROM, line %d"
,
copy_lineno
);
#define MAX_COPY_DATA_DISPLAY 100
if
(
copy_binary
)
{
/* can't usefully display the data */
if
(
copy_attname
)
errcontext
(
"COPY %s, line %d, column %s"
,
copy_relname
,
copy_lineno
,
copy_attname
);
else
errcontext
(
"COPY %s, line %d"
,
copy_relname
,
copy_lineno
);
}
else
{
if
(
copy_attname
)
{
/* error is relevant to a particular column */
errcontext
(
"COPY %s, line %d, column %s:
\"
%.*s%s
\"
"
,
copy_relname
,
copy_lineno
,
copy_attname
,
MAX_COPY_DATA_DISPLAY
,
attribute_buf
.
data
,
(
attribute_buf
.
len
>
MAX_COPY_DATA_DISPLAY
)
?
"..."
:
""
);
}
else
{
/* error is relevant to a particular line */
if
(
!
line_buf_converted
)
{
/* didn't convert the encoding yet... */
if
(
client_encoding
!=
server_encoding
)
{
char
*
cvt
;
cvt
=
(
char
*
)
pg_client_to_server
((
unsigned
char
*
)
line_buf
.
data
,
line_buf
.
len
);
if
(
cvt
!=
line_buf
.
data
)
{
/* transfer converted data back to line_buf */
line_buf
.
len
=
0
;
line_buf
.
data
[
0
]
=
'\0'
;
appendBinaryStringInfo
(
&
line_buf
,
cvt
,
strlen
(
cvt
));
}
}
line_buf_converted
=
true
;
}
errcontext
(
"COPY %s, line %d:
\"
%.*s%s
\"
"
,
copy_relname
,
copy_lineno
,
MAX_COPY_DATA_DISPLAY
,
line_buf
.
data
,
(
line_buf
.
len
>
MAX_COPY_DATA_DISPLAY
)
?
"..."
:
""
);
}
}
}
}
...
@@ -1327,7 +1392,10 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1327,7 +1392,10 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
/* Initialize static variables */
/* Initialize static variables */
fe_eof
=
false
;
fe_eof
=
false
;
eol_type
=
EOL_UNKNOWN
;
eol_type
=
EOL_UNKNOWN
;
copy_binary
=
binary
;
copy_relname
=
RelationGetRelationName
(
rel
);
copy_lineno
=
0
;
copy_lineno
=
0
;
copy_attname
=
NULL
;
/* Set up callback to identify error line number */
/* Set up callback to identify error line number */
errcontext
.
callback
=
copy_in_error_callback
;
errcontext
.
callback
=
copy_in_error_callback
;
...
@@ -1359,29 +1427,36 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1359,29 +1427,36 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
CopyReadResult
result
=
NORMAL_ATTR
;
CopyReadResult
result
=
NORMAL_ATTR
;
char
*
string
;
char
*
string
;
/* Actually read the line into memory here */
done
=
CopyReadLine
();
/*
* EOF at start of line means we're done. If we see EOF
* after some characters, we act as though it was newline
* followed by EOF, ie, process the line and then exit loop
* on next iteration.
*/
if
(
done
&&
line_buf
.
len
==
0
)
break
;
if
(
file_has_oids
)
if
(
file_has_oids
)
{
{
string
=
CopyReadAttribute
(
delim
,
&
result
);
string
=
CopyReadAttribute
(
delim
,
&
result
);
if
(
result
==
END_OF_FILE
&&
*
string
==
'\0'
)
{
/* EOF at start of line: all is well */
done
=
true
;
break
;
}
if
(
strcmp
(
string
,
null_print
)
==
0
)
if
(
strcmp
(
string
,
null_print
)
==
0
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"null OID in COPY data"
)));
errmsg
(
"null OID in COPY data"
)));
else
else
{
{
copy_attname
=
"oid"
;
loaded_oid
=
DatumGetObjectId
(
DirectFunctionCall1
(
oidin
,
loaded_oid
=
DatumGetObjectId
(
DirectFunctionCall1
(
oidin
,
CStringGetDatum
(
string
)));
CStringGetDatum
(
string
)));
if
(
loaded_oid
==
InvalidOid
)
if
(
loaded_oid
==
InvalidOid
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"invalid OID in COPY data"
)));
errmsg
(
"invalid OID in COPY data"
)));
copy_attname
=
NULL
;
}
}
}
}
...
@@ -1394,7 +1469,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1394,7 +1469,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
int
m
=
attnum
-
1
;
int
m
=
attnum
-
1
;
/*
/*
* If prior attr on this line was ended by newline
or EOF
,
* If prior attr on this line was ended by newline,
* complain.
* complain.
*/
*/
if
(
result
!=
NORMAL_ATTR
)
if
(
result
!=
NORMAL_ATTR
)
...
@@ -1405,69 +1480,34 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1405,69 +1480,34 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
string
=
CopyReadAttribute
(
delim
,
&
result
);
string
=
CopyReadAttribute
(
delim
,
&
result
);
if
(
result
==
END_OF_FILE
&&
*
string
==
'\0'
&&
cur
==
attnumlist
&&
!
file_has_oids
)
{
/* EOF at start of line: all is well */
done
=
true
;
break
;
/* out of per-attr loop */
}
if
(
strcmp
(
string
,
null_print
)
==
0
)
if
(
strcmp
(
string
,
null_print
)
==
0
)
{
{
/* we read an SQL NULL, no need to do anything */
/* we read an SQL NULL, no need to do anything */
}
}
else
else
{
{
copy_attname
=
NameStr
(
attr
[
m
]
->
attname
);
values
[
m
]
=
FunctionCall3
(
&
in_functions
[
m
],
values
[
m
]
=
FunctionCall3
(
&
in_functions
[
m
],
CStringGetDatum
(
string
),
CStringGetDatum
(
string
),
ObjectIdGetDatum
(
elements
[
m
]),
ObjectIdGetDatum
(
elements
[
m
]),
Int32GetDatum
(
attr
[
m
]
->
atttypmod
));
Int32GetDatum
(
attr
[
m
]
->
atttypmod
));
nulls
[
m
]
=
' '
;
nulls
[
m
]
=
' '
;
copy_attname
=
NULL
;
}
}
}
}
if
(
done
)
break
;
/* out of per-row loop */
/*
/*
* Complain if there are more fields on the input line.
* Complain if there are more fields on the input line.
*
*
* Special case: if we're reading a zero-column table, we won't
* Special case: if we're reading a zero-column table, we won't
* yet have called CopyReadAttribute() at all; so do that and
* yet have called CopyReadAttribute() at all; so no error if
* check we have an empty line. Fortunately we can keep that
* line is empty.
* silly corner case out of the main line of execution.
*/
*/
if
(
result
==
NORMAL_ATTR
)
if
(
result
==
NORMAL_ATTR
&&
line_buf
.
len
!=
0
)
{
if
(
attnumlist
==
NIL
&&
!
file_has_oids
)
{
string
=
CopyReadAttribute
(
delim
,
&
result
);
if
(
result
==
NORMAL_ATTR
||
*
string
!=
'\0'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"extra data after last expected column"
)));
if
(
result
==
END_OF_FILE
)
{
/* EOF at start of line: all is well */
done
=
true
;
break
;
}
}
else
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"extra data after last expected column"
)));
errmsg
(
"extra data after last expected column"
)));
}
}
/*
* If we got some data on the line, but it was ended by EOF,
* process the line normally but set flag to exit the loop
* when we return to the top.
*/
if
(
result
==
END_OF_FILE
)
done
=
true
;
}
else
else
{
{
/* binary */
/* binary */
...
@@ -1488,6 +1528,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1488,6 +1528,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
if
(
file_has_oids
)
if
(
file_has_oids
)
{
{
copy_attname
=
"oid"
;
loaded_oid
=
loaded_oid
=
DatumGetObjectId
(
CopyReadBinaryAttribute
(
0
,
DatumGetObjectId
(
CopyReadBinaryAttribute
(
0
,
&
oid_in_function
,
&
oid_in_function
,
...
@@ -1497,6 +1538,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1497,6 +1538,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"invalid OID in COPY data"
)));
errmsg
(
"invalid OID in COPY data"
)));
copy_attname
=
NULL
;
}
}
i
=
0
;
i
=
0
;
...
@@ -1505,12 +1547,14 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1505,12 +1547,14 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
int
attnum
=
lfirsti
(
cur
);
int
attnum
=
lfirsti
(
cur
);
int
m
=
attnum
-
1
;
int
m
=
attnum
-
1
;
copy_attname
=
NameStr
(
attr
[
m
]
->
attname
);
i
++
;
i
++
;
values
[
m
]
=
CopyReadBinaryAttribute
(
i
,
values
[
m
]
=
CopyReadBinaryAttribute
(
i
,
&
in_functions
[
m
],
&
in_functions
[
m
],
elements
[
m
],
elements
[
m
],
&
isnull
);
&
isnull
);
nulls
[
m
]
=
isnull
?
'n'
:
' '
;
nulls
[
m
]
=
isnull
?
'n'
:
' '
;
copy_attname
=
NULL
;
}
}
}
}
...
@@ -1642,46 +1686,53 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
...
@@ -1642,46 +1686,53 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
/*
/*
* Read the value of a single attribute.
* Read the next input line and stash it in line_buf, with conversion to
*
* server encoding.
* *result is set to indicate what terminated the read:
* NORMAL_ATTR: column delimiter
* END_OF_LINE: newline
* END_OF_FILE: EOF indicator
* In all cases, the string read up to the terminator is returned.
*
* Note: This function does not care about SQL NULL values -- it
* is the caller's responsibility to check if the returned string
* matches what the user specified for the SQL NULL value.
*
*
* delim is the column delimiter string.
* Result is true if read was terminated by EOF, false if terminated
* by newline.
*/
*/
static
char
*
static
bool
CopyRead
Attribute
(
const
char
*
delim
,
CopyReadResult
*
result
)
CopyRead
Line
(
void
)
{
{
bool
result
;
bool
change_encoding
=
(
client_encoding
!=
server_encoding
);
int
c
;
int
c
;
int
delimc
=
(
unsigned
char
)
delim
[
0
];
int
mblen
;
int
mblen
;
int
j
;
unsigned
char
s
[
2
];
unsigned
char
s
[
2
];
char
*
cvt
;
char
*
cvt
;
int
j
;
s
[
1
]
=
0
;
s
[
1
]
=
0
;
/* reset attribute_buf to empty */
/* reset line_buf to empty */
attribute_buf
.
len
=
0
;
line_buf
.
len
=
0
;
attribute_buf
.
data
[
0
]
=
'\0'
;
line_buf
.
data
[
0
]
=
'\0'
;
line_buf
.
cursor
=
0
;
/* mark that encoding conversion hasn't occurred yet */
line_buf_converted
=
false
;
/* set default status */
/* set default status */
*
result
=
NORMAL_ATTR
;
result
=
false
;
/*
* In this loop we only care for detecting newlines (\r and/or \n)
* and the end-of-copy marker (\.). For backwards compatibility
* we allow backslashes to escape newline characters. Backslashes
* other than the end marker get put into the line_buf, since
* CopyReadAttribute does its own escape processing. These four
* characters, and only these four, are assumed the same in frontend
* and backend encodings. We do not assume that second and later bytes
* of a frontend multibyte character couldn't look like ASCII characters.
*/
for
(;;)
for
(;;)
{
{
c
=
CopyGetChar
();
c
=
CopyGetChar
();
if
(
c
==
EOF
)
if
(
c
==
EOF
)
{
{
*
result
=
END_OF_FILE
;
result
=
true
;
goto
copy_eof
;
break
;
}
}
if
(
c
==
'\r'
)
if
(
c
==
'\r'
)
{
{
...
@@ -1691,7 +1742,7 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
...
@@ -1691,7 +1742,7 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
errmsg
(
"literal carriage return found in data"
),
errmsg
(
"literal carriage return found in data"
),
errhint
(
"Use
\"\\
r
\"
to represent carriage return."
)));
errhint
(
"Use
\"\\
r
\"
to represent carriage return."
)));
/* Check for \r\n on first line, _and_ handle \r\n. */
/* Check for \r\n on first line, _and_ handle \r\n. */
if
(
copy_lineno
==
1
||
eol_type
==
EOL_CRNL
)
if
(
eol_type
==
EOL_UNKNOWN
||
eol_type
==
EOL_CRNL
)
{
{
int
c2
=
CopyPeekChar
();
int
c2
=
CopyPeekChar
();
...
@@ -1717,7 +1768,6 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
...
@@ -1717,7 +1768,6 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
eol_type
=
EOL_CR
;
eol_type
=
EOL_CR
;
}
}
}
}
*
result
=
END_OF_LINE
;
break
;
break
;
}
}
if
(
c
==
'\n'
)
if
(
c
==
'\n'
)
...
@@ -1728,19 +1778,150 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
...
@@ -1728,19 +1778,150 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
errmsg
(
"literal newline found in data"
),
errmsg
(
"literal newline found in data"
),
errhint
(
"Use
\"\\
n
\"
to represent newline."
)));
errhint
(
"Use
\"\\
n
\"
to represent newline."
)));
eol_type
=
EOL_NL
;
eol_type
=
EOL_NL
;
*
result
=
END_OF_LINE
;
break
;
break
;
}
}
if
(
c
==
delimc
)
break
;
if
(
c
==
'\\'
)
if
(
c
==
'\\'
)
{
{
c
=
CopyGetChar
();
c
=
CopyGetChar
();
if
(
c
==
EOF
)
if
(
c
==
EOF
)
{
{
*
result
=
END_OF_FILE
;
result
=
true
;
goto
copy_eof
;
break
;
}
if
(
c
==
'.'
)
{
if
(
eol_type
==
EOL_CRNL
)
{
c
=
CopyGetChar
();
if
(
c
==
'\n'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker does not match previous newline style"
)));
if
(
c
!=
'\r'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker corrupt"
)));
}
c
=
CopyGetChar
();
if
(
c
!=
'\r'
&&
c
!=
'\n'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker corrupt"
)));
if
((
eol_type
==
EOL_NL
&&
c
!=
'\n'
)
||
(
eol_type
==
EOL_CRNL
&&
c
!=
'\n'
)
||
(
eol_type
==
EOL_CR
&&
c
!=
'\r'
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker does not match previous newline style"
)));
/*
* 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
=
true
;
/* report EOF */
break
;
}
/* not EOF mark, so emit \ and following char literally */
appendStringInfoCharMacro
(
&
line_buf
,
'\\'
);
}
appendStringInfoCharMacro
(
&
line_buf
,
c
);
/*
* When client encoding != server, must be careful to read the
* extra bytes of a multibyte character exactly, since the encoding
* might not ensure they don't look like ASCII. When the encodings
* are the same, we need not do this, since no server encoding we
* use has ASCII-like following bytes.
*/
if
(
change_encoding
)
{
s
[
0
]
=
c
;
mblen
=
pg_encoding_mblen
(
client_encoding
,
s
);
for
(
j
=
1
;
j
<
mblen
;
j
++
)
{
c
=
CopyGetChar
();
if
(
c
==
EOF
)
{
result
=
true
;
break
;
}
appendStringInfoCharMacro
(
&
line_buf
,
c
);
}
if
(
result
)
break
;
/* out of outer loop */
}
}
/* end of outer loop */
/*
* Done reading the line. Convert it to server encoding.
*/
if
(
change_encoding
)
{
cvt
=
(
char
*
)
pg_client_to_server
((
unsigned
char
*
)
line_buf
.
data
,
line_buf
.
len
);
if
(
cvt
!=
line_buf
.
data
)
{
/* transfer converted data back to line_buf */
line_buf
.
len
=
0
;
line_buf
.
data
[
0
]
=
'\0'
;
appendBinaryStringInfo
(
&
line_buf
,
cvt
,
strlen
(
cvt
));
}
}
line_buf_converted
=
true
;
return
result
;
}
/*
* Read the value of a single attribute, performing de-escaping as needed.
*
* *result is set to indicate what terminated the read:
* NORMAL_ATTR: column delimiter
* END_OF_LINE: end of line
* In either case, the string read up to the terminator is returned.
*
* Note: This function does not care about SQL NULL values -- it
* is the caller's responsibility to check if the returned string
* matches what the user specified for the SQL NULL value.
*
* delim is the column delimiter string.
*/
static
char
*
CopyReadAttribute
(
const
char
*
delim
,
CopyReadResult
*
result
)
{
char
c
;
char
delimc
=
delim
[
0
];
/* reset attribute_buf to empty */
attribute_buf
.
len
=
0
;
attribute_buf
.
data
[
0
]
=
'\0'
;
/* set default status */
*
result
=
END_OF_LINE
;
for
(;;)
{
if
(
line_buf
.
cursor
>=
line_buf
.
len
)
break
;
c
=
line_buf
.
data
[
line_buf
.
cursor
++
];
if
(
c
==
delimc
)
{
*
result
=
NORMAL_ATTR
;
break
;
}
}
if
(
c
==
'\\'
)
{
if
(
line_buf
.
cursor
>=
line_buf
.
len
)
break
;
c
=
line_buf
.
data
[
line_buf
.
cursor
++
];
switch
(
c
)
switch
(
c
)
{
{
case
'0'
:
case
'0'
:
...
@@ -1755,36 +1936,24 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
...
@@ -1755,36 +1936,24 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
int
val
;
int
val
;
val
=
OCTVALUE
(
c
);
val
=
OCTVALUE
(
c
);
c
=
CopyPeekChar
();
if
(
line_buf
.
cursor
<
line_buf
.
len
)
{
c
=
line_buf
.
data
[
line_buf
.
cursor
];
if
(
ISOCTAL
(
c
))
if
(
ISOCTAL
(
c
))
{
{
line_buf
.
cursor
++
;
val
=
(
val
<<
3
)
+
OCTVALUE
(
c
);
val
=
(
val
<<
3
)
+
OCTVALUE
(
c
);
CopyDonePeek
(
c
,
true
/* pick up */
);
if
(
line_buf
.
cursor
<
line_buf
.
len
)
c
=
CopyPeekChar
();
{
c
=
line_buf
.
data
[
line_buf
.
cursor
];
if
(
ISOCTAL
(
c
))
if
(
ISOCTAL
(
c
))
{
{
line_buf
.
cursor
++
;
val
=
(
val
<<
3
)
+
OCTVALUE
(
c
);
val
=
(
val
<<
3
)
+
OCTVALUE
(
c
);
CopyDonePeek
(
c
,
true
/* pick up */
);
}
}
else
{
if
(
c
==
EOF
)
{
*
result
=
END_OF_FILE
;
goto
copy_eof
;
}
}
CopyDonePeek
(
c
,
false
/* put back */
);
}
}
}
}
else
{
if
(
c
==
EOF
)
{
*
result
=
END_OF_FILE
;
goto
copy_eof
;
}
CopyDonePeek
(
c
,
false
/* put back */
);
}
c
=
val
&
0377
;
c
=
val
&
0377
;
}
}
break
;
break
;
...
@@ -1816,79 +1985,12 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
...
@@ -1816,79 +1985,12 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
case
'v'
:
case
'v'
:
c
=
'\v'
;
c
=
'\v'
;
break
;
break
;
case
'.'
:
if
(
eol_type
==
EOL_CRNL
)
{
c
=
CopyGetChar
();
if
(
c
==
'\n'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker does not match previous newline style"
)));
if
(
c
!=
'\r'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker corrupt"
)));
}
c
=
CopyGetChar
();
if
(
c
!=
'\r'
&&
c
!=
'\n'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker corrupt"
)));
if
((
eol_type
==
EOL_NL
&&
c
!=
'\n'
)
||
(
eol_type
==
EOL_CRNL
&&
c
!=
'\n'
)
||
(
eol_type
==
EOL_CR
&&
c
!=
'\r'
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"end-of-copy marker does not match previous newline style"
)));
/*
/*
* In protocol version 3, we should ignore anything
* in all other cases, take the char after '\' literally
* 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
;
}
}
}
}
appendStringInfoCharMacro
(
&
attribute_buf
,
c
);
appendStringInfoCharMacro
(
&
attribute_buf
,
c
);
/* XXX shouldn't this be done even when encoding is the same? */
if
(
client_encoding
!=
server_encoding
)
{
/* get additional bytes of the char, if any */
s
[
0
]
=
c
;
mblen
=
pg_encoding_mblen
(
client_encoding
,
s
);
for
(
j
=
1
;
j
<
mblen
;
j
++
)
{
c
=
CopyGetChar
();
if
(
c
==
EOF
)
{
*
result
=
END_OF_FILE
;
goto
copy_eof
;
}
appendStringInfoCharMacro
(
&
attribute_buf
,
c
);
}
}
}
copy_eof:
if
(
client_encoding
!=
server_encoding
)
{
cvt
=
(
char
*
)
pg_client_to_server
((
unsigned
char
*
)
attribute_buf
.
data
,
attribute_buf
.
len
);
if
(
cvt
!=
attribute_buf
.
data
)
{
/* transfer converted data back to attribute_buf */
attribute_buf
.
len
=
0
;
attribute_buf
.
data
[
0
]
=
'\0'
;
appendBinaryStringInfo
(
&
attribute_buf
,
cvt
,
strlen
(
cvt
));
}
}
}
return
attribute_buf
.
data
;
return
attribute_buf
.
data
;
...
@@ -1917,7 +2019,7 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,
...
@@ -1917,7 +2019,7 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,
if
(
fld_size
<
0
)
if
(
fld_size
<
0
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
(
errcode
(
ERRCODE_BAD_COPY_FILE_FORMAT
),
errmsg
(
"invalid
size for field %d"
,
column_no
)));
errmsg
(
"invalid
field size"
)));
/* reset attribute_buf to empty, and load raw data in it */
/* reset attribute_buf to empty, and load raw data in it */
attribute_buf
.
len
=
0
;
attribute_buf
.
len
=
0
;
...
@@ -1944,8 +2046,7 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,
...
@@ -1944,8 +2046,7 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,
if
(
attribute_buf
.
cursor
!=
attribute_buf
.
len
)
if
(
attribute_buf
.
cursor
!=
attribute_buf
.
len
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_INVALID_BINARY_REPRESENTATION
),
(
errcode
(
ERRCODE_INVALID_BINARY_REPRESENTATION
),
errmsg
(
"incorrect binary data format in field %d"
,
errmsg
(
"incorrect binary data format"
)));
column_no
)));
*
isnull
=
false
;
*
isnull
=
false
;
return
result
;
return
result
;
...
...
src/test/regress/expected/alter_table.out
View file @
0e319c7a
...
@@ -998,7 +998,7 @@ copy test("........pg.dropped.1........") to stdout;
...
@@ -998,7 +998,7 @@ copy test("........pg.dropped.1........") to stdout;
ERROR: column "........pg.dropped.1........" of relation "test" does not exist
ERROR: column "........pg.dropped.1........" of relation "test" does not exist
copy test from stdin;
copy test from stdin;
ERROR: extra data after last expected column
ERROR: extra data after last expected column
CONTEXT: COPY
FROM, line 1
CONTEXT: COPY
test, line 1: "10 11 12"
select * from test;
select * from test;
b | c
b | c
---+---
---+---
...
...
src/test/regress/expected/copy2.out
View file @
0e319c7a
...
@@ -35,17 +35,17 @@ ERROR: column "d" specified more than once
...
@@ -35,17 +35,17 @@ ERROR: column "d" specified more than once
-- missing data: should fail
-- missing data: should fail
COPY x from stdin;
COPY x from stdin;
ERROR: invalid input syntax for integer: ""
ERROR: invalid input syntax for integer: ""
CONTEXT: COPY
FROM, line 1
CONTEXT: COPY
x, line 1, column a: ""
COPY x from stdin;
COPY x from stdin;
ERROR: missing data for column "e"
ERROR: missing data for column "e"
CONTEXT: COPY
FROM, line 1
CONTEXT: COPY
x, line 1: "2000 230 23 23"
COPY x from stdin;
COPY x from stdin;
ERROR: missing data for column "e"
ERROR: missing data for column "e"
CONTEXT: COPY
FROM, line 1
CONTEXT: COPY
x, line 1: "2001 231 \N \N"
-- extra data: should fail
-- extra data: should fail
COPY x from stdin;
COPY x from stdin;
ERROR: extra data after last expected column
ERROR: extra data after last expected column
CONTEXT: COPY
FROM, line 1
CONTEXT: COPY
x, line 1: "2002 232 40 50 60 70 80"
-- various COPY options: delimiters, oids, NULL string
-- various COPY options: delimiters, oids, NULL string
COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x';
COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x';
-- check results of copy in
-- check results of copy in
...
...
src/test/regress/expected/domain.out
View file @
0e319c7a
...
@@ -40,7 +40,7 @@ INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate
...
@@ -40,7 +40,7 @@ INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate
-- Test copy
-- Test copy
COPY basictest (testvarchar) FROM stdin; -- fail
COPY basictest (testvarchar) FROM stdin; -- fail
ERROR: value too long for type character varying(5)
ERROR: value too long for type character varying(5)
CONTEXT: COPY
FROM, line 1
CONTEXT: COPY
basictest, line 1: "notsoshorttext"
COPY basictest (testvarchar) FROM stdin;
COPY basictest (testvarchar) FROM stdin;
select * from basictest;
select * from basictest;
testint4 | testtext | testvarchar | testnumeric
testint4 | testtext | testvarchar | testnumeric
...
@@ -127,11 +127,11 @@ INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
...
@@ -127,11 +127,11 @@ INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
-- Test copy
-- Test copy
COPY nulltest FROM stdin; --fail
COPY nulltest FROM stdin; --fail
ERROR: domain dcheck does not allow null values
ERROR: domain dcheck does not allow null values
CONTEXT: COPY
FROM, line 1
CONTEXT: COPY
nulltest, line 1: "a b \N d \N"
-- Last row is bad
-- Last row is bad
COPY nulltest FROM stdin;
COPY nulltest FROM stdin;
ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5"
ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5"
CONTEXT: COPY
FROM, line 3
CONTEXT: COPY
nulltest, line 3: "a b c \N a"
select * from nulltest;
select * from nulltest;
col1 | col2 | col3 | col4 | col5
col1 | col2 | col3 | col4 | col5
------+------+------+------+------
------+------+------+------+------
...
...
src/test/regress/output/constraints.source
View file @
0e319c7a
...
@@ -274,7 +274,7 @@ SELECT '' AS two, * FROM COPY_TBL;
...
@@ -274,7 +274,7 @@ SELECT '' AS two, * FROM COPY_TBL;
COPY COPY_TBL FROM '@abs_srcdir@/data/constrf.data';
COPY COPY_TBL FROM '@abs_srcdir@/data/constrf.data';
ERROR: new row for relation "copy_tbl" violates check constraint "copy_con"
ERROR: new row for relation "copy_tbl" violates check constraint "copy_con"
CONTEXT: COPY
FROM, line 2
CONTEXT: COPY
copy_tbl, line 2: "7 check failed 6"
SELECT * FROM COPY_TBL;
SELECT * FROM COPY_TBL;
x | y | z
x | y | z
---+---------------+---
---+---------------+---
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment