determine what column(s) form the primary key, in C extention

Started by alex maslakovalmost 6 years ago5 messagesgeneral
Jump to latest
#1alex maslakov
alex@serendipia.email

Hey. I'm creating an extention in C. An extention will be fired as, or
inside, a trigger.

What I need: dynamically, inside a trigger, identify which column, or
columns if the primary key is composed of multiple columns, form the
primary key -- their indexes or names.

I need a fast way, therefore I don't consider using SPI_exec(..) and the
like.

I was suggested to use `get_primary_key_attnos` from
`src/include/catalog/pg_constraint.h`

extern Bitmapset *get_primary_key_attnos(Oid relid, bool deferrableOk)

It returns *Bitstamp. And it's got "nwords" and "words[]". But those
return just big numbers, not something that look similar to an index of
the primary key column.

And therefore I haven't had any luck thus far.

How to do it?

#2David Rowley
dgrowleyml@gmail.com
In reply to: alex maslakov (#1)
Re: determine what column(s) form the primary key, in C extention

Hi Alex,

On Tue, 28 Jul 2020 at 05:47, alex maslakov <alex@serendipia.email> wrote:

I was suggested to use `get_primary_key_attnos` from
`src/include/catalog/pg_constraint.h`

extern Bitmapset *get_primary_key_attnos(Oid relid, bool deferrableOk)

It returns *Bitstamp. And it's got "nwords" and "words[]". But those
return just big numbers, not something that look similar to an index of
the primary key column.

And therefore I haven't had any luck thus far.

How to do it?

You'll need to loop over the return value of that function with
bms_next_member()

e.g.
pkattnos = get_primary_key_attnos(oid, false);
i = -1;
while ((i = bms_next_member(pkattnos , i)) >= 0)
{
/* do stuff with i */
/* you'll need to use i - FirstLowInvalidHeapAttributeNumber to get
the pg_attribute.attnum */
}

For the future, for questions, you should use the general list. If
the question is very source code related then you might have more luck
in pgsql-hackers. This is not the right list. Please post any
followup questions on one of those lists.

Note the description for this list, per
https://www.postgresql.org/list/ is "Notification of git commits are
sent to this list. Do not post here!"

David

#3alex maslakov
alex@serendipia.email
In reply to: David Rowley (#2)
Re: determine what column(s) form the primary key, in C extention

I'm emailing it to the 'general' list.

(1)

This:

    int i = -1;
    while ((i = bms_next_member(pkattnos , i)) >= 0) {
        /* do stuff with i */
        /* you'll need to use i - FirstLowInvalidHeapAttributeNumber to
get the pg_attribute.attnum */

        elog(INFO, "bms_next_member i: %d", i);
    }

prints 10 and then 9

Then:

  10 - FirstLowInvalidHeapAttributeNumber (-8) ==> 2

  9 - FirstLowInvalidHeapAttributeNumber (-8) ==> 1

These are indexes of the columns, right?

Do they start from 1, not from 0?

(2)

I'll use this C code as an example to build an extention in Rust. The
Postgresql bindings for Rust I have don't contain a definition of
`FirstLowInvalidHeapAttributeNumber` for some reason. I can define it
since it's simply single digit constant.

However what does in some source files it's defined as (-7) and in some
as (-8)? Which should I use?

El 28/07/2020 a las 03:20, David Rowley escribió:

Show quoted text

Hi Alex,

On Tue, 28 Jul 2020 at 05:47, alex maslakov <alex@serendipia.email> wrote:

I was suggested to use `get_primary_key_attnos` from
`src/include/catalog/pg_constraint.h`

extern Bitmapset *get_primary_key_attnos(Oid relid, bool deferrableOk)

It returns *Bitstamp. And it's got "nwords" and "words[]". But those
return just big numbers, not something that look similar to an index of
the primary key column.

And therefore I haven't had any luck thus far.

How to do it?

You'll need to loop over the return value of that function with
bms_next_member()

e.g.
pkattnos = get_primary_key_attnos(oid, false);
i = -1;
while ((i = bms_next_member(pkattnos , i)) >= 0)
{
/* do stuff with i */
/* you'll need to use i - FirstLowInvalidHeapAttributeNumber to get
the pg_attribute.attnum */
}

For the future, for questions, you should use the general list. If
the question is very source code related then you might have more luck
in pgsql-hackers. This is not the right list. Please post any
followup questions on one of those lists.

Note the description for this list, per
https://www.postgresql.org/list/ is "Notification of git commits are
sent to this list. Do not post here!"

David

#4David Rowley
dgrowleyml@gmail.com
In reply to: alex maslakov (#3)
Re: determine what column(s) form the primary key, in C extention

On Wed, 29 Jul 2020 at 03:45, alex maslakov <alex@serendipia.email> wrote:

int i = -1;
while ((i = bms_next_member(pkattnos , i)) >= 0) {
/* do stuff with i */
/* you'll need to use i - FirstLowInvalidHeapAttributeNumber to
get the pg_attribute.attnum */

elog(INFO, "bms_next_member i: %d", i);
}

prints 10 and then 9

Then:

10 - FirstLowInvalidHeapAttributeNumber (-8) ==> 2

9 - FirstLowInvalidHeapAttributeNumber (-8) ==> 1

These are indexes of the columns, right?

Do they start from 1, not from 0?

User attributes start at 1. Have a look at the pg_attribute system
catalogue table. The number you get will be the attnum column from
that table.

(2)

I'll use this C code as an example to build an extention in Rust. The
Postgresql bindings for Rust I have don't contain a definition of
`FirstLowInvalidHeapAttributeNumber` for some reason. I can define it
since it's simply single digit constant.

However what does in some source files it's defined as (-7) and in some
as (-8)? Which should I use?

It did recently change from -8 to -7 when we removed Oid as a system
column in pg12. The number will never change on a major version, so
you'll always know what it is for versions that have already been
released. There's always a chance it'll change from -7 in some future
PostgreSQL version though.

David

#5James Sewell
james.sewell@gmail.com
In reply to: alex maslakov (#3)
Re: determine what column(s) form the primary key, in C extention

(2)

I'll use this C code as an example to build an extention in Rust. The
Postgresql bindings for Rust I have don't contain a definition of
`FirstLowInvalidHeapAttributeNumber` for some reason. I can define it
since it's simply single digit constant.

Not an answer to your question - but use better bindings!
https://github.com/zombodb/pgx <https://github.com/zombodb/pgx&gt;

[nix-shell:~/rust/pgx_master]$ grep -R FirstLowInvalidHeapAttributeNumber
pgx-pg-sys/
pgx-pg-sys/generated-bindings/pg12_specific.rs:pub const
FirstLowInvalidHeapAttributeNumber: i32 = -7;

Which is obviously not quite right still, so I pushed a version with some
extra includes. Now you will get:

[nix-shell:~/rust/pgx_master]$ grep -R FirstLowInvalidHeapAttributeNumber
./pgx-pg-sys/
./pgx-pg-sys/generated-bindings/pg10_specific.rs:pub const
FirstLowInvalidHeapAttributeNumber: i32 = -8;
./pgx-pg-sys/generated-bindings/pg12_specific.rs:pub const
FirstLowInvalidHeapAttributeNumber: i32 = -7;
./pgx-pg-sys/generated-bindings/pg11_specific.rs:pub const
FirstLowInvalidHeapAttributeNumber: i32 = -8;

You'll need to use the Github version not the crates.io until the next
release if you want all the versions.