23
By: Lloyd Albin 11/6/2012 Serial versus Serial What they don’t tell you about referential integrity and serials.

Serial versus Serial What they don’t tell you about referential integrity and serials

  • Upload
    gaye

  • View
    56

  • Download
    0

Embed Size (px)

DESCRIPTION

Serial versus Serial What they don’t tell you about referential integrity and serials. By: Lloyd Albin 11/6/2012. Serials. Serials are really integers that have a sequence attached to provide the capability to have a auto incrementing integer. There are three sizes of serials:. - PowerPoint PPT Presentation

Citation preview

Page 1: Serial versus Serial What they don’t tell you about referential integrity and serials

By: Lloyd Albin11/6/2012

Serial versus SerialWhat they don’t tell you about

referential integrity and serials.

Page 2: Serial versus Serial What they don’t tell you about referential integrity and serials

Serials are really integers that have a sequence attached to provide the capability to have a auto incrementing integer.

There are three sizes of serials:

Serials

Name Storage Size Rangesmallserial 2 bytes 1 to 32,767serial 4 bytes 1 to 2,147,483,647bigserial 8 bytes 1 to

9,223,372,036,854,775,807

Page 3: Serial versus Serial What they don’t tell you about referential integrity and serials

The simplest way to create a serial is to use the serial type.

CREATE TABLE tablename (colname SERIAL

);

Using the serial type will cause this notice to show up.

NOTICE: CREATE TABLE will create implicit sequence "tablename_colname_seq" for serial column "tablename.colname"

Creating a Serial (Short Method)

Page 4: Serial versus Serial What they don’t tell you about referential integrity and serials

The notice can be avoided by creating a serial the long method.

CREATE SEQUENCE tablename_colname_seq;

CREATE TABLE tablename ( colname integer NOT NULL DEFAULT nextval('tablename_colname_seq'));

ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

Creating a Serial (Long Method)

Page 5: Serial versus Serial What they don’t tell you about referential integrity and serials

The dump method does the same thing but in a different order and does two extra command.

CREATE TABLE tablename ( colname integer NOT NULL);

CREATE SEQUENCE tablename_colname_seq;

ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

SELECT pg_catalog.setval('tablename_colname_seq', 1, true);

ALTER TABLE tablename ALTER COLUMN colname SET DEFAULT nextval('tablename_colname_seq'::regclass);

Creating a Serial (Dump Method)

Page 6: Serial versus Serial What they don’t tell you about referential integrity and serials

Thus, we have created an integer column and arranged for its default values to be assigned from a sequence generator. A NOT NULL constraint is applied to ensure that a null value cannot be inserted. (In most cases you would also want to attach a UNIQUE or PRIMARY KEY constraint to prevent duplicate values from being inserted by accident, but this is not automatic.) Lastly, the sequence is marked as "owned by" the column, so that it will be dropped if the column or table is dropped.

The sequence created for a serial column is automatically dropped when the owning column is dropped. You can drop the sequence without dropping the column, but this will force removal of the column default expression.

Notes about Serials

Page 7: Serial versus Serial What they don’t tell you about referential integrity and serials

When you need to move a table with a serial, you may just simply move the table and the sequence will automatically move with the table.

ALTER TABLE old_schemaname.tablenameSET SCHEMA new_schemaname;

Moving Tables with Serials

Page 8: Serial versus Serial What they don’t tell you about referential integrity and serials

When you need to delete a table with a serial, you may just simply delete the table and the sequence will automatically be deleted with the table.

DROP TABLE tablename;

Even if you use restrict, the sequence will be deleted.

DROP TABLE tablename RESTRICT;

Deleting Tables with Serials

Page 9: Serial versus Serial What they don’t tell you about referential integrity and serials

According to the docs, 9.2 and older, you may delete the sequence and this will remove the default expression.

DROP SEQUENCE tablename_colname_seq;

ERROR: cannot drop sequence tablename_colname_seq because other objects depend on itDETAIL: default for table tablename column colname depends on sequence tablename_colname_seqHINT: Use DROP ... CASCADE to drop the dependent objects too.

Deleting Serials attached to Tables

Page 10: Serial versus Serial What they don’t tell you about referential integrity and serials

So now we will try dropping the sequence with a cascade command.

DROP SEQUENCE tablename_colname_seq CASCADE;

This works perfectly leaving the table and having removed the default and switching the serial to a integer.

Deleting Serials attached to Tables

Page 11: Serial versus Serial What they don’t tell you about referential integrity and serials

Everything seems to be great. You go along moving tables/views/etc to other schemas, so anything left over must me ok to drop before dropping the schema. There might even be some sequences that you can drop without any error messages. But the problem appears later when you try entering data into a table and receive this message.

INSERT INTO tablename VALUES (DEFAULT);ERROR: relation "tablename_colname_seq" does not exist

The Problem

Page 12: Serial versus Serial What they don’t tell you about referential integrity and serials

So while these two serials may look the same on the outside, they don’t act the same and so must be different on the inside.

Two different types of Serials?

Page 13: Serial versus Serial What they don’t tell you about referential integrity and serials

When looking closely at two tables, one that the sequence moved and one that the sequence did not move, I noticed that they were slightly different.

Working Style – Sequence moves:CREATE TABLE tablename(colname integer DEFAULT nextval('tablename_colname_seq'::regclass) NOT NULL );

Problem Style – Sequence does not move:CREATE TABLE tablename(colname integer DEFAULT nextval(('tablename_colname_seq'::text)::regclass) NOT NULL );

Finding the difference

Page 14: Serial versus Serial What they don’t tell you about referential integrity and serials

To fix the default value, you need to remove the text by issuing an alter table command.

ALTER TABLE tablename ALTER COLUMN colname SET DEFAULT nextval('tablename_colname_seq'::regclass);

Fixing the difference

Page 15: Serial versus Serial What they don’t tell you about referential integrity and serials

If you now move the tables to a different schema and then try to delete the sequence in the old schema you will get the error message about “cannot drop sequence”. This is good because we are now seeing some referential integrity. But they sequence did not move with the table.

If you delete the table the sequence will not be deleted. So there is currently only one way referential integrity.

What is fixed and what is not fixed

Page 16: Serial versus Serial What they don’t tell you about referential integrity and serials

With my GUI tools the tables/sequence now look the same, so I dumped both types of tables and found one more difference.

ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

Finding the next difference

Page 17: Serial versus Serial What they don’t tell you about referential integrity and serials

Now the table acts the way we expect it should. When we move the table, the sequence moves also. We are not allowed to delete the sequence without deleting the table. If we delete the table, the sequence is automatically deleted.

We now have bi-directional referential integrity.

Finally fixed

Page 18: Serial versus Serial What they don’t tell you about referential integrity and serials

When looking at the Postgres documentation about Sequence Functions, I found when everything changed. It happened between versions 8.0 and 8.1.

If you have any serials created in 8.0 or before and are now using 8.1 or newer, you do not have any referential integrity on those early serials but will have either one-way or bi-directional referential integrity on the newer serials.

Finding out how this happened

Page 19: Serial versus Serial What they don’t tell you about referential integrity and serials

If you have a 1-1 relationship, sequence to table, then you will want bi-directional referential integrity.

If you have a 1 to many relationship, one sequence to many tables, then you will want one way referential integrity. This one way relationship keeps you from dropping the sequence when other tables still rely on it. But you must move the sequence separately when moving the tables.

One Way versus Bi-Directional

Page 20: Serial versus Serial What they don’t tell you about referential integrity and serials

Note: Before PostgreSQL 8.1, the arguments of the sequence functions were of type text, not regclass, and the above-described conversion from a text string to an OID value would happen at run time during each call. For backwards compatibility, this facility still exists, but internally it is now handled as an implicit coercion from text to regclass before the function is invoked.

When you write the argument of a sequence function as an unadorned literal string, it becomes a constant of type regclass. Since this is really just an OID, it will track the originally identified sequence despite later renaming, schema reassignment, etc. This "early binding" behavior is usually desirable for sequence references in column defaults and views. But sometimes you will want "late binding" where the sequence reference is resolved at run time. To get late-binding behavior, force the constant to be stored as a text constant instead of regclass:

nextval('foo'::text) foo is looked up at runtime

Note that late binding was the only behavior supported in PostgreSQL releases before 8.1, so you may need to do this to preserve the semantics of old applications.

Of course, the argument of a sequence function can be an expression as well as a constant. If it is a text expression then the implicit coercion will result in a run-time lookup.

Sequence Manipulation Note

Page 21: Serial versus Serial What they don’t tell you about referential integrity and serials

What we need to do is look at all the default values and see if there are any ‘::text)::regclass)’.

SELECT adsrc FROM pg_catalog.pg_attrdefWHERE adnum = 1AND adsrc LIKE '%::text)::regclass)';

How to find out if your affected

adsrcnextval(('schemaname.tablename_colname_seq'::text)::regclass)

Page 22: Serial versus Serial What they don’t tell you about referential integrity and serials

The answer is yes, with conditions.1. If you don’t use the same sequence on more

than one table some of the time. It needs to be one way or the other. This is so that you can either do the OWNED BY or not.

2. If you use the default name formatting for the sequence name, this will allow you to easily figure out the table and field name, otherwise it is more complex but not impossible.

Is there any way to automate the fix

Page 23: Serial versus Serial What they don’t tell you about referential integrity and serials

ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;This provides referential integrity from the table to the sequence. If you move or drop the table, the sequence will either move or be dropped at the same time.

ALTER TABLE tablename ALTER COLUMN colname SET DEFAULT nextval('tablename_colname_seq'::regclass);This provides referential integrity from the sequence to the table. You may not delete the sequence if any table relies on it. But must be of type regclass and not a re-cast to type regclass.

In Closing – Recap