Index: doc/src/sgml/ref/copy.sgml
===================================================================
RCS file: /var/cvsup/pgsql/doc/src/sgml/ref/copy.sgml,v
retrieving revision 1.32
diff -c -r1.32 copy.sgml
*** doc/src/sgml/ref/copy.sgml 20 Jun 2002 16:00:43 -0000 1.32
--- doc/src/sgml/ref/copy.sgml 14 Jul 2002 00:49:07 -0000
***************
*** 21,27 ****
1999-12-11
! COPY table
FROM { 'filename' | stdin }
[ [ WITH ]
[ BINARY ]
--- 21,28 ----
1999-12-11
! COPY table
! [ ( column [, ...] ) ]
FROM { 'filename' | stdin }
[ [ WITH ]
[ BINARY ]
***************
*** 29,34 ****
--- 30,36 ----
[ DELIMITER [ AS ] 'delimiter' ]
[ NULL [ AS ] 'null string' ] ]
COPY table
+ [ ( column [, ...] ) ]
TO { 'filename' | stdout }
[ [ WITH ]
[ BINARY ]
***************
*** 55,60 ****
--- 57,72 ----
+
+
+ column list
+
+
+ An optional list of columns to be copied. If no column list is
+ specified, all columns will be used.
+
+
+
filename
***************
*** 185,190 ****
--- 197,210 ----
to> a file, while COPY FROM copies
data from> a file to a table (appending the data to
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.
Index: src/backend/commands/copy.c
===================================================================
RCS file: /var/cvsup/pgsql/src/backend/commands/copy.c,v
retrieving revision 1.158
diff -c -r1.158 copy.c
*** src/backend/commands/copy.c 20 Jun 2002 20:29:27 -0000 1.158
--- src/backend/commands/copy.c 14 Jul 2002 01:33:28 -0000
***************
*** 28,33 ****
--- 28,34 ----
#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,58 ****
/* 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 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 const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
--- 47,60 ----
/* 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";
***************
*** 267,273 ****
char *filename = stmt->filename;
bool is_from = stmt->is_from;
bool pipe = (stmt->filename == NULL);
! List *option;
DefElem *dbinary = NULL;
DefElem *doids = NULL;
DefElem *ddelim = NULL;
--- 269,276 ----
char *filename = stmt->filename;
bool is_from = stmt->is_from;
bool pipe = (stmt->filename == NULL);
! List *option;
! List *attlist = stmt->attlist;
DefElem *dbinary = NULL;
DefElem *doids = NULL;
DefElem *ddelim = NULL;
***************
*** 289,313 ****
if (strcmp(defel->defname, "binary") == 0)
{
if (dbinary)
! elog(ERROR, "COPY: conflicting options");
dbinary = defel;
}
else if (strcmp(defel->defname, "oids") == 0)
{
if (doids)
! elog(ERROR, "COPY: conflicting options");
doids = defel;
}
else if (strcmp(defel->defname, "delimiter") == 0)
{
if (ddelim)
! elog(ERROR, "COPY: conflicting options");
ddelim = defel;
}
else if (strcmp(defel->defname, "null") == 0)
{
if (dnull)
! elog(ERROR, "COPY: conflicting options");
dnull = defel;
}
else
--- 292,318 ----
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
***************
*** 367,372 ****
--- 372,395 ----
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,416 ****
elog(ERROR, "COPY: %s is a directory.", filename);
}
}
! CopyFrom(rel, binary, oids, fp, delim, null_print);
}
else
{ /* copy from database to file */
--- 433,439 ----
elog(ERROR, "COPY: %s is a directory.", filename);
}
}
! CopyFrom(rel, attlist, binary, oids, fp, delim, null_print);
}
else
{ /* copy from database to file */
***************
*** 466,472 ****
elog(ERROR, "COPY: %s is a directory.", filename);
}
}
! CopyTo(rel, binary, oids, fp, delim, null_print);
}
if (!pipe)
--- 489,495 ----
elog(ERROR, "COPY: %s is a directory.", filename);
}
}
! CopyTo(rel, attlist, binary, oids, fp, delim, null_print);
}
if (!pipe)
***************
*** 494,501 ****
* Copy from relation TO file.
*/
static void
! CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
! char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
--- 517,524 ----
* Copy from relation TO file.
*/
static void
! CopyTo(Relation rel, List *attlist, bool binary, bool oids,
! FILE *fp, char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
***************
*** 509,514 ****
--- 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",
***************
*** 517,522 ****
--- 544,561 ----
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,605 ****
}
}
! for (i = 0; i < attr_count; i++)
{
Datum origvalue,
value;
bool isnull;
! origvalue = heap_getattr(tuple, i + 1, tupDesc, &isnull);
if (!binary)
{
--- 632,645 ----
}
}
! for (i = 0; i < copy_attr_count; i++)
{
Datum origvalue,
value;
bool isnull;
+ int mi = attmap[i];
! origvalue = heap_getattr(tuple, mi + 1, tupDesc, &isnull);
if (!binary)
{
***************
*** 628,652 ****
* (or for binary case, becase we must output untoasted
* value).
*/
! if (isvarlena[i])
value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
else
value = origvalue;
if (!binary)
{
! string = DatumGetCString(FunctionCall3(&out_functions[i],
value,
! ObjectIdGetDatum(elements[i]),
! Int32GetDatum(attr[i]->atttypmod)));
CopyAttributeOut(fp, string, delim);
pfree(string);
}
else
{
! fld_size = attr[i]->attlen;
CopySendData(&fld_size, sizeof(int16), fp);
! if (isvarlena[i])
{
/* varlena */
Assert(fld_size == -1);
--- 668,692 ----
* (or for binary case, becase we must output untoasted
* value).
*/
! if (isvarlena[mi])
value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
else
value = origvalue;
if (!binary)
{
! string = DatumGetCString(FunctionCall3(&out_functions[mi],
value,
! ObjectIdGetDatum(elements[mi]),
! Int32GetDatum(attr[mi]->atttypmod)));
CopyAttributeOut(fp, string, delim);
pfree(string);
}
else
{
! fld_size = attr[mi]->attlen;
CopySendData(&fld_size, sizeof(int16), fp);
! if (isvarlena[mi])
{
/* varlena */
Assert(fld_size == -1);
***************
*** 654,660 ****
VARSIZE(value),
fp);
}
! else if (!attr[i]->attbyval)
{
/* fixed-length pass-by-reference */
Assert(fld_size > 0);
--- 694,700 ----
VARSIZE(value),
fp);
}
! else if (!attr[mi]->attbyval)
{
/* fixed-length pass-by-reference */
Assert(fld_size > 0);
***************
*** 709,721 ****
* Copy FROM file to relation.
*/
static void
! CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
! char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
Form_pg_attribute *attr;
! AttrNumber attr_count;
FmgrInfo *in_functions;
Oid *elements;
int i;
--- 749,761 ----
* Copy FROM file to relation.
*/
static void
! 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, copy_attr_count, def_attr_count;
FmgrInfo *in_functions;
Oid *elements;
int i;
***************
*** 732,741 ****
--- 772,788 ----
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,772 ****
--- 805,846 ----
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,832 ****
copy_lineno = 0;
fe_eof = false;
while (!done)
{
CHECK_FOR_INTERRUPTS();
copy_lineno++;
!
/* Reset the per-output-tuple exprcontext */
ResetPerTupleExprContext(estate);
--- 895,908 ----
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,879 ****
elog(ERROR, "COPY TEXT: Invalid Oid");
}
}
!
! for (i = 0; i < attr_count && !done; i++)
{
string = CopyReadAttribute(fp, &isnull, delim,
&newline, null_print);
! if (isnull)
! {
! /* already set values[i] and nulls[i] */
}
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] = ' ';
}
}
if (!done)
CopyReadNewline(fp, &newline);
}
--- 930,971 ----
elog(ERROR, "COPY TEXT: Invalid Oid");
}
}
!
! /*
! * 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 ){
! /* 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);
}
***************
*** 975,981 ****
break;
tuple = heap_formtuple(tupDesc, values, nulls);
!
if (oids && file_has_oids)
tuple->t_data->t_oid = loaded_oid;
--- 1067,1073 ----
break;
tuple = heap_formtuple(tupDesc, values, nulls);
!
if (oids && file_has_oids)
tuple->t_data->t_oid = loaded_oid;
***************
*** 1021,1032 ****
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);
}
--- 1113,1118 ----
***************
*** 1361,1363 ****
--- 1447,1497 ----
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(;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);
+ }
+
Index: src/backend/parser/gram.y
===================================================================
RCS file: /var/cvsup/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.339
diff -c -r2.339 gram.y
*** src/backend/parser/gram.y 12 Jul 2002 18:43:17 -0000 2.339
--- src/backend/parser/gram.y 14 Jul 2002 00:49:07 -0000
***************
*** 1268,1298 ****
/*****************************************************************************
*
* QUERY :
! * COPY 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 *n = makeNode(CopyStmt);
n->relation = $3;
! n->is_from = $5;
! n->filename = $6;
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);
$$ = (Node *)n;
}
;
--- 1268,1299 ----
/*****************************************************************************
*
* QUERY :
! * 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_column_list opt_oids
! copy_from copy_file_name copy_delimiter opt_with copy_opt_list
{
CopyStmt *n = makeNode(CopyStmt);
n->relation = $3;
! 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 ($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: src/backend/rewrite/rewriteHandler.c
===================================================================
RCS file: /var/cvsup/pgsql/src/backend/rewrite/rewriteHandler.c,v
retrieving revision 1.103
diff -c -r1.103 rewriteHandler.c
*** src/backend/rewrite/rewriteHandler.c 20 Jun 2002 20:29:34 -0000 1.103
--- src/backend/rewrite/rewriteHandler.c 14 Jul 2002 00:49:07 -0000
***************
*** 43,49 ****
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);
--- 43,48 ----
***************
*** 411,417 ****
*
* If there is no default, return a NULL instead.
*/
! static Node *
build_column_default(Relation rel, int attrno)
{
TupleDesc rd_att = rel->rd_att;
--- 410,416 ----
*
* If there is no default, return a NULL instead.
*/
! Node *
build_column_default(Relation rel, int attrno)
{
TupleDesc rd_att = rel->rd_att;
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /var/cvsup/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.271
diff -c -r1.271 pg_dump.c
*** src/bin/pg_dump/pg_dump.c 12 Jul 2002 18:43:18 -0000 1.271
--- src/bin/pg_dump/pg_dump.c 14 Jul 2002 00:49:07 -0000
***************
*** 133,138 ****
--- 133,139 ----
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,847 ****
--- 843,849 ----
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,870 ****
*/
selectSourceSchema(tbinfo->relnamespace->nspname);
if (oids && hasoids)
{
! appendPQExpBuffer(q, "COPY %s WITH OIDS TO stdout;",
fmtQualifiedId(tbinfo->relnamespace->nspname,
! classname));
}
else
{
! appendPQExpBuffer(q, "COPY %s TO stdout;",
fmtQualifiedId(tbinfo->relnamespace->nspname,
! classname));
}
res = PQexec(g_conn, q->data);
if (!res ||
--- 856,874 ----
*/
selectSourceSchema(tbinfo->relnamespace->nspname);
+ column_list = fmtCopyColumnList(tbinfo);
+
if (oids && hasoids)
{
! appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
fmtQualifiedId(tbinfo->relnamespace->nspname,
! classname),column_list);
}
else
{
! appendPQExpBuffer(q, "COPY %s %s TO stdout;",
fmtQualifiedId(tbinfo->relnamespace->nspname,
! classname), column_list);
}
res = PQexec(g_conn, q->data);
if (!res ||
***************
*** 1189,1196 ****
{
/* Dump/restore using COPY */
dumpFn = dumpClasses_nodumpData;
! sprintf(copyBuf, "COPY %s %sFROM stdin;\n",
! fmtId(tblinfo[i].relname, force_quotes),
(oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
copyStmt = copyBuf;
}
--- 1193,1201 ----
{
/* Dump/restore using COPY */
dumpFn = dumpClasses_nodumpData;
! 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,5862 ****
--- 5865,5902 ----
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: src/include/nodes/parsenodes.h
===================================================================
RCS file: /var/cvsup/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.185
diff -c -r1.185 parsenodes.h
*** src/include/nodes/parsenodes.h 12 Jul 2002 18:43:19 -0000 1.185
--- src/include/nodes/parsenodes.h 14 Jul 2002 00:49:07 -0000
***************
*** 860,865 ****
--- 860,866 ----
{
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: src/include/rewrite/rewriteHandler.h
===================================================================
RCS file: /var/cvsup/pgsql/src/include/rewrite/rewriteHandler.h,v
retrieving revision 1.19
diff -c -r1.19 rewriteHandler.h
*** src/include/rewrite/rewriteHandler.h 20 Jun 2002 20:29:52 -0000 1.19
--- src/include/rewrite/rewriteHandler.h 14 Jul 2002 00:49:07 -0000
***************
*** 16,22 ****
#include "nodes/parsenodes.h"
-
extern List *QueryRewrite(Query *parsetree);
#endif /* REWRITEHANDLER_H */
--- 16,22 ----
#include "nodes/parsenodes.h"
extern List *QueryRewrite(Query *parsetree);
+ extern Node *build_column_default(Relation rel, int attrno);
#endif /* REWRITEHANDLER_H */
Index: src/test/regress/parallel_schedule
===================================================================
RCS file: /var/cvsup/pgsql/src/test/regress/parallel_schedule,v
retrieving revision 1.10
diff -c -r1.10 parallel_schedule
*** src/test/regress/parallel_schedule 20 Jun 2002 17:09:42 -0000 1.10
--- src/test/regress/parallel_schedule 14 Jul 2002 01:42:36 -0000
***************
*** 74,77 ****
# The sixth group of parallel test
# ----------
# "plpgsql" cannot run concurrently with "rules"
! test: limit plpgsql temp domain rangefuncs
--- 74,77 ----
# The sixth group of parallel test
# ----------
# "plpgsql" cannot run concurrently with "rules"
! test: limit plpgsql temp domain rangefuncs copy2
Index: src/test/regress/serial_schedule
===================================================================
RCS file: /var/cvsup/pgsql/src/test/regress/serial_schedule,v
retrieving revision 1.10
diff -c -r1.10 serial_schedule
*** src/test/regress/serial_schedule 20 Jun 2002 17:09:42 -0000 1.10
--- src/test/regress/serial_schedule 14 Jul 2002 01:42:27 -0000
***************
*** 80,85 ****
--- 80,86 ----
test: foreign_key
test: limit
test: plpgsql
+ test: copy2
test: temp
test: domain
test: rangefuncs