61

I have the following line in a CREATE TABLE statement:

field1_id bigint DEFAULT nextval('table1_field1_id_seq'::regclass) NOT NULL,

What does regclass mean in the above? Is it an absolute requirement to add ::regclass?

N.B: I had seen the Postgresql documentation link which tells about regclass, but couldn't understand it.

Tms91
  • 3,456
  • 6
  • 40
  • 74
saji89
  • 2,093
  • 4
  • 27
  • 49

2 Answers2

89

No, you do not need the cast to regclass when calling a function like nextval that accepts a regclass parameter, as there is an implict cast from text to regclass. In some other contexts an explicit cast to regclass may be required.

Explanation:

::regclass is a cast, like ::integer.

regclass is a "magic" data type; it's actually an alias for oid, or "object identifier". See Object identifier types in the documentation. Casting to regclass is a shortcut way of saying "this the name of a relation, please convert it to the oid of that relation". Casts to regclass are aware of the search_path, unlike querying pg_class for a relation's oid directly, so casting to regclass isn't exactly equivalent to subquerying pg_class.

Tables are relations. So are sequences, and views. So you can get the oid of a view or sequence by casting to regclass too.

There are implicit casts defined for text to regclass, so if you omit the explicit cast and you're calling a function that accepts regclass the cast is done automatically. So you do not need it in, for example, nextval calls.

There are other places where you may. For example you can't compare text directly with oid; so you can do this:

regress=> select * from pg_class where oid = 'table1'::regclass;

but not this:

regress=> select * from pg_class where oid = 'table1';
ERROR:  invalid input syntax for type oid: "table1"
LINE 1: select * from pg_class where oid = 'table1';

Just for fun I tried to write a query that performed the equivalent operation of casting to regclass. Don't use it, it's mostly for fun, and as an attempt to demo what's actually happening. Unless you're really interested in how Pg's guts work you can stop reading here.

As I understand it, 'sequence_name'::regclass::oid is roughly equivalent to the following query:

WITH sp(sp_ord, sp_schema) AS (
  SELECT 
    generate_series(1, array_length(current_schemas('t'),1)),
    unnest(current_schemas('t'))
)
SELECT c.oid
FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid)
INNER JOIN sp ON (n.nspname = sp.sp_schema)
WHERE c.relname = 'sequence_name'
ORDER BY sp.sp_ord
LIMIT 1;

except that it's a lot shorter and a lot faster. See System information functions for the definition of current_schemas(...), etc.

In other words:

  • Get a ab array listing all schemas we have access to and pair each entry up with an ordinal number for its position in the array
  • Search pg_class for relations with matching names and associate each with its namespace (schema)
  • Sort the list of remaining relations by the order in which their schemas appeared in search_path
  • and pick the first match
Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
  • So my query line would essentially be interpreted as `nextval(oid1)`, where `oid1` is the `oid` of `table1_field1_id_seq`. Am I right? – saji89 Nov 09 '12 at 04:16
  • @saji89 Correct, but note that the cast to oid is resolved when the query is executed, not when the table is defined. This matters because if you were to drop and re-create the sequence it'd have a new oid, but the same name. The cast to oid will find the new oid. – Craig Ringer Nov 09 '12 at 04:20
  • So even if I drop a sequence, the oid of that sequence is still there in the system? – saji89 Nov 09 '12 at 04:22
  • @saji89 The row with that oid is removed from `pg_class`, where information about sequences, tables and views is kept. However, oids aren't re-used so a new oid is allocated when you create a new sequence, even if it has the same name. Try it. `CREATE SEQUENCE s1; SELECT 's1'::regclass::oid; DROP SEQUENCE s1; CREATE SEQUENCE s1; SELECT 's1'::regclass::oid;`. You'll get two different oids. If you `select * from pg_class where oid = 28327` (or whatever the first oid was) after dropping the sequence, you'll get no results because that row is gone from `pg_class`. – Craig Ringer Nov 09 '12 at 04:40
  • +1, Now its fully clear. Thanks for that clarification and your time.. And bearing with me.. ;) – saji89 Nov 09 '12 at 04:49
  • Oops, the latest update did confuse me :`'sequence_name'::regclass::oid`. in that `'sequence_name'::regclass` already is translated to oid isn't it? Then what does the last `::oid` mean? – saji89 Nov 09 '12 at 05:18
  • 1
    @saji89 Sorry, should've explained. While `regclass` is an oid internally, it's still *displayed* as a table name in `psql` output, etc. If you want to display the actual `oid`, you can cast to `oid`, which is what `'sequence_name'::regclass::oid` does; casts to `regclass` then casts that to `oid` so it isn't formatted for display anymore. As I said, `regclass` is kind of a magic type. – Craig Ringer Nov 09 '12 at 05:43
  • 3
    As a bonus, you can also cast _from_ the numerical oid, i.e. `select 1234::regclass`, which can be useful if you want to know 'what table a particular `pg_toast_` table is associated with. – GreenReaper Apr 12 '17 at 06:10
0

From what I understand of the documentation, oid are subdivided in types. regclass are database objects representing relations (so that they belong to the metadata table pg_class).

It expresses a dependency between the sequence and the DEFAULT expression (meaning the process of producing a default value if no explicit value is provided in a INSERT query for instance), so that if one emits a DROP SEQUENCE ... on the sequence, the query won't pass, unless it's cascaded (by writing DROP SEQUENCE table1_field1_id_seq CASCADE).

didierc
  • 14,572
  • 3
  • 32
  • 52
  • So, If I cascade the `DROP SEQUENCE`, the column(field) where I had used this sequence as `DEFAULT` will have that default value removed? – saji89 Nov 09 '12 at 04:30
  • I think so. It's what I understand from the documentation, but I didn't test it. – didierc Nov 09 '12 at 09:35
  • I think that the cast to that type of oid enforces the dependency relationship between the expression and the sequence, so that removing it from the definition would remove de dependency, and let you drop the sequence without cascading, but again you should test to confirm that. – didierc Nov 09 '12 at 09:43
  • @Craig Ringer said that when the type is not explicit, the type casting is resolved at query execution time, and then it infers the relationship *from* the default expression *to* the sequence, but I don't think that the engine will check dynamically if expressions are tied to the sequence (relationship *from* the sequence *to* another object), and having that `regclass` tells the engine that a relationship exists. – didierc Nov 09 '12 at 09:51