From a90db34b542d9f31582627a0bfa43901811b84b2 Mon Sep 17 00:00:00 2001 From: Bruce Momjian <bruce@momjian.us> Date: Thu, 18 Jul 2002 04:43:51 +0000 Subject: [PATCH] The attached patch (against HEAD) implements COPY x (a,d,c,b) from stdin; COPY x (a,c) to stdout; as well as the corresponding changes to pg_dump to use the new functionality. This functionality is not available when using the BINARY option. If a column is not specified in the COPY FROM statement, its default values will be used. In addition to this functionality, I tweaked a couple of the error messages emitted by the new COPY <options> checks. Brent Verner --- doc/src/sgml/ref/copy.sgml | 24 ++- src/backend/commands/copy.c | 218 +++++++++++++++++++++------ src/backend/parser/gram.y | 25 +-- src/backend/rewrite/rewriteHandler.c | 5 +- src/bin/pg_dump/pg_dump.c | 54 ++++++- src/include/nodes/parsenodes.h | 3 +- src/include/rewrite/rewriteHandler.h | 4 +- src/test/regress/parallel_schedule | 2 +- src/test/regress/serial_schedule | 3 +- 9 files changed, 267 insertions(+), 71 deletions(-) diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index 28ca264c65c..a1a5e9baa76 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.32 2002/06/20 16:00:43 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.33 2002/07/18 04:43:50 momjian Exp $ PostgreSQL documentation --> @@ -21,7 +21,8 @@ PostgreSQL documentation <date>1999-12-11</date> </refsynopsisdivinfo> <synopsis> -COPY <replaceable class="parameter">table</replaceable> +COPY <replaceable class="parameter">table</replaceable> + [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ] FROM { '<replaceable class="parameter">filename</replaceable>' | <filename>stdin</filename> } [ [ WITH ] [ BINARY ] @@ -29,6 +30,7 @@ COPY <replaceable class="parameter">table</replaceable> [ DELIMITER [ AS ] '<replaceable class="parameter">delimiter</replaceable>' ] [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] ] COPY <replaceable class="parameter">table</replaceable> + [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ] TO { '<replaceable class="parameter">filename</replaceable>' | <filename>stdout</filename> } [ [ WITH ] [ BINARY ] @@ -55,6 +57,16 @@ COPY <replaceable class="parameter">table</replaceable> </para> </listitem> </varlistentry> + + <varlistentry> + <term><replaceable class="parameter">column list</replaceable></term> + <listitem> + <para> + An optional list of columns to be copied. If no column list is + specified, all columns will be used. + </para> + </listitem> + </varlistentry> <varlistentry> <term><replaceable class="parameter">filename</replaceable></term> @@ -187,6 +199,14 @@ ERROR: <replaceable>reason</replaceable> whatever is in the table already). </para> + <para> + When using the optional column list syntax, <command>COPY TO</command> + and <command>COPY FROM</command> will only copy the specified + columns' values to/from the table. If a column in the table + is not in the column list, <command>COPY FROM</command> will insert + default values for that column if a default value is defined. + </para> + <para> <command>COPY</command> with a file name instructs the <productname>PostgreSQL</productname> backend to directly read from diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 7410bff04b1..438126a3e18 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.158 2002/06/20 20:29:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.159 2002/07/18 04:43:50 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,7 @@ #include "commands/copy.h" #include "commands/trigger.h" #include "executor/executor.h" +#include "rewrite/rewriteHandler.h" #include "libpq/libpq.h" #include "miscadmin.h" #include "tcop/pquery.h" @@ -46,13 +47,14 @@ /* non-export function prototypes */ -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 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"; @@ -267,7 +269,8 @@ DoCopy(const CopyStmt *stmt) char *filename = stmt->filename; bool is_from = stmt->is_from; bool pipe = (stmt->filename == NULL); - List *option; + List *option; + List *attlist = stmt->attlist; DefElem *dbinary = NULL; DefElem *doids = NULL; DefElem *ddelim = NULL; @@ -289,25 +292,27 @@ DoCopy(const CopyStmt *stmt) if (strcmp(defel->defname, "binary") == 0) { if (dbinary) - elog(ERROR, "COPY: conflicting options"); + /* 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) - elog(ERROR, "COPY: conflicting options"); + /* 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: conflicting options"); + 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: conflicting options"); + elog(ERROR, "COPY: NULL representation may only be defined once in query"); dnull = defel; } else @@ -367,6 +372,24 @@ DoCopy(const CopyStmt *stmt) 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) { /* copy from file to database */ if (rel->rd_rel->relkind != RELKIND_RELATION) @@ -410,7 +433,7 @@ DoCopy(const CopyStmt *stmt) elog(ERROR, "COPY: %s is a directory.", filename); } } - CopyFrom(rel, binary, oids, fp, delim, null_print); + CopyFrom(rel, attlist, binary, oids, fp, delim, null_print); } else { /* copy from database to file */ @@ -466,7 +489,7 @@ DoCopy(const CopyStmt *stmt) elog(ERROR, "COPY: %s is a directory.", filename); } } - CopyTo(rel, binary, oids, fp, delim, null_print); + CopyTo(rel, attlist, binary, oids, fp, delim, null_print); } if (!pipe) @@ -494,8 +517,8 @@ DoCopy(const CopyStmt *stmt) * Copy from relation TO file. */ static void -CopyTo(Relation rel, bool binary, bool oids, FILE *fp, - char *delim, char *null_print) +CopyTo(Relation rel, List *attlist, bool binary, bool oids, + FILE *fp, char *delim, char *null_print) { HeapTuple tuple; TupleDesc tupDesc; @@ -509,6 +532,10 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, 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", @@ -517,6 +544,18 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, 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; + } + } + } + } /* * For binary copy we really only need isvarlena, but compute it @@ -593,13 +632,14 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, } } - for (i = 0; i < attr_count; i++) + for (i = 0; i < copy_attr_count; i++) { Datum origvalue, value; bool isnull; + int mi = attmap[i]; - origvalue = heap_getattr(tuple, i + 1, tupDesc, &isnull); + origvalue = heap_getattr(tuple, mi + 1, tupDesc, &isnull); if (!binary) { @@ -628,25 +668,25 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, * (or for binary case, becase we must output untoasted * value). */ - if (isvarlena[i]) + if (isvarlena[mi]) value = PointerGetDatum(PG_DETOAST_DATUM(origvalue)); else value = origvalue; if (!binary) { - string = DatumGetCString(FunctionCall3(&out_functions[i], + string = DatumGetCString(FunctionCall3(&out_functions[mi], value, - ObjectIdGetDatum(elements[i]), - Int32GetDatum(attr[i]->atttypmod))); + ObjectIdGetDatum(elements[mi]), + Int32GetDatum(attr[mi]->atttypmod))); CopyAttributeOut(fp, string, delim); pfree(string); } else { - fld_size = attr[i]->attlen; + fld_size = attr[mi]->attlen; CopySendData(&fld_size, sizeof(int16), fp); - if (isvarlena[i]) + if (isvarlena[mi]) { /* varlena */ Assert(fld_size == -1); @@ -654,7 +694,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, VARSIZE(value), fp); } - else if (!attr[i]->attbyval) + else if (!attr[mi]->attbyval) { /* fixed-length pass-by-reference */ Assert(fld_size > 0); @@ -709,13 +749,13 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, * Copy FROM file to relation. */ static void -CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, - char *delim, char *null_print) +CopyFrom(Relation rel, List *attlist, bool binary, bool oids, + FILE *fp, char *delim, char *null_print) { HeapTuple tuple; TupleDesc tupDesc; Form_pg_attribute *attr; - AttrNumber attr_count; + AttrNumber attr_count, copy_attr_count, def_attr_count; FmgrInfo *in_functions; Oid *elements; int i; @@ -732,10 +772,17 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, 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; tupDesc = RelationGetDescr(rel); attr = tupDesc->attrs; attr_count = tupDesc->natts; + copy_attr_count = length(attlist); + def_attr_count = 0; /* * We need a ResultRelInfo so we can use the regular executor's @@ -758,15 +805,42 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, slot = ExecAllocTableSlot(tupleTable); ExecSetSlotDescriptor(slot, tupDesc, false); + if (!binary) { + /* + * 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... */ } @@ -821,12 +895,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, copy_lineno = 0; fe_eof = false; + econtext = GetPerTupleExprContext(estate); + while (!done) { CHECK_FOR_INTERRUPTS(); copy_lineno++; - + /* Reset the per-output-tuple exprcontext */ ResetPerTupleExprContext(estate); @@ -854,26 +930,42 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, elog(ERROR, "COPY TEXT: Invalid Oid"); } } - - for (i = 0; i < attr_count && !done; i++) + + /* + * here, we only try to read as many attributes as + * were specified. + */ + for (i = 0; i < copy_attr_count && !done; i++) { + int m = attmap[i]; string = CopyReadAttribute(fp, &isnull, delim, &newline, null_print); - if (isnull) - { - /* already set values[i] and nulls[i] */ + + if( isnull ){ + /* nothing */ } else if (string == NULL) done = 1; /* end of file */ else { - values[i] = FunctionCall3(&in_functions[i], - CStringGetDatum(string), - ObjectIdGetDatum(elements[i]), - Int32GetDatum(attr[i]->atttypmod)); - nulls[i] = ' '; + 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); } @@ -975,7 +1067,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, break; tuple = heap_formtuple(tupDesc, values, nulls); - + if (oids && file_has_oids) tuple->t_data->t_oid = loaded_oid; @@ -1021,12 +1113,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, ExecARInsertTriggers(estate, resultRelInfo, tuple); } - for (i = 0; i < attr_count; i++) - { - if (!attr[i]->attbyval && nulls[i] != 'n') - pfree(DatumGetPointer(values[i])); - } - heap_freetuple(tuple); } @@ -1361,3 +1447,51 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim) pfree(string_start); /* pfree pg_server_to_client result */ #endif } + +/* + * 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(;i<attr_count;++i) + { + if( strcmp(strVal(lfirst(cur)),NameStr(tupDesc->attrs[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); +} + diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index f2220aa00b9..17a3b61e762 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.343 2002/07/18 04:41:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.344 2002/07/18 04:43:50 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -1262,31 +1262,32 @@ opt_id: ColId { $$ = $1; } /***************************************************************************** * * QUERY : - * COPY <relname> FROM/TO [WITH options] + * COPY <relname> ['(' columnList ')'] FROM/TO [WITH options] * * BINARY, OIDS, and DELIMITERS kept in old locations * for backward compatibility. 2002-06-18 * *****************************************************************************/ -CopyStmt: COPY opt_binary qualified_name opt_oids copy_from - copy_file_name copy_delimiter opt_with copy_opt_list +CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids + copy_from copy_file_name copy_delimiter opt_with copy_opt_list { CopyStmt *n = makeNode(CopyStmt); n->relation = $3; - n->is_from = $5; - n->filename = $6; + n->attlist = $4; + n->is_from = $6; + n->filename = $7; n->options = NIL; /* Concatenate user-supplied flags */ if ($2) n->options = lappend(n->options, $2); - if ($4) - n->options = lappend(n->options, $4); - if ($7) - n->options = lappend(n->options, $7); - if ($9) - n->options = nconc(n->options, $9); + if ($5) + n->options = lappend(n->options, $5); + if ($8) + n->options = lappend(n->options, $8); + if ($10) + n->options = nconc(n->options, $10); $$ = (Node *)n; } ; diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index ae199d51ce8..0ae1e223baa 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.103 2002/06/20 20:29:34 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.104 2002/07/18 04:43:50 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -43,7 +43,6 @@ static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index); static void rewriteTargetList(Query *parsetree, Relation target_relation); static TargetEntry *process_matched_tle(TargetEntry *src_tle, TargetEntry *prior_tle); -static Node *build_column_default(Relation rel, int attrno); static void markQueryForUpdate(Query *qry, bool skipOldNew); static List *matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree); @@ -411,7 +410,7 @@ process_matched_tle(TargetEntry *src_tle, * * If there is no default, return a NULL instead. */ -static Node * +Node * build_column_default(Relation rel, int attrno) { TupleDesc rd_att = rel->rd_att; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index dd6aad5503d..7f263c3eb47 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.271 2002/07/12 18:43:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.272 2002/07/18 04:43:50 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -133,6 +133,7 @@ static char *GetPrivileges(Archive *AH, const char *s, const char *type); static int dumpBlobs(Archive *AH, char *, void *); static int dumpDatabase(Archive *AH); static const char *getAttrName(int attrnum, TableInfo *tblInfo); +static const char* fmtCopyColumnList(const TableInfo* ti); extern char *optarg; extern int optind, @@ -842,6 +843,7 @@ dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv) int ret; bool copydone; char copybuf[COPYBUFSIZ]; + const char* column_list; if (g_verbose) write_msg(NULL, "dumping out the contents of table %s\n", classname); @@ -854,17 +856,19 @@ dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv) */ selectSourceSchema(tbinfo->relnamespace->nspname); + column_list = fmtCopyColumnList(tbinfo); + if (oids && hasoids) { - appendPQExpBuffer(q, "COPY %s WITH OIDS TO stdout;", + appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;", fmtQualifiedId(tbinfo->relnamespace->nspname, - classname)); + classname),column_list); } else { - appendPQExpBuffer(q, "COPY %s TO stdout;", + appendPQExpBuffer(q, "COPY %s %s TO stdout;", fmtQualifiedId(tbinfo->relnamespace->nspname, - classname)); + classname), column_list); } res = PQexec(g_conn, q->data); if (!res || @@ -1189,8 +1193,9 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout, { /* Dump/restore using COPY */ dumpFn = dumpClasses_nodumpData; - sprintf(copyBuf, "COPY %s %sFROM stdin;\n", - fmtId(tblinfo[i].relname, force_quotes), + sprintf(copyBuf, "COPY %s %s %sFROM stdin;\n", + fmtQualifiedId(tblinfo[i].relnamespace->nspname,tblinfo[i].relname), + fmtCopyColumnList(&(tblinfo[i])), (oids && tblinfo[i].hasoids) ? "WITH OIDS " : ""); copyStmt = copyBuf; } @@ -5860,3 +5865,38 @@ fmtQualifiedId(const char *schema, const char *id) return id_return->data; } + +/* + * return a column list clause for the qualified relname. + * returns an empty string if the remote server is older than + * 7.3. + */ +static const char* +fmtCopyColumnList(const TableInfo* ti) +{ + static PQExpBuffer q = NULL; + int numatts = ti->numatts; + char** attnames = ti->attnames; + int i; + + if (g_fout->remoteVersion < 70300 ) + return ""; + + if (q) /* first time through? */ + resetPQExpBuffer(q); + else + q = createPQExpBuffer(); + + resetPQExpBuffer(q); + + appendPQExpBuffer(q,"("); + for (i = 0; i < numatts; i++) + { + if( i > 0 ) + appendPQExpBuffer(q,","); + appendPQExpBuffer(q, fmtId(attnames[i], force_quotes)); + } + appendPQExpBuffer(q, ")"); + return q->data; +} + diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index f64f1b3d746..e6b27d03af4 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.189 2002/07/18 04:42:29 momjian Exp $ + * $Id: parsenodes.h,v 1.190 2002/07/18 04:43:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -884,6 +884,7 @@ typedef struct CopyStmt { NodeTag type; RangeVar *relation; /* the relation to copy */ + List *attlist; bool is_from; /* TO or FROM */ char *filename; /* if NULL, use stdin/stdout */ List *options; /* List of DefElem nodes */ diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index 900ffca658f..69fecc8142d 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: rewriteHandler.h,v 1.19 2002/06/20 20:29:52 momjian Exp $ + * $Id: rewriteHandler.h,v 1.20 2002/07/18 04:43:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -16,7 +16,7 @@ #include "nodes/parsenodes.h" - extern List *QueryRewrite(Query *parsetree); +extern Node *build_column_default(Relation rel, int attrno); #endif /* REWRITEHANDLER_H */ diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 1a72d1bc6e0..919c37e13f6 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -74,4 +74,4 @@ test: select_views alter_table portals_p2 rules foreign_key # The sixth group of parallel test # ---------- # "plpgsql" cannot run concurrently with "rules" -test: limit plpgsql temp domain rangefuncs +test: limit plpgsql temp domain rangefuncs copy2 diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 87afc7c4512..552d63f9e30 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -1,4 +1,4 @@ -# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.10 2002/06/20 17:09:42 momjian Exp $ +# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.11 2002/07/18 04:43:51 momjian Exp $ # This should probably be in an order similar to parallel_schedule. test: boolean test: char @@ -80,6 +80,7 @@ test: rules test: foreign_key test: limit test: plpgsql +test: copy2 test: temp test: domain test: rangefuncs -- GitLab