The attached patch (against HEAD) implements
authorBruce Momjian <bruce@momjian.us>
Thu, 18 Jul 2002 04:43:51 +0000 (04:43 +0000)
committerBruce Momjian <bruce@momjian.us>
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 <options> 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 @@
 <!--
-$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
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<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); 
+}
+
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 <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;
                                }
                ;
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