Re: ToDo: allow to get a number of processed rows by COPY statement

Lists: pgsql-hackers
From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: ToDo: allow to get a number of processed rows by COPY statement
Date: 2011-10-04 10:22:19
Message-ID: CAFj8pRAeEUSP8zuNkNcMP1gkr_i9KVN76S+A+13ehj=Z8E5Wow@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Hello

There is not possible to get a number of processed rows when COPY is
evaluated via SPI. Client can use a tag, but SPI doesn't use a tag.

I propose a small change a ProcessUtility to return a processed rows.

Note: I found a small inconsistency between SPI and Utility interface.
SPI still use a 4 byte unsign int for storing a number of processed
rows. Utility use a 8bytes unsign int.

Motivation:

postgres=# \sf fx
CREATE OR REPLACE FUNCTION public.fx(tablename text, filename text)
RETURNS integer
LANGUAGE plpgsql
AS $function$
declare r int;
begin
execute format('COPY %s FROM %s', quote_ident(tablename),
quote_literal(filename));
get diagnostics r = row_count;
return r;
end;
$function$

Regards

Pavel Stehule

Attachment Content-Type Size
copy_processed_rows.diff text/x-patch 5.5 KB

From: "Kevin Grittner" <Kevin(dot)Grittner(at)wicourts(dot)gov>
To: "Pavel Stehule" <pavel(dot)stehule(at)gmail(dot)com>, "PostgreSQL Hackers" <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: ToDo: allow to get a number of processed rows by COPY statement
Date: 2011-10-07 18:17:12
Message-ID: 4E8EFBD80200002500041BB5@gw.wicourts.gov
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com> wrote:

> There is not possible to get a number of processed rows when COPY
> is evaluated via SPI. Client can use a tag, but SPI doesn't use a
> tag.
>
> I propose a small change a ProcessUtility to return a processed
> rows.

Please add this to the open CommitFest:

https://commitfest.postgresql.org/action/commitfest_view/open

-Kevin


From: Bruce Momjian <bruce(at)momjian(dot)us>
To: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
Cc: PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: ToDo: allow to get a number of processed rows by COPY statement
Date: 2012-08-16 02:31:45
Message-ID: 20120816023145.GH8353@momjian.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers


What ever happened to this patch? I don't see it on any of the
commit-fests, though someone was asked for it to be added:

http://archives.postgresql.org/pgsql-hackers/2011-10/msg00381.php

---------------------------------------------------------------------------

On Tue, Oct 4, 2011 at 12:22:19PM +0200, Pavel Stehule wrote:
> Hello
>
> There is not possible to get a number of processed rows when COPY is
> evaluated via SPI. Client can use a tag, but SPI doesn't use a tag.
>
> I propose a small change a ProcessUtility to return a processed rows.
>
> Note: I found a small inconsistency between SPI and Utility interface.
> SPI still use a 4 byte unsign int for storing a number of processed
> rows. Utility use a 8bytes unsign int.
>
> Motivation:
>
> postgres=# \sf fx
> CREATE OR REPLACE FUNCTION public.fx(tablename text, filename text)
> RETURNS integer
> LANGUAGE plpgsql
> AS $function$
> declare r int;
> begin
> execute format('COPY %s FROM %s', quote_ident(tablename),
> quote_literal(filename));
> get diagnostics r = row_count;
> return r;
> end;
> $function$
>
> Regards
>
> Pavel Stehule

> diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
> index 398bc40..a7c2b8f 100644
> --- a/src/backend/executor/functions.c
> +++ b/src/backend/executor/functions.c
> @@ -600,6 +600,7 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
> es->qd->params,
> false, /* not top level */
> es->qd->dest,
> + NULL,
> NULL);
> result = true; /* never stops early */
> }
> diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
> index 688279c..21cabcc 100644
> --- a/src/backend/executor/spi.c
> +++ b/src/backend/executor/spi.c
> @@ -1838,6 +1838,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
> {
> Node *stmt = (Node *) lfirst(lc2);
> bool canSetTag;
> + bool isCopyStmt = false;
> DestReceiver *dest;
>
> _SPI_current->processed = 0;
> @@ -1857,6 +1858,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
> {
> CopyStmt *cstmt = (CopyStmt *) stmt;
>
> + isCopyStmt = true;
> if (cstmt->filename == NULL)
> {
> my_res = SPI_ERROR_COPY;
> @@ -1911,16 +1913,23 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
> }
> else
> {
> + uint32 processed;
> +
> ProcessUtility(stmt,
> plansource->query_string,
> paramLI,
> false, /* not top level */
> dest,
> - NULL);
> + NULL,
> + &processed);
> /* Update "processed" if stmt returned tuples */
> +
> if (_SPI_current->tuptable)
> _SPI_current->processed = _SPI_current->tuptable->alloced -
> _SPI_current->tuptable->free;
> + else if (canSetTag && isCopyStmt)
> + _SPI_current->processed = processed;
> +
> res = SPI_OK_UTILITY;
> }
>
> diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
> index 466727b..1a861ee 100644
> --- a/src/backend/tcop/pquery.c
> +++ b/src/backend/tcop/pquery.c
> @@ -1184,7 +1184,8 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
> portal->portalParams,
> isTopLevel,
> dest,
> - completionTag);
> + completionTag,
> + NULL);
>
> /* Some utility statements may change context on us */
> MemoryContextSwitchTo(PortalGetHeapMemory(portal));
> diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
> index 0749227..35db28c 100644
> --- a/src/backend/tcop/utility.c
> +++ b/src/backend/tcop/utility.c
> @@ -319,6 +319,9 @@ CheckRestrictedOperation(const char *cmdname)
> * completionTag is only set nonempty if we want to return a nondefault status.
> *
> * completionTag may be NULL if caller doesn't want a status string.
> + *
> + * processed may be NULL if caller doesn't want a number of processed rows
> + * by COPY statement
> */
> void
> ProcessUtility(Node *parsetree,
> @@ -326,7 +329,8 @@ ProcessUtility(Node *parsetree,
> ParamListInfo params,
> bool isTopLevel,
> DestReceiver *dest,
> - char *completionTag)
> + char *completionTag,
> + uint32 *processed)
> {
> Assert(queryString != NULL); /* required as of 8.4 */
>
> @@ -337,10 +341,10 @@ ProcessUtility(Node *parsetree,
> */
> if (ProcessUtility_hook)
> (*ProcessUtility_hook) (parsetree, queryString, params,
> - isTopLevel, dest, completionTag);
> + isTopLevel, dest, completionTag, processed);
> else
> standard_ProcessUtility(parsetree, queryString, params,
> - isTopLevel, dest, completionTag);
> + isTopLevel, dest, completionTag, processed);
> }
>
> void
> @@ -349,7 +353,8 @@ standard_ProcessUtility(Node *parsetree,
> ParamListInfo params,
> bool isTopLevel,
> DestReceiver *dest,
> - char *completionTag)
> + char *completionTag,
> + uint32 *processed)
> {
> check_xact_readonly(parsetree);
>
> @@ -571,6 +576,7 @@ standard_ProcessUtility(Node *parsetree,
> params,
> false,
> None_Receiver,
> + NULL,
> NULL);
> }
>
> @@ -716,12 +722,14 @@ standard_ProcessUtility(Node *parsetree,
>
> case T_CopyStmt:
> {
> - uint64 processed;
> + uint64 _processed;
>
> - processed = DoCopy((CopyStmt *) parsetree, queryString);
> + _processed = DoCopy((CopyStmt *) parsetree, queryString);
> if (completionTag)
> snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
> - "COPY " UINT64_FORMAT, processed);
> + "COPY " UINT64_FORMAT, _processed);
> + if (processed != NULL)
> + *processed = (uint32) _processed;
> }
> break;
>
> @@ -782,6 +790,7 @@ standard_ProcessUtility(Node *parsetree,
> params,
> false,
> None_Receiver,
> + NULL,
> NULL);
> }
>
> diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
> index c21857a..86fad4b 100644
> --- a/src/include/tcop/utility.h
> +++ b/src/include/tcop/utility.h
> @@ -20,15 +20,16 @@
> /* Hook for plugins to get control in ProcessUtility() */
> typedef void (*ProcessUtility_hook_type) (Node *parsetree,
> const char *queryString, ParamListInfo params, bool isTopLevel,
> - DestReceiver *dest, char *completionTag);
> + DestReceiver *dest, char *completionTag,
> + uint32 *processed);
> extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
>
> extern void ProcessUtility(Node *parsetree, const char *queryString,
> ParamListInfo params, bool isTopLevel,
> - DestReceiver *dest, char *completionTag);
> + DestReceiver *dest, char *completionTag, uint32 *processed);
> extern void standard_ProcessUtility(Node *parsetree, const char *queryString,
> ParamListInfo params, bool isTopLevel,
> - DestReceiver *dest, char *completionTag);
> + DestReceiver *dest, char *completionTag, uint32 *processed);
>
> extern bool UtilityReturnsTuples(Node *parsetree);
>

>
> --
> Sent via pgsql-hackers mailing list (pgsql-hackers(at)postgresql(dot)org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers

--
Bruce Momjian <bruce(at)momjian(dot)us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +


From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: Bruce Momjian <bruce(at)momjian(dot)us>
Cc: PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: ToDo: allow to get a number of processed rows by COPY statement
Date: 2012-08-16 04:12:10
Message-ID: CAFj8pRDOWm19H4jcknsMSX668RK+64VOZg5r6MiXEz_Q4+hB9A@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Hello

I can reassign it again

Regards

Pavel

2012/8/16 Bruce Momjian <bruce(at)momjian(dot)us>:
>
> What ever happened to this patch? I don't see it on any of the
> commit-fests, though someone was asked for it to be added:
>
> http://archives.postgresql.org/pgsql-hackers/2011-10/msg00381.php
>
> ---------------------------------------------------------------------------
>
> On Tue, Oct 4, 2011 at 12:22:19PM +0200, Pavel Stehule wrote:
>> Hello
>>
>> There is not possible to get a number of processed rows when COPY is
>> evaluated via SPI. Client can use a tag, but SPI doesn't use a tag.
>>
>> I propose a small change a ProcessUtility to return a processed rows.
>>
>> Note: I found a small inconsistency between SPI and Utility interface.
>> SPI still use a 4 byte unsign int for storing a number of processed
>> rows. Utility use a 8bytes unsign int.
>>
>> Motivation:
>>
>> postgres=# \sf fx
>> CREATE OR REPLACE FUNCTION public.fx(tablename text, filename text)
>> RETURNS integer
>> LANGUAGE plpgsql
>> AS $function$
>> declare r int;
>> begin
>> execute format('COPY %s FROM %s', quote_ident(tablename),
>> quote_literal(filename));
>> get diagnostics r = row_count;
>> return r;
>> end;
>> $function$
>>
>> Regards
>>
>> Pavel Stehule
>
>> diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
>> index 398bc40..a7c2b8f 100644
>> --- a/src/backend/executor/functions.c
>> +++ b/src/backend/executor/functions.c
>> @@ -600,6 +600,7 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
>> es->qd->params,
>> false, /* not top level */
>> es->qd->dest,
>> + NULL,
>> NULL);
>> result = true; /* never stops early */
>> }
>> diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
>> index 688279c..21cabcc 100644
>> --- a/src/backend/executor/spi.c
>> +++ b/src/backend/executor/spi.c
>> @@ -1838,6 +1838,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
>> {
>> Node *stmt = (Node *) lfirst(lc2);
>> bool canSetTag;
>> + bool isCopyStmt = false;
>> DestReceiver *dest;
>>
>> _SPI_current->processed = 0;
>> @@ -1857,6 +1858,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
>> {
>> CopyStmt *cstmt = (CopyStmt *) stmt;
>>
>> + isCopyStmt = true;
>> if (cstmt->filename == NULL)
>> {
>> my_res = SPI_ERROR_COPY;
>> @@ -1911,16 +1913,23 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
>> }
>> else
>> {
>> + uint32 processed;
>> +
>> ProcessUtility(stmt,
>> plansource->query_string,
>> paramLI,
>> false, /* not top level */
>> dest,
>> - NULL);
>> + NULL,
>> + &processed);
>> /* Update "processed" if stmt returned tuples */
>> +
>> if (_SPI_current->tuptable)
>> _SPI_current->processed = _SPI_current->tuptable->alloced -
>> _SPI_current->tuptable->free;
>> + else if (canSetTag && isCopyStmt)
>> + _SPI_current->processed = processed;
>> +
>> res = SPI_OK_UTILITY;
>> }
>>
>> diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
>> index 466727b..1a861ee 100644
>> --- a/src/backend/tcop/pquery.c
>> +++ b/src/backend/tcop/pquery.c
>> @@ -1184,7 +1184,8 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
>> portal->portalParams,
>> isTopLevel,
>> dest,
>> - completionTag);
>> + completionTag,
>> + NULL);
>>
>> /* Some utility statements may change context on us */
>> MemoryContextSwitchTo(PortalGetHeapMemory(portal));
>> diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
>> index 0749227..35db28c 100644
>> --- a/src/backend/tcop/utility.c
>> +++ b/src/backend/tcop/utility.c
>> @@ -319,6 +319,9 @@ CheckRestrictedOperation(const char *cmdname)
>> * completionTag is only set nonempty if we want to return a nondefault status.
>> *
>> * completionTag may be NULL if caller doesn't want a status string.
>> + *
>> + * processed may be NULL if caller doesn't want a number of processed rows
>> + * by COPY statement
>> */
>> void
>> ProcessUtility(Node *parsetree,
>> @@ -326,7 +329,8 @@ ProcessUtility(Node *parsetree,
>> ParamListInfo params,
>> bool isTopLevel,
>> DestReceiver *dest,
>> - char *completionTag)
>> + char *completionTag,
>> + uint32 *processed)
>> {
>> Assert(queryString != NULL); /* required as of 8.4 */
>>
>> @@ -337,10 +341,10 @@ ProcessUtility(Node *parsetree,
>> */
>> if (ProcessUtility_hook)
>> (*ProcessUtility_hook) (parsetree, queryString, params,
>> - isTopLevel, dest, completionTag);
>> + isTopLevel, dest, completionTag, processed);
>> else
>> standard_ProcessUtility(parsetree, queryString, params,
>> - isTopLevel, dest, completionTag);
>> + isTopLevel, dest, completionTag, processed);
>> }
>>
>> void
>> @@ -349,7 +353,8 @@ standard_ProcessUtility(Node *parsetree,
>> ParamListInfo params,
>> bool isTopLevel,
>> DestReceiver *dest,
>> - char *completionTag)
>> + char *completionTag,
>> + uint32 *processed)
>> {
>> check_xact_readonly(parsetree);
>>
>> @@ -571,6 +576,7 @@ standard_ProcessUtility(Node *parsetree,
>> params,
>> false,
>> None_Receiver,
>> + NULL,
>> NULL);
>> }
>>
>> @@ -716,12 +722,14 @@ standard_ProcessUtility(Node *parsetree,
>>
>> case T_CopyStmt:
>> {
>> - uint64 processed;
>> + uint64 _processed;
>>
>> - processed = DoCopy((CopyStmt *) parsetree, queryString);
>> + _processed = DoCopy((CopyStmt *) parsetree, queryString);
>> if (completionTag)
>> snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
>> - "COPY " UINT64_FORMAT, processed);
>> + "COPY " UINT64_FORMAT, _processed);
>> + if (processed != NULL)
>> + *processed = (uint32) _processed;
>> }
>> break;
>>
>> @@ -782,6 +790,7 @@ standard_ProcessUtility(Node *parsetree,
>> params,
>> false,
>> None_Receiver,
>> + NULL,
>> NULL);
>> }
>>
>> diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
>> index c21857a..86fad4b 100644
>> --- a/src/include/tcop/utility.h
>> +++ b/src/include/tcop/utility.h
>> @@ -20,15 +20,16 @@
>> /* Hook for plugins to get control in ProcessUtility() */
>> typedef void (*ProcessUtility_hook_type) (Node *parsetree,
>> const char *queryString, ParamListInfo params, bool isTopLevel,
>> - DestReceiver *dest, char *completionTag);
>> + DestReceiver *dest, char *completionTag,
>> + uint32 *processed);
>> extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
>>
>> extern void ProcessUtility(Node *parsetree, const char *queryString,
>> ParamListInfo params, bool isTopLevel,
>> - DestReceiver *dest, char *completionTag);
>> + DestReceiver *dest, char *completionTag, uint32 *processed);
>> extern void standard_ProcessUtility(Node *parsetree, const char *queryString,
>> ParamListInfo params, bool isTopLevel,
>> - DestReceiver *dest, char *completionTag);
>> + DestReceiver *dest, char *completionTag, uint32 *processed);
>>
>> extern bool UtilityReturnsTuples(Node *parsetree);
>>
>
>>
>> --
>> Sent via pgsql-hackers mailing list (pgsql-hackers(at)postgresql(dot)org)
>> To make changes to your subscription:
>> http://www.postgresql.org/mailpref/pgsql-hackers
>
>
> --
> Bruce Momjian <bruce(at)momjian(dot)us> http://momjian.us
> EnterpriseDB http://enterprisedb.com
>
> + It's impossible for everything to be true. +


From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: Bruce Momjian <bruce(at)momjian(dot)us>
Cc: PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: ToDo: allow to get a number of processed rows by COPY statement
Date: 2012-08-16 11:43:25
Message-ID: CAFj8pRByTazObQmAWj6KVnGd_uUPY470s1_oK=_AQfSSp1=XsQ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Hello

here is updated patch

postgres=# copy omega to '/tmp/xxx';
COPY 60
postgres=# do $$ declare r int;
begin
copy omega from '/tmp/xxx'; get diagnostics r = row_count; raise
notice '>>> %', r;
end;
$$ language plpgsql;
NOTICE: >>> 60
DO

Regards

Pavel

2012/8/16 Bruce Momjian <bruce(at)momjian(dot)us>:
>
> What ever happened to this patch? I don't see it on any of the
> commit-fests, though someone was asked for it to be added:
>
> http://archives.postgresql.org/pgsql-hackers/2011-10/msg00381.php
>
> ---------------------------------------------------------------------------
>
> On Tue, Oct 4, 2011 at 12:22:19PM +0200, Pavel Stehule wrote:
>> Hello
>>
>> There is not possible to get a number of processed rows when COPY is
>> evaluated via SPI. Client can use a tag, but SPI doesn't use a tag.
>>
>> I propose a small change a ProcessUtility to return a processed rows.
>>
>> Note: I found a small inconsistency between SPI and Utility interface.
>> SPI still use a 4 byte unsign int for storing a number of processed
>> rows. Utility use a 8bytes unsign int.
>>
>> Motivation:
>>
>> postgres=# \sf fx
>> CREATE OR REPLACE FUNCTION public.fx(tablename text, filename text)
>> RETURNS integer
>> LANGUAGE plpgsql
>> AS $function$
>> declare r int;
>> begin
>> execute format('COPY %s FROM %s', quote_ident(tablename),
>> quote_literal(filename));
>> get diagnostics r = row_count;
>> return r;
>> end;
>> $function$
>>
>> Regards
>>
>> Pavel Stehule
>
>> diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
>> index 398bc40..a7c2b8f 100644
>> --- a/src/backend/executor/functions.c
>> +++ b/src/backend/executor/functions.c
>> @@ -600,6 +600,7 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
>> es->qd->params,
>> false, /* not top level */
>> es->qd->dest,
>> + NULL,
>> NULL);
>> result = true; /* never stops early */
>> }
>> diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
>> index 688279c..21cabcc 100644
>> --- a/src/backend/executor/spi.c
>> +++ b/src/backend/executor/spi.c
>> @@ -1838,6 +1838,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
>> {
>> Node *stmt = (Node *) lfirst(lc2);
>> bool canSetTag;
>> + bool isCopyStmt = false;
>> DestReceiver *dest;
>>
>> _SPI_current->processed = 0;
>> @@ -1857,6 +1858,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
>> {
>> CopyStmt *cstmt = (CopyStmt *) stmt;
>>
>> + isCopyStmt = true;
>> if (cstmt->filename == NULL)
>> {
>> my_res = SPI_ERROR_COPY;
>> @@ -1911,16 +1913,23 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
>> }
>> else
>> {
>> + uint32 processed;
>> +
>> ProcessUtility(stmt,
>> plansource->query_string,
>> paramLI,
>> false, /* not top level */
>> dest,
>> - NULL);
>> + NULL,
>> + &processed);
>> /* Update "processed" if stmt returned tuples */
>> +
>> if (_SPI_current->tuptable)
>> _SPI_current->processed = _SPI_current->tuptable->alloced -
>> _SPI_current->tuptable->free;
>> + else if (canSetTag && isCopyStmt)
>> + _SPI_current->processed = processed;
>> +
>> res = SPI_OK_UTILITY;
>> }
>>
>> diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
>> index 466727b..1a861ee 100644
>> --- a/src/backend/tcop/pquery.c
>> +++ b/src/backend/tcop/pquery.c
>> @@ -1184,7 +1184,8 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
>> portal->portalParams,
>> isTopLevel,
>> dest,
>> - completionTag);
>> + completionTag,
>> + NULL);
>>
>> /* Some utility statements may change context on us */
>> MemoryContextSwitchTo(PortalGetHeapMemory(portal));
>> diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
>> index 0749227..35db28c 100644
>> --- a/src/backend/tcop/utility.c
>> +++ b/src/backend/tcop/utility.c
>> @@ -319,6 +319,9 @@ CheckRestrictedOperation(const char *cmdname)
>> * completionTag is only set nonempty if we want to return a nondefault status.
>> *
>> * completionTag may be NULL if caller doesn't want a status string.
>> + *
>> + * processed may be NULL if caller doesn't want a number of processed rows
>> + * by COPY statement
>> */
>> void
>> ProcessUtility(Node *parsetree,
>> @@ -326,7 +329,8 @@ ProcessUtility(Node *parsetree,
>> ParamListInfo params,
>> bool isTopLevel,
>> DestReceiver *dest,
>> - char *completionTag)
>> + char *completionTag,
>> + uint32 *processed)
>> {
>> Assert(queryString != NULL); /* required as of 8.4 */
>>
>> @@ -337,10 +341,10 @@ ProcessUtility(Node *parsetree,
>> */
>> if (ProcessUtility_hook)
>> (*ProcessUtility_hook) (parsetree, queryString, params,
>> - isTopLevel, dest, completionTag);
>> + isTopLevel, dest, completionTag, processed);
>> else
>> standard_ProcessUtility(parsetree, queryString, params,
>> - isTopLevel, dest, completionTag);
>> + isTopLevel, dest, completionTag, processed);
>> }
>>
>> void
>> @@ -349,7 +353,8 @@ standard_ProcessUtility(Node *parsetree,
>> ParamListInfo params,
>> bool isTopLevel,
>> DestReceiver *dest,
>> - char *completionTag)
>> + char *completionTag,
>> + uint32 *processed)
>> {
>> check_xact_readonly(parsetree);
>>
>> @@ -571,6 +576,7 @@ standard_ProcessUtility(Node *parsetree,
>> params,
>> false,
>> None_Receiver,
>> + NULL,
>> NULL);
>> }
>>
>> @@ -716,12 +722,14 @@ standard_ProcessUtility(Node *parsetree,
>>
>> case T_CopyStmt:
>> {
>> - uint64 processed;
>> + uint64 _processed;
>>
>> - processed = DoCopy((CopyStmt *) parsetree, queryString);
>> + _processed = DoCopy((CopyStmt *) parsetree, queryString);
>> if (completionTag)
>> snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
>> - "COPY " UINT64_FORMAT, processed);
>> + "COPY " UINT64_FORMAT, _processed);
>> + if (processed != NULL)
>> + *processed = (uint32) _processed;
>> }
>> break;
>>
>> @@ -782,6 +790,7 @@ standard_ProcessUtility(Node *parsetree,
>> params,
>> false,
>> None_Receiver,
>> + NULL,
>> NULL);
>> }
>>
>> diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
>> index c21857a..86fad4b 100644
>> --- a/src/include/tcop/utility.h
>> +++ b/src/include/tcop/utility.h
>> @@ -20,15 +20,16 @@
>> /* Hook for plugins to get control in ProcessUtility() */
>> typedef void (*ProcessUtility_hook_type) (Node *parsetree,
>> const char *queryString, ParamListInfo params, bool isTopLevel,
>> - DestReceiver *dest, char *completionTag);
>> + DestReceiver *dest, char *completionTag,
>> + uint32 *processed);
>> extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
>>
>> extern void ProcessUtility(Node *parsetree, const char *queryString,
>> ParamListInfo params, bool isTopLevel,
>> - DestReceiver *dest, char *completionTag);
>> + DestReceiver *dest, char *completionTag, uint32 *processed);
>> extern void standard_ProcessUtility(Node *parsetree, const char *queryString,
>> ParamListInfo params, bool isTopLevel,
>> - DestReceiver *dest, char *completionTag);
>> + DestReceiver *dest, char *completionTag, uint32 *processed);
>>
>> extern bool UtilityReturnsTuples(Node *parsetree);
>>
>
>>
>> --
>> Sent via pgsql-hackers mailing list (pgsql-hackers(at)postgresql(dot)org)
>> To make changes to your subscription:
>> http://www.postgresql.org/mailpref/pgsql-hackers
>
>
> --
> Bruce Momjian <bruce(at)momjian(dot)us> http://momjian.us
> EnterpriseDB http://enterprisedb.com
>
> + It's impossible for everything to be true. +

Attachment Content-Type Size
copy-processed.diff application/octet-stream 14.1 KB

From: Heikki Linnakangas <hlinnakangas(at)vmware(dot)com>
To: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
Cc: Bruce Momjian <bruce(at)momjian(dot)us>, PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: ToDo: allow to get a number of processed rows by COPY statement
Date: 2012-09-19 12:32:03
Message-ID: 5059BB43.20008@vmware.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

On 16.08.2012 14:43, Pavel Stehule wrote:
> Hello
>
> here is updated patch

The patch seems to be truncated, it ends with:

*** a/src/test/regress/input/copy.source
--- b/src/test/regress/input/copy.source
***************
*** 106,108 **** this is just a line full of junk that would error out
if parsed
--- 106,112 ----
\.

copy copytest3 to stdout csv header;
+
+ -- copy should to return processed rows
+ do $$
+

I believe the code changes are OK, but regression test changes are
missing. Can you resend the full patch, please?

- Heikki