pseudo-referential integrity with ENUMs and ARRAYs

janus on 2009-02-28T17:56:22

After all the whining from users of the most popular open source database over the years, here's some cheering about the most advanced open source database: pseudo-referential integrity with ENUMs and ARRAYs

Have you ever been in the situation where you needed an array or didn't want to introduce an extra mapping table for just a few well-defined values without introducing inconcistencies?

Since PostgreSQL got ENUM support it's pretty easy to solve:

test=# CREATE TYPE foo AS ENUM ('a', 'b', 'c'); CREATE TYPE test=# CREATE TABLE bar ( test(# id INTEGER PRIMARY KEY, test(# foo foo[] NOT NULL DEFAULT '{a}' test(# ); NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "bar_pkey" for table "bar" CREATE TABLE test=#

Now try to insert unkown values:

test=# INSERT INTO bar (id, foo) VALUES (1, '{x}'); ERROR: invalid input value for enum foo: "x" test=#

Works as expected (the common feeling when i'm working with this database btw).

It surely accepts valid values:

test=# INSERT INTO bar (id, foo) VALUES (1, '{b}'); INSERT 0 1 test=# INSERT INTO bar (id, foo) VALUES (2, '{b,c,a}'); INSERT 0 1 test=# INSERT INTO bar (id, foo) VALUES (3, '{a,b,c,a,a}'); INSERT 0 1 test=#

Let's try the default value:

test=# INSERT INTO bar (id) VALUES (4); INSERT 0 1 test=#

And look at the table contents:

test=# SELECT * FROM bar; id | foo ----+------------- 1 | {b} 2 | {b,c,a} 3 | {a,b,c,a,a} 4 | {a} (4 rows)

test=#

And of course we can only UPDATE to defined ENUM values:

test=# UPDATE bar SET foo = '{x}' WHERE id = 4; ERROR: invalid input value for enum foo: "x" test=# UPDATE bar SET foo = '{b}' WHERE id = 4; UPDATE 1 test=#

So much about whining... NOT! ;-)

EDIT/P.S.: lbr pointed that extending the ENUM wouldn't be that easy. First, i don't think you should use this approach if you're expecting the ENUM values to change. Second, it can be done like this:

test=# CREATE TYPE foo2 AS ENUM ('a', 'b', 'c', 'd'); CREATE TYPE test=# ALTER TABLE bar ALTER COLUMN foo DROP DEFAULT, test-# ALTER COLUMN foo TYPE foo2[] USING string_to_array(array_to_string(foo, ','), ',')::foo2[], test-# ALTER COLUMN foo SET DEFAULT '{a}'; ALTER TABLE test=#

Thanks to lbr for pointing it out and making me happy again by proving that PostgreSQL works and works and works.... and works :-)


Postgres++

autarch on 2009-02-28T21:37:15

++++++++

Pg is a really nice tool.