The attached patch (against HEAD) implements
authorBruce Momjian
Thu, 18 Jul 2002 04:43:51 +0000 (04:43 +0000)
committerBruce Momjian
Thu, 18 Jul 2002 04:43:51 +0000 (04:43 +0000)
  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  checks.

Brent Verner

doc/src/sgml/ref/copy.sgml
src/backend/commands/copy.c
src/backend/parser/gram.y
src/backend/rewrite/rewriteHandler.c
src/bin/pg_dump/pg_dump.c
src/include/nodes/parsenodes.h
src/include/rewrite/rewriteHandler.h
src/test/regress/parallel_schedule
src/test/regress/serial_schedule

index 28ca264c65c20610250c6e416cfad4a4e03eab95..a1a5e9baa765e8f0d0e64f6ed2d6e3f35658fad1 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -21,7 +21,8 @@ PostgreSQL documentation
    1999-12-11
   
   
-COPY table
+COPY table 
+    [ ( column [, ...] ) ]
     FROM { 'filename' | stdin }
     [ [ WITH ] 
           [ BINARY ] 
@@ -29,6 +30,7 @@ COPY table
           [ DELIMITER [ AS ] 'delimiter' ]
           [ NULL [ AS ] 'null string' ] ]
 COPY table
+    [ ( column [, ...] ) ]
     TO { 'filename' | stdout }
     [ [ WITH ] 
           [ BINARY ]
@@ -55,6 +57,16 @@ COPY table
        
       
      
+     
+        
+      column list
+      
+       
+   An optional list of columns to be copied.  If no column list is
+   specified, all columns will be used.
+       
+      
+     
 
      
       filename
@@ -187,6 +199,14 @@ ERROR: reason
    whatever is in the table already).
   
 
+   
+   When using the optional column list syntax, COPY TO 
+    and COPY FROM will only copy the specified
+    columns' values to/from the table. If a column in the table
+    is not in the column list, COPY FROM will insert 
+    default values for that column if a default value is defined.
+  
+
   
    COPY with a file name instructs the
    PostgreSQL backend to directly read from
index 7410bff04b1defc7c681e0d489ef55d6d6bf6fd7..438126a3e1809735552239602a2bf94912cbc58a 100644 (file)
@@ -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"
 
 
 /* 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
+    {
+      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); 
+}
+
index f2220aa00b9935bb1e685ccd09c279b5db34b33c..17a3b61e76226607a4ca024cf22c8f43f5458a6b 100644 (file)
@@ -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  FROM/TO [WITH options]
+ *             COPY  ['(' 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;
                }
        ;
index ae199d51ce874b3348acd56adefa5739511cd893..0ae1e223baae20fc71bb1b85c8de49edab7c7817 100644 (file)
@@ -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;
index dd6aad5503df8dc10e0a2d7ac30d14baf9eafff4..7f263c3eb47dcefbf8492fb31ffe26fc3e81eed9 100644 (file)
@@ -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;
+}
+
index f64f1b3d7463870bf4407661a84403fd7bdfbec2..e6b27d03af486ef485a78813c59f9701fddf5f13 100644 (file)
@@ -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 */
index 900ffca658f48520cbd0a0127df03b00d963bad6..69fecc8142d1785d30fc1a4e0875f2cb2baad6bf 100644 (file)
@@ -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 */
index 1a72d1bc6e0a96566d3b0570f97ac285dc90f610..919c37e13f65d18e810fbb8b10048eb7309ef6b6 100644 (file)
@@ -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
index 87afc7c451246b898bdf49bf6807ab0d06a8fecc..552d63f9e300750aeba0e13849f261a75fb0a558 100644 (file)
@@ -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