Index: src/backend/commands/copy.c =================================================================== RCS file: /var/lib/cvs/pgsql/src/backend/commands/copy.c,v retrieving revision 1.160 diff -c -r1.160 copy.c *** src/backend/commands/copy.c 20 Jul 2002 05:16:57 -0000 1.160 --- src/backend/commands/copy.c 25 Jul 2002 20:23:12 -0000 *************** *** 45,60 **** #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7')) #define OCTVALUE(c) ((c) - '0') /* non-export function prototypes */ static void CopyTo(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print); static void CopyFrom(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print); static Oid GetInputFunction(Oid type); static Oid GetTypeElement(Oid type); ! static void CopyReadNewline(FILE *fp, 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 void CopyAssertAttlist(Relation rel, List* attlist, bool from); static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0"; --- 45,65 ---- #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7')) #define OCTVALUE(c) ((c) - '0') + typedef enum CopyReadResult + { + NORMAL_ATTR, + END_OF_LINE, + END_OF_FILE + } CopyReadResult; /* non-export function prototypes */ static void CopyTo(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print); static void CopyFrom(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print); static Oid GetInputFunction(Oid type); static Oid GetTypeElement(Oid type); ! static char *CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result); static void CopyAttributeOut(FILE *fp, char *string, char *delim); ! static void CopyCheckAttlist(Relation rel, List *attlist); static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0"; *************** *** 271,284 **** bool pipe = (stmt->filename == NULL); List *option; List *attlist = stmt->attlist; - DefElem *dbinary = NULL; - DefElem *doids = NULL; - DefElem *ddelim = NULL; - DefElem *dnull = NULL; bool binary = false; bool oids = false; ! char *delim = "\t"; ! char *null_print = "\\N"; FILE *fp; Relation rel; AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); --- 276,285 ---- bool pipe = (stmt->filename == NULL); List *option; List *attlist = stmt->attlist; bool binary = false; bool oids = false; ! char *delim = NULL; ! char *null_print = NULL; FILE *fp; Relation rel; AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); *************** *** 289,339 **** { DefElem *defel = (DefElem *) lfirst(option); if (strcmp(defel->defname, "binary") == 0) { ! if (dbinary) ! /* should this really be an error? */ elog(ERROR, "COPY: BINARY option appears more than once"); ! dbinary = defel; } else if (strcmp(defel->defname, "oids") == 0) { ! if (doids) ! /* should this really be an error? */ elog(ERROR, "COPY: OIDS option appears more than once"); ! doids = defel; } else if (strcmp(defel->defname, "delimiter") == 0) { ! if (ddelim) elog(ERROR, "COPY: DELIMITER string may only be defined once in query"); ! ddelim = defel; } else if (strcmp(defel->defname, "null") == 0) { ! if (dnull) elog(ERROR, "COPY: NULL representation may only be defined once in query"); ! dnull = defel; } else elog(ERROR, "COPY: option \"%s\" not recognized", defel->defname); } ! if (dbinary) ! binary = intVal(dbinary->arg); ! if (doids) ! oids = intVal(doids->arg); ! if (ddelim) ! delim = strVal(ddelim->arg); ! if (dnull) ! null_print = strVal(dnull->arg); ! ! if (binary && ddelim) elog(ERROR, "You can not specify the DELIMITER in BINARY mode."); ! if (binary && dnull) elog(ERROR, "You can not specify NULL in BINARY mode."); /* * Open and lock the relation, using the appropriate lock type. --- 290,342 ---- { DefElem *defel = (DefElem *) lfirst(option); + /* XXX: Should we bother checking for doubled options? */ + if (strcmp(defel->defname, "binary") == 0) { ! if (binary) elog(ERROR, "COPY: BINARY option appears more than once"); ! ! binary = intVal(defel->arg); } else if (strcmp(defel->defname, "oids") == 0) { ! if (oids) elog(ERROR, "COPY: OIDS option appears more than once"); ! ! oids = intVal(defel->arg); } else if (strcmp(defel->defname, "delimiter") == 0) { ! if (delim) elog(ERROR, "COPY: DELIMITER string may only be defined once in query"); ! ! delim = strVal(defel->arg); } else if (strcmp(defel->defname, "null") == 0) { ! if (null_print) elog(ERROR, "COPY: NULL representation may only be defined once in query"); ! ! null_print = strVal(defel->arg); } else elog(ERROR, "COPY: option \"%s\" not recognized", defel->defname); } ! if (binary && delim) elog(ERROR, "You can not specify the DELIMITER in BINARY mode."); ! if (binary && null_print) elog(ERROR, "You can not specify NULL in BINARY mode."); + + /* Set defaults */ + if (!delim) + delim = "\t"; + + if (!null_print) + null_print = "\\N"; /* * Open and lock the relation, using the appropriate lock type. *************** *** 372,393 **** server_encoding = GetDatabaseEncoding(); #endif ! if( attlist == NIL ){ /* get list of attributes in the relation */ TupleDesc desc = RelationGetDescr(rel); int i; ! for(i = 0; i < desc->natts; ++i){ ! Ident* id = makeNode(Ident); id->name = NameStr(desc->attrs[i]->attname); attlist = lappend(attlist,id); } } ! else{ ! if( binary ){ elog(ERROR,"COPY: BINARY format cannot be used with specific column list"); ! } ! /* verify that any user-specified attributes exist in the relation */ ! CopyAssertAttlist(rel,attlist,is_from); } if (is_from) --- 375,398 ---- server_encoding = GetDatabaseEncoding(); #endif ! if (attlist == NIL) ! { /* get list of attributes in the relation */ TupleDesc desc = RelationGetDescr(rel); int i; ! for (i = 0; i < desc->natts; ++i) ! { ! Ident *id = makeNode(Ident); id->name = NameStr(desc->attrs[i]->attname); attlist = lappend(attlist,id); } } ! else ! { ! if (binary) elog(ERROR,"COPY: BINARY format cannot be used with specific column list"); ! ! CopyCheckAttlist(rel, attlist); } if (is_from) *************** *** 532,541 **** int16 fld_size; char *string; Snapshot mySnapshot; ! int copy_attr_count; ! int* attmap; ! int p = 0; ! List* cur; if (oids && !rel->rd_rel->relhasoids) elog(ERROR, "COPY: table %s does not have OIDs", --- 537,546 ---- int16 fld_size; char *string; Snapshot mySnapshot; ! int copy_attr_count; ! int *attmap; ! int p = 0; ! List *cur; if (oids && !rel->rd_rel->relhasoids) elog(ERROR, "COPY: table %s does not have OIDs", *************** *** 544,558 **** tupDesc = rel->rd_att; attr_count = rel->rd_att->natts; attr = rel->rd_att->attrs; copy_attr_count = length(attlist); { ! attmap = (int*)palloc(copy_attr_count * sizeof(int)); ! foreach(cur,attlist){ ! for (i = 0; i < attr_count; i++){ ! if( strcmp(strVal(lfirst(cur)),NameStr(attr[i]->attname)) == 0){ ! attmap[p++] = i; ! continue; ! } } } } --- 549,568 ---- tupDesc = rel->rd_att; attr_count = rel->rd_att->natts; attr = rel->rd_att->attrs; + copy_attr_count = length(attlist); + attmap = (int *) palloc(copy_attr_count * sizeof(int)); + + foreach(cur, attlist) { ! const char *currAtt = strVal(lfirst(cur)); ! ! for (i = 0; i < attr_count; i++) ! { ! if (namestrcmp(&attr[i]->attname, currAtt) == 0) ! { ! attmap[p++] = i; ! continue; } } } *************** *** 642,648 **** Datum origvalue, value; bool isnull; ! int mi = attmap[i]; origvalue = heap_getattr(tuple, mi + 1, tupDesc, &isnull); --- 652,658 ---- Datum origvalue, value; bool isnull; ! int mi = attmap[i]; origvalue = heap_getattr(tuple, mi + 1, tupDesc, &isnull); *************** *** 767,785 **** Oid in_func_oid; Datum *values; char *nulls; - bool isnull; int done = 0; - char *string; ResultRelInfo *resultRelInfo; EState *estate = CreateExecutorState(); /* for ExecConstraints() */ TupleTable tupleTable; TupleTableSlot *slot; - Oid loaded_oid = InvalidOid; - bool skip_tuple = false; bool file_has_oids; ! int* attmap = NULL; ! int* defmap = NULL; ! Node** defexprs = NULL; /* array of default att expressions */ ExprContext *econtext; /* used for ExecEvalExpr for default atts */ ExprDoneCond isdone; --- 777,791 ---- Oid in_func_oid; Datum *values; char *nulls; int done = 0; ResultRelInfo *resultRelInfo; EState *estate = CreateExecutorState(); /* for ExecConstraints() */ TupleTable tupleTable; TupleTableSlot *slot; bool file_has_oids; ! int *attmap = NULL; ! int *defmap = NULL; ! Node **defexprs = NULL; /* array of default att expressions */ ExprContext *econtext; /* used for ExecEvalExpr for default atts */ ExprDoneCond isdone; *************** *** 817,850 **** * pick up the input function and default expression (if any) for * each attribute in the relation. */ ! List* cur; ! attmap = (int*)palloc(sizeof(int) * attr_count); ! defmap = (int*)palloc(sizeof(int) * attr_count); ! defexprs = (Node**)palloc(sizeof(Node*) * attr_count); in_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo)); elements = (Oid *) palloc(attr_count * sizeof(Oid)); for (i = 0; i < attr_count; i++) { ! int p = 0; ! bool specified = false; in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); fmgr_info(in_func_oid, &in_functions[i]); elements[i] = GetTypeElement(attr[i]->atttypid); ! foreach(cur,attlist){ ! if( strcmp(strVal(lfirst(cur)),NameStr(attr[i]->attname)) == 0){ attmap[p] = i; specified = true; continue; } ! ++p; } ! if( ! specified ){ ! /* column not specified, try to get a default */ ! defexprs[def_attr_count] = build_column_default(rel,i+1); ! if( defexprs[def_attr_count] != NULL ){ ! defmap[def_attr_count] = i; ! ++def_attr_count; ! } } } file_has_oids = oids; /* must rely on user to tell us this... */ --- 823,866 ---- * pick up the input function and default expression (if any) for * each attribute in the relation. */ ! attmap = (int *) palloc(sizeof(int) * attr_count); ! defmap = (int *) palloc(sizeof(int) * attr_count); ! defexprs = (Node **) palloc(sizeof(Node *) * attr_count); in_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo)); elements = (Oid *) palloc(attr_count * sizeof(Oid)); for (i = 0; i < attr_count; i++) { ! List *l; ! int p = 0; ! bool specified = false; ! in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); fmgr_info(in_func_oid, &in_functions[i]); elements[i] = GetTypeElement(attr[i]->atttypid); ! ! foreach(l, attlist) ! { ! if (namestrcmp(&attr[i]->attname, strVal(lfirst(l))) == 0) ! { attmap[p] = i; specified = true; continue; } ! p++; } ! ! /* if column not specified, use default value */ ! if (! specified) ! { ! defexprs[def_attr_count] = build_column_default(rel, i + 1); ! ! /* Shouldn't happen */ ! if (defexprs[def_attr_count] == NULL) ! elog(ERROR, "COPY TEXT: Column %d has no default value", ! i + 1); ! ! defmap[def_attr_count] = i; ! def_attr_count++; } } file_has_oids = oids; /* must rely on user to tell us this... */ *************** *** 857,869 **** /* Signature */ CopyGetData(readSig, 12, fp); ! if (CopyGetEof(fp) || ! memcmp(readSig, BinarySignature, 12) != 0) elog(ERROR, "COPY BINARY: file signature not recognized"); /* Integer layout field */ CopyGetData(&tmp, sizeof(int32), fp); ! if (CopyGetEof(fp) || ! tmp != 0x01020304) elog(ERROR, "COPY BINARY: incompatible integer layout"); /* Flags field */ CopyGetData(&tmp, sizeof(int32), fp); --- 873,883 ---- /* Signature */ CopyGetData(readSig, 12, fp); ! if (CopyGetEof(fp) || memcmp(readSig, BinarySignature, 12) != 0) elog(ERROR, "COPY BINARY: file signature not recognized"); /* Integer layout field */ CopyGetData(&tmp, sizeof(int32), fp); ! if (CopyGetEof(fp) || tmp != 0x01020304) elog(ERROR, "COPY BINARY: incompatible integer layout"); /* Flags field */ CopyGetData(&tmp, sizeof(int32), fp); *************** *** 875,882 **** elog(ERROR, "COPY BINARY: unrecognized critical flags in header"); /* Header extension length */ CopyGetData(&tmp, sizeof(int32), fp); ! if (CopyGetEof(fp) || ! tmp < 0) elog(ERROR, "COPY BINARY: bogus file header (missing length)"); /* Skip extension header, if present */ while (tmp-- > 0) --- 889,895 ---- elog(ERROR, "COPY BINARY: unrecognized critical flags in header"); /* Header extension length */ CopyGetData(&tmp, sizeof(int32), fp); ! if (CopyGetEof(fp) || tmp < 0) elog(ERROR, "COPY BINARY: bogus file header (missing length)"); /* Skip extension header, if present */ while (tmp-- > 0) *************** *** 904,909 **** --- 917,925 ---- while (!done) { + bool skip_tuple; + Oid loaded_oid; + CHECK_FOR_INTERRUPTS(); copy_lineno++; *************** *** 917,932 **** if (!binary) { ! int newline = 0; if (file_has_oids) { ! string = CopyReadAttribute(fp, &isnull, delim, ! &newline, null_print); ! if (isnull) elog(ERROR, "COPY TEXT: NULL Oid"); - else if (string == NULL) - done = 1; /* end of file */ else { loaded_oid = DatumGetObjectId(DirectFunctionCall1(oidin, --- 933,949 ---- if (!binary) { ! CopyReadResult result; ! char *string; if (file_has_oids) { ! string = CopyReadAttribute(fp, delim, &result); ! ! if (result == END_OF_FILE) ! done = 1; ! else if (string == NULL || strcmp(string, null_print) == 0) elog(ERROR, "COPY TEXT: NULL Oid"); else { loaded_oid = DatumGetObjectId(DirectFunctionCall1(oidin, *************** *** 943,978 **** for (i = 0; i < copy_attr_count && !done; i++) { int m = attmap[i]; - string = CopyReadAttribute(fp, &isnull, delim, - &newline, null_print); ! if( isnull ){ ! /* nothing */ } - else if (string == NULL) - done = 1; /* end of file */ else { values[m] = FunctionCall3(&in_functions[m], ! CStringGetDatum(string), ! ObjectIdGetDatum(elements[m]), ! Int32GetDatum(attr[m]->atttypmod)); nulls[m] = ' '; } } ! /* * as above, we only try a default lookup if one is * known to be available */ ! for (i = 0; i < def_attr_count && !done; i++){ bool isnull; ! values[defmap[i]] = ExecEvalExpr(defexprs[i],econtext,&isnull,&isdone); ! if( ! isnull ) ! nulls[defmap[i]] = ' '; } - if (!done) - CopyReadNewline(fp, &newline); } else { /* binary */ --- 960,1004 ---- for (i = 0; i < copy_attr_count && !done; i++) { int m = attmap[i]; ! string = CopyReadAttribute(fp, delim, &result); ! ! /* If we got an end-of-line before we expected, bail out */ ! if (result == END_OF_LINE && i < (copy_attr_count - 1)) ! elog(ERROR, "COPY TEXT: Missing data for attribute %d", i + 1); ! ! if (result == END_OF_FILE) ! done = 1; ! else if (strcmp(string, null_print) == 0) ! { ! /* we read an SQL NULL, no need to do anything */ } else { values[m] = FunctionCall3(&in_functions[m], ! CStringGetDatum(string), ! ObjectIdGetDatum(elements[m]), ! Int32GetDatum(attr[m]->atttypmod)); nulls[m] = ' '; } } ! ! if (result == NORMAL_ATTR && !done) ! elog(ERROR, "COPY TEXT: Extra data encountered"); ! /* * as above, we only try a default lookup if one is * known to be available */ ! for (i = 0; i < def_attr_count && !done; i++) ! { bool isnull; ! values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, ! &isnull, &isdone); ! ! if (! isnull) ! nulls[defmap[i]] = ' '; } } else { /* binary */ *************** *** 980,987 **** fld_size; CopyGetData(&fld_count, sizeof(int16), fp); ! if (CopyGetEof(fp) || ! fld_count == -1) done = 1; else { --- 1006,1012 ---- fld_size; CopyGetData(&fld_count, sizeof(int16), fp); ! if (CopyGetEof(fp) || fld_count == -1) done = 1; else { *************** *** 1173,1208 **** return result; } - - /* - * Reads input from fp until an end of line is seen. - */ - - static void - CopyReadNewline(FILE *fp, int *newline) - { - if (!*newline) - { - elog(WARNING, "CopyReadNewline: extra fields ignored"); - while (!CopyGetEof(fp) && (CopyGetChar(fp) != '\n')); - } - *newline = 0; - } - /* * Read the value of a single attribute. * ! * Result is either a string, or NULL (if EOF or a null attribute). ! * Note that the caller should not pfree the string! * ! * *isnull is set true if a null attribute, else false. ! * delim is the column delimiter string (currently always 1 character). ! * *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, char *null_print) { int c; int delimc = (unsigned char)delim[0]; --- 1198,1222 ---- return result; } /* * Read the value of a single attribute. * ! * Results are returned in the status indicator, as well as the ! * return value. If a value was successfully read but there is ! * more to read before EOL, NORMAL_ATTR is set and the value read ! * is returned. If a value was read and we hit EOL, END_OF_LINE ! * is set and the value read is returned. If we hit the EOF, ! * END_OF_FILE is set and NULL 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(FILE *fp, const char *delim, CopyReadResult *result) { int c; int delimc = (unsigned char)delim[0]; *************** *** 1220,1242 **** attribute_buf.len = 0; attribute_buf.data[0] = '\0'; ! /* if last delimiter was a newline return a NULL attribute */ ! if (*newline) ! { ! *isnull = (bool) true; ! return NULL; ! } ! ! *isnull = (bool) false; /* set default */ for (;;) { c = CopyGetChar(fp); if (c == EOF) ! goto endOfFile; if (c == '\n') { ! *newline = 1; break; } if (c == delimc) --- 1234,1253 ---- attribute_buf.len = 0; attribute_buf.data[0] = '\0'; ! /* set default */ ! *result = NORMAL_ATTR; for (;;) { c = CopyGetChar(fp); if (c == EOF) ! { ! *result = END_OF_FILE; ! return NULL; ! } if (c == '\n') { ! *result = END_OF_LINE; break; } if (c == delimc) *************** *** 1245,1251 **** { c = CopyGetChar(fp); if (c == EOF) ! goto endOfFile; switch (c) { case '0': --- 1256,1265 ---- { c = CopyGetChar(fp); if (c == EOF) ! { ! *result = END_OF_FILE; ! return NULL; ! } switch (c) { case '0': *************** *** 1274,1287 **** else { if (c == EOF) ! goto endOfFile; CopyDonePeek(fp, c, false /* put back */ ); } } else { if (c == EOF) ! goto endOfFile; CopyDonePeek(fp, c, false /* put back */ ); } c = val & 0377; --- 1288,1307 ---- else { if (c == EOF) ! { ! *result = END_OF_FILE; ! return NULL; ! } CopyDonePeek(fp, c, false /* put back */ ); } } else { if (c == EOF) ! { ! *result = END_OF_FILE; ! return NULL; ! } CopyDonePeek(fp, c, false /* put back */ ); } c = val & 0377; *************** *** 1319,1325 **** c = CopyGetChar(fp); if (c != '\n') elog(ERROR, "CopyReadAttribute: end of record marker corrupted"); ! goto endOfFile; } } appendStringInfoCharMacro(&attribute_buf, c); --- 1339,1346 ---- c = CopyGetChar(fp); if (c != '\n') elog(ERROR, "CopyReadAttribute: end of record marker corrupted"); ! *result = END_OF_FILE; ! return NULL; } } appendStringInfoCharMacro(&attribute_buf, c); *************** *** 1334,1340 **** { c = CopyGetChar(fp); if (c == EOF) ! goto endOfFile; appendStringInfoCharMacro(&attribute_buf, c); } } --- 1355,1364 ---- { c = CopyGetChar(fp); if (c == EOF) ! { ! *result = END_OF_FILE; ! return NULL; ! } appendStringInfoCharMacro(&attribute_buf, c); } } *************** *** 1357,1369 **** } #endif - if (strcmp(attribute_buf.data, null_print) == 0) - *isnull = true; - return attribute_buf.data; - - endOfFile: - return NULL; } static void --- 1381,1387 ---- *************** *** 1454,1502 **** } /* ! * CopyAssertAttlist: elog(ERROR,...) if the specified attlist * is not valid for the Relation */ static void ! CopyAssertAttlist(Relation rel, List* attlist, bool from) { ! TupleDesc tupDesc; ! List* cur; ! char* illegalattname = NULL; ! int attr_count; ! const char* to_or_from; ! ! if( attlist == NIL ) ! return; ! to_or_from = (from == true ? "FROM" : "TO"); tupDesc = RelationGetDescr(rel); ! Assert(tupDesc != NULL); ! ! /* ! * make sure there aren't more columns specified than are in the table ! */ ! attr_count = tupDesc->natts; ! if( attr_count < length(attlist) ) ! elog(ERROR,"More columns specified in COPY %s command than in target relation",to_or_from); ! ! /* ! * make sure no columns are specified that don't exist in the table ! */ ! foreach(cur,attlist) ! { ! int found = 0; ! int i = 0; ! for(;iattrs[i]->attname)) == 0) ! ++found; ! } ! if( ! found ) ! illegalattname = strVal(lfirst(cur)); ! } ! if( illegalattname ) ! elog(ERROR,"Attribute referenced in COPY %s command does not exist: \"%s.%s\"",to_or_from,RelationGetRelationName(rel),illegalattname); } --- 1472,1521 ---- } /* ! * CopyCheckAttlist: elog(ERROR,...) if the specified attlist * is not valid for the Relation */ static void ! CopyCheckAttlist(Relation rel, List *attlist) { ! TupleDesc tupDesc; ! int attr_count; ! List *l; ! if (attlist == NIL) ! return; tupDesc = RelationGetDescr(rel); ! Assert(tupDesc != NULL); ! ! /* ! * make sure there aren't more columns specified than are in the table ! */ ! attr_count = tupDesc->natts; ! if (attr_count < length(attlist)) ! elog(ERROR, "COPY: Too many columns specified"); ! ! /* ! * make sure no columns are specified that don't exist in the table ! */ ! foreach(l, attlist) ! { ! char *colName = strVal(lfirst(l)); ! bool found = false; ! int i; ! ! for (i = 0; i < attr_count; i++) ! { ! if (namestrcmp(&tupDesc->attrs[i]->attname, colName) == 0) ! { ! found = true; ! break; ! } ! } ! ! if (!found) ! elog(ERROR, "COPY: Specified column \"%s\" does not exist", ! colName); ! } } Index: src/test/regress/expected/copy2.out =================================================================== RCS file: /var/lib/cvs/pgsql/src/test/regress/expected/copy2.out,v retrieving revision 1.2 diff -c -r1.2 copy2.out *** src/test/regress/expected/copy2.out 18 Jul 2002 17:11:49 -0000 1.2 --- src/test/regress/expected/copy2.out 25 Jul 2002 20:23:13 -0000 *************** *** 23,32 **** FOR EACH ROW EXECUTE PROCEDURE fn_x_after(); CREATE TRIGGER trg_x_before BEFORE INSERT ON x FOR EACH ROW EXECUTE PROCEDURE fn_x_before(); ! COPY x (a,b,c,d,e) from stdin; ! COPY x (b,d) from stdin; ! COPY x (b,d) from stdin; ! COPY x (a,b,c,d,e) from stdin; COPY x TO stdout; 10000 21 31 41 before trigger fired 10001 22 32 42 before trigger fired --- 23,54 ---- FOR EACH ROW EXECUTE PROCEDURE fn_x_after(); CREATE TRIGGER trg_x_before BEFORE INSERT ON x FOR EACH ROW EXECUTE PROCEDURE fn_x_before(); ! COPY x (a, b, c, d, e) from stdin; ! COPY x (b, d) from stdin; ! COPY x (b, d) from stdin; ! COPY x (a, b, c, d, e) from stdin; ! -- non-existent column in column list: should fail ! COPY x (xyz) from stdin; ! ERROR: COPY: Specified column "xyz" does not exist ! -- too many columns in column list: should fail ! COPY x (a, b, c, d, e, d, c) from stdin; ! ERROR: COPY: Too many columns specified ! -- missing data: should fail ! COPY x from stdin; ! ERROR: copy: line 1, COPY TEXT: Missing data for attribute 1 ! lost synchronization with server, resetting connection ! COPY x from stdin; ! ERROR: copy: line 1, COPY TEXT: Missing data for attribute 4 ! lost synchronization with server, resetting connection ! COPY x from stdin; ! ERROR: copy: line 1, COPY TEXT: Missing data for attribute 4 ! lost synchronization with server, resetting connection ! -- extra data: should fail ! COPY x from stdin; ! ERROR: copy: line 1, COPY TEXT: Extra data encountered ! lost synchronization with server, resetting connection ! -- various COPY options: delimiters, oids, NULL string ! COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x'; COPY x TO stdout; 10000 21 31 41 before trigger fired 10001 22 32 42 before trigger fired *************** *** 34,44 **** --- 56,80 ---- 10003 24 34 44 before trigger fired 10004 25 35 45 before trigger fired 10005 26 36 46 before trigger fired + 6 \N 45 80 before trigger fired 1 1 stuff test_1 after trigger fired 2 2 stuff test_2 after trigger fired 3 3 stuff test_3 after trigger fired 4 4 stuff test_4 after trigger fired 5 5 stuff test_5 after trigger fired + COPY x (c, e) TO stdout; + 31 before trigger fired + 32 before trigger fired + 33 before trigger fired + 34 before trigger fired + 35 before trigger fired + 36 before trigger fired + 45 before trigger fired + stuff after trigger fired + stuff after trigger fired + stuff after trigger fired + stuff after trigger fired + stuff after trigger fired DROP TABLE x; DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_after(); Index: src/test/regress/sql/copy2.sql =================================================================== RCS file: /var/lib/cvs/pgsql/src/test/regress/sql/copy2.sql,v retrieving revision 1.2 diff -c -r1.2 copy2.sql *** src/test/regress/sql/copy2.sql 18 Jul 2002 22:31:44 -0000 1.2 --- src/test/regress/sql/copy2.sql 25 Jul 2002 20:23:13 -0000 *************** *** 26,47 **** CREATE TRIGGER trg_x_before BEFORE INSERT ON x FOR EACH ROW EXECUTE PROCEDURE fn_x_before(); ! COPY x (a,b,c,d,e) from stdin; 10000 21 31 41 51 \. ! COPY x (b,d) from stdin; 1 test_1 \. ! COPY x (b,d) from stdin; 2 test_2 3 test_3 4 test_4 5 test_5 \. ! COPY x (a,b,c,d,e) from stdin; 10001 22 32 42 52 10002 23 33 43 53 10003 24 34 44 54 --- 26,47 ---- CREATE TRIGGER trg_x_before BEFORE INSERT ON x FOR EACH ROW EXECUTE PROCEDURE fn_x_before(); ! COPY x (a, b, c, d, e) from stdin; 10000 21 31 41 51 \. ! COPY x (b, d) from stdin; 1 test_1 \. ! COPY x (b, d) from stdin; 2 test_2 3 test_3 4 test_4 5 test_5 \. ! COPY x (a, b, c, d, e) from stdin; 10001 22 32 42 52 10002 23 33 43 53 10003 24 34 44 54 *************** *** 49,55 **** --- 49,84 ---- 10005 26 36 46 56 \. + -- non-existent column in column list: should fail + COPY x (xyz) from stdin; + + -- too many columns in column list: should fail + COPY x (a, b, c, d, e, d, c) from stdin; + + -- missing data: should fail + COPY x from stdin; + + \. + COPY x from stdin; + 2000 230 23 23 + \. + COPY x from stdin; + 2001 231 \N \N + \. + + -- extra data: should fail + COPY x from stdin; + 2002 232 40 50 60 70 80 + \. + + -- various COPY options: delimiters, oids, NULL string + COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x'; + 500000,x,45,80,90 + \. + + COPY x TO stdout; + COPY x (c, e) TO stdout; DROP TABLE x; DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_after();