Number of updated rows with LibPQ

Started by Dominique Devienneover 3 years ago8 messagesgeneral
Jump to latest
#1Dominique Devienne
ddevienne@gmail.com

Hi,

Is there a way to programmatically now how many rows an UPDATE did update?
I've read about [PQcmdTuples][1]https://www.postgresql.org/docs/14/libpq-exec.html#LIBPQ-PQCMDTUPLES, but surely I shouldn't have to parse
that string, no?
For selects, I have [PQnTuples][2]https://www.postgresql.org/docs/14/libpq-exec.html#LIBPQ-PQNTUPLES, but what to do on INSERT, UPDATE, DELETE?
Parse the result of PQcmdTuples myself??? If so, what's the 0 in the
INSERT below?
Is the output of PQcmdTuples "stable", i.e. "official"? Not locale dependent?

Thanks, --DD

[1]: https://www.postgresql.org/docs/14/libpq-exec.html#LIBPQ-PQCMDTUPLES
[2]: https://www.postgresql.org/docs/14/libpq-exec.html#LIBPQ-PQNTUPLES

postgres=# create table foo (v int);
CREATE TABLE
postgres=# insert into foo values (1), (2), (3);
INSERT 0 3
postgres=# update foo set v = 2*v where v = 2;
UPDATE 1
postgres=# delete from foo where v = 3;
DELETE 1
postgres=# select v from foo where v > 1;
...
(1 row)
postgres=# delete from foo;
DELETE 2
postgres=# drop table foo;
DROP TABLE
postgres=#

#2Laurenz Albe
laurenz.albe@cybertec.at
In reply to: Dominique Devienne (#1)
Re: Number of updated rows with LibPQ

On Wed, 2022-10-05 at 16:38 +0200, Dominique Devienne wrote:

Hi,

Is there a way to programmatically now how many rows an UPDATE did update?
I've read about [PQcmdTuples][1], but surely I shouldn't have to parse
that string, no?
For selects, I have [PQnTuples][2], but what to do on INSERT, UPDATE, DELETE?
Parse the result of PQcmdTuples myself??? If so, what's the 0 in the
INSERT below?
Is the output of PQcmdTuples "stable", i.e. "official"? Not locale dependent?

Thanks, --DD

[1]: https://www.postgresql.org/docs/14/libpq-exec.html#LIBPQ-PQCMDTUPLES
[2]: https://www.postgresql.org/docs/14/libpq-exec.html#LIBPQ-PQNTUPLES

postgres=# create table foo (v int);
CREATE TABLE
postgres=# insert into foo values (1), (2), (3);
INSERT 0 3
postgres=# update foo set v = 2*v where v = 2;
UPDATE 1
postgres=# delete from foo where v = 3;
DELETE 1
postgres=# select v from foo where v > 1;
...
(1 row)
postgres=# delete from foo;
DELETE 2
postgres=# drop table foo;
DROP TABLE
postgres=#

Yes, you have to use PQcmdTuples(), and you have to convert the string to an integer.

But don't worry: the result will *not* be "INSERT 0 5", it will be just "5", so
you won't have to parse anything.

Yours,
Laurenz Albe
--
Cybertec | https://www.cybertec-postgresql.com

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Laurenz Albe (#2)
Re: Number of updated rows with LibPQ

Laurenz Albe <laurenz.albe@cybertec.at> writes:

On Wed, 2022-10-05 at 16:38 +0200, Dominique Devienne wrote:

For selects, I have [PQnTuples][2], but what to do on INSERT, UPDATE, DELETE?
Parse the result of PQcmdTuples myself??? If so, what's the 0 in the
INSERT below?

Yes, you have to use PQcmdTuples(), and you have to convert the string to an integer.
But don't worry: the result will *not* be "INSERT 0 5", it will be just "5", so
you won't have to parse anything.

Yeah, just applying atoi() or atol() to the result should be enough.

regards, tom lane

#4Dominique Devienne
ddevienne@gmail.com
In reply to: Tom Lane (#3)
Re: Number of updated rows with LibPQ

On Wed, Oct 5, 2022 at 8:17 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Laurenz Albe <laurenz.albe@cybertec.at> writes:

On Wed, 2022-10-05 at 16:38 +0200, Dominique Devienne wrote:
Yes, you have to use PQcmdTuples(), and you have to convert the string to an integer.
But don't worry: the result will *not* be "INSERT 0 5", it will be just "5"

Thanks. What's the leading 0 though, then?
I guessed it might be the number of rows returned, but it isn't, see below:

postgres=# create table foo (id serial primary key, v int);
CREATE TABLE
postgres=# insert into foo (v) values (1), (2) returning id;
id
----
1
2
(2 rows)

INSERT 0 2

Yeah, just applying atoi() or atol() to the result should be enough.

Thanks too. Since I'm in C++, I used <charconv> instead, and
discovered it can be empty something, not 0.
I guess atoi() would have hidden that distinction, and worked anyway
(returning 0).

In the same topic, I've noticed an INSERT returns PGRES_COMMAND_OK,
while an INSERT-RETURNING returns PGRES_TUPLES_OK. So there's no way
to use the status to distinguish a SELECT from anything else? A RETURNING clause
makes any statement supporting it an hybrid of a command and a query,
but then how
does one know the exact "kind" of the statement?

E.g. So how does psql show INSERT in either cases? By parsing the SQL
itself, client-side?
Or is there a libpq API on PGresult that would allow to get the type
of statement the result is from?

Thanks, --DD

#5Guillaume Lelarge
guillaume@lelarge.info
In reply to: Dominique Devienne (#4)
Re: Number of updated rows with LibPQ

Le ven. 14 oct. 2022 à 13:52, Dominique Devienne <ddevienne@gmail.com> a
écrit :

On Wed, Oct 5, 2022 at 8:17 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Laurenz Albe <laurenz.albe@cybertec.at> writes:

On Wed, 2022-10-05 at 16:38 +0200, Dominique Devienne wrote:
Yes, you have to use PQcmdTuples(), and you have to convert the string

to an integer.

But don't worry: the result will *not* be "INSERT 0 5", it will be

just "5"

Thanks. What's the leading 0 though, then?

The leading number was the OID of the inserted row if you only had one row
and if the table had OID on rows. Otherwise, it was zero. It's always 0
nowadays since you can't have OID on rows.

--
Guillaume.

#6Laurenz Albe
laurenz.albe@cybertec.at
In reply to: Dominique Devienne (#4)
Re: Number of updated rows with LibPQ

On Fri, 2022-10-14 at 13:52 +0200, Dominique Devienne wrote:

On Wed, Oct 5, 2022 at 8:17 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Laurenz Albe <laurenz.albe@cybertec.at> writes:

On Wed, 2022-10-05 at 16:38 +0200, Dominique Devienne wrote:
Yes, you have to use PQcmdTuples(), and you have to convert the string to an integer.
But don't worry: the result will *not* be "INSERT 0 5", it will be just "5"

Thanks. What's the leading 0 though, then?
I guessed it might be the number of rows returned, but it isn't, see below:

postgres=# create table foo (id serial primary key, v int);
CREATE TABLE
postgres=# insert into foo (v) values (1), (2) returning id;
 id
----
  1
  2
(2 rows)

INSERT 0 2

That 0 is the OID of the newly inserted tuple.
Since there are no more tables WITH OIDS, the number is always 0, but
is left in the output for compatibility reasons.

Yeah, just applying atoi() or atol() to the result should be enough.

Thanks too. Since I'm in C++, I used <charconv> instead, and
discovered it can be empty something, not 0.
I guess atoi() would have hidden that distinction, and worked anyway
(returning 0).

In the same topic, I've noticed an INSERT returns PGRES_COMMAND_OK,
while an INSERT-RETURNING returns PGRES_TUPLES_OK. So there's no way
to use the status to distinguish a SELECT from anything else? A RETURNING clause
makes any statement supporting it an hybrid of a command and a query,
but then how
does one know the exact "kind" of the statement?

E.g. So how does psql show INSERT in either cases? By parsing the SQL
itself, client-side?
Or is there a libpq API on PGresult that would allow to get the type
of statement the result is from?

The command tag is not what you look at.

You simply check the result from an INSERT statement. If it is PGRES_TUPLES_OK,
it must have been INSERT ... RETRUNING.

Yours,
Laurenz Albe
--
Cybertec | https://www.cybertec-postgresql.com

#7Daniel Verite
daniel@manitou-mail.org
In reply to: Laurenz Albe (#6)
Re: Number of updated rows with LibPQ

Laurenz Albe wrote:

Or is there a libpq API on PGresult that would allow to get the type
of statement the result is from?

The command tag is not what you look at.

Yet that's what psql does. from PrintQueryResult():

/* if it's INSERT/UPDATE/DELETE RETURNING, also print status */
if (last || pset.show_all_results)
{
cmdstatus = PQcmdStatus(result);
if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
strncmp(cmdstatus, "UPDATE", 6) == 0 ||
strncmp(cmdstatus, "DELETE", 6) == 0)
PrintQueryStatus(result, printStatusFout);
}

You simply check the result from an INSERT statement. If it is
PGRES_TUPLES_OK, it must have been INSERT ... RETRUNING.

Or a SELECT, or an UPDATE RETURNING, or a DELETE RETURNING.
The code still need to look at PQcmdStatus() to learn which kind it is,
if it needs to know this.

Best regards,
--
Daniel Vérité
https://postgresql.verite.pro/
Twitter: @DanielVerite

#8Dominique Devienne
ddevienne@gmail.com
In reply to: Daniel Verite (#7)
Re: Number of updated rows with LibPQ

On Fri, Oct 14, 2022 at 4:39 PM Daniel Verite <daniel@manitou-mail.org> wrote:

Or a SELECT, or an UPDATE RETURNING, or a DELETE RETURNING.
The code still need to look at PQcmdStatus() to learn which kind it is,

Thanks Daniel. This is exactly what I needed. --DD

PS: Now I wonder whether PQcmdTuples() points to the same buffer as
PQcmdStatus(), except with an offset...