From 023570f5e3a1695cb3e906079e6b87ac3720d607 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 3 Mar 2006 19:54:10 +0000 Subject: [PATCH] Make the COPY command return a command tag that includes the number of rows copied. Backend side of Volkan Yazici's recent patch, with corrections and documentation. --- doc/src/sgml/protocol.sgml | 15 ++++++++++++--- doc/src/sgml/ref/copy.sgml | 16 +++++++++++++++- src/backend/commands/copy.c | 20 ++++++++++++++++++-- src/backend/tcop/utility.c | 10 ++++++++-- src/include/commands/copy.h | 4 ++-- 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 689460ed92..73eef92fff 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1,4 +1,4 @@ - + Frontend/Backend Protocol @@ -2069,7 +2069,7 @@ CommandComplete (B) String - + The command tag. This is usually a single word that identifies which SQL command was completed. @@ -2109,7 +2109,16 @@ CommandComplete (B) FETCH rows where rows is the number of rows that have been retrieved from the cursor. - + + + + For a COPY command, the tag is + COPY rows where + rows is the number of rows copied. + (Note: the row count appears only in + PostgreSQL 8.2 and later.) + + diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index bf6b1f1c3f..e748cc2e8e 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -1,5 +1,5 @@ @@ -253,6 +253,20 @@ COPY tablename [ ( + + Outputs + + + On successful completion, a COPY command returns a command + tag of the form + +COPY count + + The count is the number + of rows inserted into or copied from the table. + + + Notes diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index af3df4a689..858815e56e 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.258 2006/02/03 12:41:07 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.259 2006/03/03 19:54:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -102,6 +102,7 @@ typedef struct CopyStateData int client_encoding; /* remote side's character encoding */ bool need_transcoding; /* client encoding diff from server? */ bool encoding_embeds_ascii; /* ASCII can be non-first byte? */ + uint64 processed; /* # of tuples processed */ /* parameters from the COPY command */ Relation rel; /* relation to copy to or from */ @@ -710,7 +711,7 @@ CopyLoadRawBuf(CopyState cstate) * Do not allow the copy if user doesn't have proper permission to access * the table. */ -void +uint64 DoCopy(const CopyStmt *stmt) { CopyState cstate; @@ -724,6 +725,7 @@ DoCopy(const CopyStmt *stmt) AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); AclResult aclresult; ListCell *option; + uint64 processed; /* Allocate workspace and zero all fields */ cstate = (CopyStateData *) palloc0(sizeof(CopyStateData)); @@ -1019,6 +1021,7 @@ DoCopy(const CopyStmt *stmt) cstate->line_buf_converted = false; cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1); cstate->raw_buf_index = cstate->raw_buf_len = 0; + cstate->processed = 0; /* Set up encoding conversion info */ cstate->client_encoding = pg_get_client_encoding(); @@ -1161,10 +1164,14 @@ DoCopy(const CopyStmt *stmt) heap_close(cstate->rel, (is_from ? NoLock : AccessShareLock)); /* Clean up storage (probably not really necessary) */ + processed = cstate->processed; + pfree(cstate->attribute_buf.data); pfree(cstate->line_buf.data); pfree(cstate->raw_buf); pfree(cstate); + + return processed; } @@ -1401,6 +1408,8 @@ CopyTo(CopyState cstate) CopySendEndOfRow(cstate); MemoryContextSwitchTo(oldcontext); + + cstate->processed++; } heap_endscan(scandesc); @@ -2002,6 +2011,13 @@ CopyFrom(CopyState cstate) /* AFTER ROW INSERT Triggers */ ExecARInsertTriggers(estate, resultRelInfo, tuple); + + /* + * We count only tuples not suppressed by a BEFORE INSERT trigger; + * this is the same definition used by execMain.c for counting + * tuples inserted by an INSERT command. + */ + cstate->processed++; } } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 9a9d138032..36c6e45393 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.253 2006/03/03 03:30:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.254 2006/03/03 19:54:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -636,7 +636,13 @@ ProcessUtility(Node *parsetree, break; case T_CopyStmt: - DoCopy((CopyStmt *) parsetree); + { + uint64 processed = DoCopy((CopyStmt *) parsetree); + + if (completionTag) + snprintf(completionTag, COMPLETION_TAG_BUFSIZE, + "COPY " UINT64_FORMAT, processed); + } break; case T_PrepareStmt: diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index 7a22c5bd8d..bd4e7812d9 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/copy.h,v 1.25 2004/12/31 22:03:28 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/commands/copy.h,v 1.26 2006/03/03 19:54:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,6 @@ #include "nodes/parsenodes.h" -extern void DoCopy(const CopyStmt *stmt); +extern uint64 DoCopy(const CopyStmt *stmt); #endif /* COPY_H */