66 *
77 *
88 * IDENTIFICATION
9- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.86 1999/07/22 02:40:06 tgl Exp $
9+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.87 1999/09/11 22:28:11 tgl Exp $
1010 *
1111 *-------------------------------------------------------------------------
1212 */
2626#include "commands/copy.h"
2727#include "commands/trigger.h"
2828#include "executor/executor.h"
29+ #include "lib/stringinfo.h"
2930#include "libpq/libpq.h"
3031#include "miscadmin.h"
3132#include "utils/acl.h"
@@ -51,14 +52,10 @@ static void GetIndexRelations(Oid main_relation_oid,
5152int * n_indices ,
5253Relation * * index_rels );
5354
54- #ifdef COPY_PATCH
5555static void CopyReadNewline (FILE * fp ,int * newline );
5656static char * CopyReadAttribute (FILE * fp ,bool * isnull ,char * delim ,int * newline );
57- #else
58- static char * CopyReadAttribute (FILE * fp ,bool * isnull ,char * delim );
59- #endif
6057
61- static void CopyAttributeOut (FILE * fp ,char * string ,char * delim , int is_array );
58+ static void CopyAttributeOut (FILE * fp ,char * string ,char * delim );
6259static int CountTuples (Relation relation );
6360
6461/*
@@ -431,7 +428,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
431428{
432429string = (char * ) (* fmgr_faddr (& out_functions [i ]))
433430(value ,elements [i ],typmod [i ]);
434- CopyAttributeOut (fp ,string ,delim , attr [ i ] -> attnelems );
431+ CopyAttributeOut (fp ,string ,delim );
435432pfree (string );
436433}
437434else
@@ -691,38 +688,31 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
691688{
692689if (!binary )
693690{
694- #ifdef COPY_PATCH
695691int newline = 0 ;
696692
697- #endif
698693lineno ++ ;
699694if (oids )
700695{
701- #ifdef COPY_PATCH
702696string = CopyReadAttribute (fp ,& isnull ,delim ,& newline );
703- #else
704- string = CopyReadAttribute (fp ,& isnull ,delim );
705- #endif
706697if (string == NULL )
707698done = 1 ;
708699else
709700{
710701loaded_oid = oidin (string );
711702if (loaded_oid < BootstrapObjectIdData )
712703elog (ERROR ,"COPY TEXT: Invalid Oid. line: %d" ,lineno );
704+ pfree (string );
713705}
714706}
715707for (i = 0 ;i < attr_count && !done ;i ++ )
716708{
717- #ifdef COPY_PATCH
718709string = CopyReadAttribute (fp ,& isnull ,delim ,& newline );
719- #else
720- string = CopyReadAttribute (fp ,& isnull ,delim );
721- #endif
722710if (isnull )
723711{
724712values [i ]= PointerGetDatum (NULL );
725713nulls [i ]= 'n' ;
714+ if (string )
715+ pfree (string );
726716}
727717else if (string == NULL )
728718done = 1 ;
@@ -739,12 +729,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
739729if (!PointerIsValid (values [i ])&&
740730!(rel -> rd_att -> attrs [i ]-> attbyval ))
741731elog (ERROR ,"copy from line %d: Bad file format" ,lineno );
732+ pfree (string );
742733}
743734}
744- #ifdef COPY_PATCH
745735if (!done )
746736CopyReadNewline (fp ,& newline );
747- #endif
748737}
749738else
750739{/* binary */
@@ -812,11 +801,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
812801if (done )
813802continue ;
814803
815- /*
816- * Does it have any sence ? - vadim 12/14/96
817- *
818- * tupDesc = CreateTupleDesc(attr_count, attr);
819- */
820804tuple = heap_formtuple (tupDesc ,values ,nulls );
821805if (oids )
822806tuple -> t_data -> t_oid = loaded_oid ;
@@ -1086,30 +1070,18 @@ GetIndexRelations(Oid main_relation_oid,
10861070}
10871071}
10881072
1089- #define EXT_ATTLEN (5 * BLCKSZ)
10901073
10911074/*
1092- returns 1is c is in s
1075+ returns 1if c is in s
10931076*/
10941077static bool
10951078inString (char c ,char * s )
10961079{
1097- int i ;
1098-
1099- if (s )
1100- {
1101- i = 0 ;
1102- while (s [i ]!= '\0' )
1103- {
1104- if (s [i ]== c )
1105- return 1 ;
1106- i ++ ;
1107- }
1108- }
1080+ if (s && c )
1081+ return strchr (s ,c )!= NULL ;
11091082return 0 ;
11101083}
11111084
1112- #ifdef COPY_PATCH
11131085/*
11141086 * Reads input from fp until an end of line is seen.
11151087 */
@@ -1125,64 +1097,57 @@ CopyReadNewline(FILE *fp, int *newline)
11251097* newline = 0 ;
11261098}
11271099
1128- #endif
1129-
11301100/*
1131- * Reads input from fp until eof is seen. If we are reading from standard
1132- * input, AND we see a dot on a line by itself (a dot followed immediately
1133- * by a newline), we exit as if we saw eof. This is so that copy pipelines
1134- * can be used as standard input.
1101+ * Read the value of a single attribute.
1102+ *
1103+ * Result is either a palloc'd string, or NULL (if EOF or a null attribute).
1104+ * *isnull is set true if a null attribute, else false.
1105+ *
1106+ * delim is the string of acceptable delimiter characters(s).
1107+ * *newline remembers whether we've seen a newline ending this tuple.
11351108 */
11361109
11371110static char *
1138- #ifdef COPY_PATCH
11391111CopyReadAttribute (FILE * fp ,bool * isnull ,char * delim ,int * newline )
1140- #else
1141- CopyReadAttribute (FILE * fp ,bool * isnull ,char * delim )
1142- #endif
11431112{
1144- static char attribute [ EXT_ATTLEN ] ;
1113+ StringInfoData attribute_buf ;
11451114char c ;
1146- int done = 0 ;
1147- int i = 0 ;
1148-
11491115#ifdef MULTIBYTE
11501116int mblen ;
11511117int encoding ;
11521118unsignedchar s [2 ];
1119+ char * cvt ;
11531120int j ;
11541121
1155- #endif
1156-
1157- #ifdef MULTIBYTE
11581122encoding = pg_get_client_encoding ();
11591123s [1 ]= 0 ;
11601124#endif
11611125
1162- #ifdef COPY_PATCH
11631126/* if last delimiter was a newline return a NULL attribute */
11641127if (* newline )
11651128{
11661129* isnull = (bool ) true;
11671130return NULL ;
11681131}
1169- #endif
11701132
11711133* isnull = (bool ) false;/* set default */
1134+
1135+ initStringInfo (& attribute_buf );
1136+
11721137if (CopyGetEof (fp ))
1173- return NULL ;
1138+ goto endOfFile ;
11741139
1175- while (! done )
1140+ for (;; )
11761141{
11771142c = CopyGetChar (fp );
1178-
11791143if (CopyGetEof (fp ))
1180- return NULL ;
1181- else if (c == '\\' )
1144+ gotoendOfFile ;
1145+
1146+ if (c == '\\' )
11821147{
11831148c = CopyGetChar (fp );
11841149if (CopyGetEof (fp ))
1185- return NULL ;
1150+ goto endOfFile ;
11861151switch (c )
11871152{
11881153case '0' :
@@ -1212,14 +1177,14 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
12121177else
12131178{
12141179if (CopyGetEof (fp ))
1215- return NULL ;
1180+ goto endOfFile ;
12161181CopyDonePeek (fp ,c ,0 );/* Return to stream! */
12171182}
12181183}
12191184else
12201185{
12211186if (CopyGetEof (fp ))
1222- return NULL ;
1187+ goto endOfFile ;
12231188CopyDonePeek (fp ,c ,0 );/* Return to stream! */
12241189}
12251190c = val & 0377 ;
@@ -1244,66 +1209,70 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
12441209c = '\v' ;
12451210break ;
12461211case 'N' :
1247- attribute [0 ]= '\0' ;/* just to be safe */
12481212* isnull = (bool ) true;
12491213break ;
12501214case '.' :
12511215c = CopyGetChar (fp );
12521216if (c != '\n' )
12531217elog (ERROR ,"CopyReadAttribute - end of record marker corrupted. line: %d" ,lineno );
1254- return NULL ;
1218+ goto endOfFile ;
12551219break ;
12561220}
12571221}
1258- else if (inString ( c , delim ) || c == '\n' )
1222+ else if (c == '\n' || inString ( c , delim ) )
12591223{
1260- #ifdef COPY_PATCH
12611224if (c == '\n' )
12621225* newline = 1 ;
1263- #endif
1264- done = 1 ;
1226+ break ;
12651227}
1266- if (!done )
1267- attribute [i ++ ]= c ;
1228+ appendStringInfoChar (& attribute_buf ,c );
12681229#ifdef MULTIBYTE
1230+ /* get additional bytes of the char, if any */
12691231s [0 ]= c ;
12701232mblen = pg_encoding_mblen (encoding ,s );
1271- mblen -- ;
1272- for (j = 0 ;j < mblen ;j ++ )
1233+ for (j = 1 ;j < mblen ;j ++ )
12731234{
12741235c = CopyGetChar (fp );
12751236if (CopyGetEof (fp ))
1276- return NULL ;
1277- attribute [ i ++ ] = c ;
1237+ goto endOfFile ;
1238+ appendStringInfoChar ( & attribute_buf , c ) ;
12781239}
12791240#endif
1280- if (i == EXT_ATTLEN - 1 )
1281- elog (ERROR ,"CopyReadAttribute - attribute length too long. line: %d" ,lineno );
12821241}
1283- attribute [ i ] = '\0' ;
1242+
12841243#ifdef MULTIBYTE
1285- return (pg_client_to_server ((unsignedchar * )attribute ,strlen (attribute )));
1286- #else
1287- return & attribute [0 ];
1244+ cvt = (char * )pg_client_to_server ((unsignedchar * )attribute_buf .data ,
1245+ attribute_buf .len );
1246+ if (cvt != attribute_buf .data )
1247+ {
1248+ pfree (attribute_buf .data );
1249+ return cvt ;
1250+ }
12881251#endif
1252+ return attribute_buf .data ;
1253+
1254+ endOfFile :
1255+ pfree (attribute_buf .data );
1256+ return NULL ;
12891257}
12901258
12911259static void
1292- CopyAttributeOut (FILE * fp ,char * server_string ,char * delim , int is_array )
1260+ CopyAttributeOut (FILE * fp ,char * server_string ,char * delim )
12931261{
12941262char * string ;
12951263char c ;
1296-
12971264#ifdef MULTIBYTE
1298- int mblen ;
1265+ char * string_start ;
12991266int encoding ;
1267+ int mblen ;
13001268int i ;
1301-
13021269#endif
13031270
13041271#ifdef MULTIBYTE
1305- string = pg_server_to_client (server_string ,strlen (server_string ));
13061272encoding = pg_get_client_encoding ();
1273+ string = (char * )pg_server_to_client ((unsignedchar * )server_string ,
1274+ strlen (server_string ));
1275+ string_start = string ;
13071276#else
13081277string = server_string ;
13091278#endif
@@ -1315,33 +1284,20 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim, int is_array)
13151284for (; (c = * string )!= '\0' ;string ++ )
13161285#endif
13171286{
1318- if (c == delim [0 ]|| c == '\n' ||
1319- (c == '\\' && !is_array ))
1287+ if (c == delim [0 ]|| c == '\n' || c == '\\' )
13201288CopySendChar ('\\' ,fp );
1321- else if (c == '\\' && is_array )
1322- {
1323- if (* (string + 1 )== '\\' )
1324- {
1325- /* translate \\ to \\\\ */
1326- CopySendChar ('\\' ,fp );
1327- CopySendChar ('\\' ,fp );
1328- CopySendChar ('\\' ,fp );
1329- string ++ ;
1330- }
1331- else if (* (string + 1 )== '"' )
1332- {
1333- /* translate \" to \\\" */
1334- CopySendChar ('\\' ,fp );
1335- CopySendChar ('\\' ,fp );
1336- }
1337- }
13381289#ifdef MULTIBYTE
13391290for (i = 0 ;i < mblen ;i ++ )
13401291CopySendChar (* (string + i ),fp );
13411292#else
1342- CopySendChar (* string ,fp );
1293+ CopySendChar (c ,fp );
13431294#endif
13441295}
1296+
1297+ #ifdef MULTIBYTE
1298+ if (string_start != server_string )
1299+ pfree (string_start );/* pfree pg_server_to_client result */
1300+ #endif
13451301}
13461302
13471303/*