Accessing composite type columns in indexes

Started by Michael Glaesemannabout 20 years ago7 messagesgeneral
Jump to latest
#1Michael Glaesemann
grzm@seespotcode.net

Michael Fuhr's example of using composite types for date intervals/
ranges/periods prompted me to explore this a little further. While
doing so, it appears that one can't directly access the columns of a
composite type when creating an index, i.e., neither UNIQUE (foo.bar)
nor UNIQUE ((foo).bar) work. I was able to create indexes including
composite columns by creating functions that returned values from a
composite type parameter.

Is this expected?

Here are the details:

begin;
BEGIN
-- closed-open date interval [from_date, to_date)
create type date_co_interval as
(
from_date date
, to_date date
);
CREATE TYPE

create function co_begin(date_co_interval) returns date
strict
immutable
security definer
language plpgsql as '
declare
i alias for $1;
begin
return i.from_date;
end;
';
CREATE FUNCTION

-- convenience function
create function prior(date) returns date
strict
immutable
security definer
language plpgsql as '
declare
p alias for $1;
begin
return p - 1;
end;
';
CREATE FUNCTION

create function co_end(date_co_interval) returns date
strict
immutable
security definer
language plpgsql as '
declare
i alias for $1;
begin
return prior(i.to_date);
end;
';
CREATE FUNCTION

savepoint composite_dot;
SAVEPOINT

create table employment_history
(
company text not null
, during date_co_interval not null
, unique (company, during.from_date, during.to_date)
);
ERROR: syntax error at or near "." at character 129
LINE 5: , unique (company, during.from_date, during.to_date)
^
rollback to savepoint composite_dot;
ROLLBACK

savepoint composite_parens;
SAVEPOINT

create table employment_history
(
company text not null
, during date_co_interval
, unique (company, (during).from_date, (during).to_date)
);
ERROR: syntax error at or near "(" at character 114
LINE 5: , unique (company, (during).from_date, (during).to_date)
^
rollback to savepoint composite_parens;
ROLLBACK

savepoint function_on_composite;
SAVEPOINT

create table employment_history
(
company text not null
, during date_co_interval not null
, unique (company, co_begin(during), co_end(during))
);
ERROR: syntax error at or near "(" at character 131
LINE 5: , unique (company, co_begin(during), co_end(during))
^
rollback to savepoint function_on_composite;
ROLLBACK

savepoint parens_function_on_composite;
SAVEPOINT

create table employment_history
(
company text not null
, during date_co_interval not null
, unique (company, (co_begin(during)), (co_end(during)))
);
ERROR: syntax error at or near "(" at character 123
LINE 5: , unique (company, (co_begin(during)), (co_end(during)))
^
rollback to savepoint parens_function_on_composite;
ROLLBACK

create table employment_history
(
company text not null
, during date_co_interval not null
);
CREATE TABLE

savepoint composite_idx;
SAVEPOINT

create unique index employment_history_pkey_idx
on employment_history (company, during.from_date, during.to_date);
ERROR: syntax error at or near "," at character 98
LINE 2: on employment_history (company, during.from_date, during.to_...
^
rollback to savepoint composite_idx;
ROLLBACK

savepoint composite_parens_idx;
SAVEPOINT

create unique index employment_history_pkey_idx
on employment_history (company, (during).from_date, (during).to_date);
ERROR: syntax error at or near "." at character 89
LINE 2: on employment_history (company, (during).from_date, (during)...
^
rollback to savepoint composite_parens_idx;
ROLLBACK

create unique index employment_history_pkey_idx
on employment_history (company, co_begin(during), co_end(during));
CREATE INDEX

rollback;
ROLLBACK
select version();

version
------------------------------------------------------------------------
----------------------------------------------------------------------
PostgreSQL 8.1.3 on powerpc-apple-darwin8.4.0, compiled by GCC
powerpc-apple-darwin8-gcc-4.0.1 (GCC) 4.0.1 (Apple Computer, Inc.
build 5247)
(1 row)

Michael Glaesemann
grzm myrealbox com

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Glaesemann (#1)
Re: Accessing composite type columns in indexes

Michael Glaesemann <grzm@myrealbox.com> writes:

... it appears that one can't directly access the columns of a
composite type when creating an index, i.e., neither UNIQUE (foo.bar)
nor UNIQUE ((foo).bar) work.

You need both, ie something like

create table foo (bar date_co_interval);
create unique index fooi on foo (((bar).from_date));

The outer set of parens is required for any index expression. Basically
that's to fix a grammar conflict against the possible presence of an
index opclass, that is given

create index fooi on foo (x ! y)

is that an infix operator expression "x ! y", or a postfix operator
expression "x !" followed by an opclass name?

The inner set of parens is because "a.b" is always interpreted as a
table and column name. To refer to a column, and then qualify it with
a composite-type field, we require you to write "(b).c" or "(a.b).c".
It'd be legal to write the same index as
create unique index fooi on foo (((foo.bar).from_date));

Make sense now?

regards, tom lane

#3Michael Fuhr
mike@fuhr.org
In reply to: Michael Glaesemann (#1)
Re: Accessing composite type columns in indexes

On Sat, Mar 04, 2006 at 12:21:38PM +0900, Michael Glaesemann wrote:

create unique index employment_history_pkey_idx
on employment_history (company, (during).from_date, (during).to_date);
ERROR: syntax error at or near "." at character 89
LINE 2: on employment_history (company, (during).from_date, (during)...
^

This works:

create unique index employment_history_pkey_idx
on employment_history (company, ((during).from_date), ((during).to_date));

--
Michael Fuhr

#4Michael Glaesemann
grzm@seespotcode.net
In reply to: Michael Fuhr (#3)
Re: Accessing composite type columns in indexes

On Mar 4, 2006, at 13:34 , Michael Fuhr wrote:

On Sat, Mar 04, 2006 at 12:21:38PM +0900, Michael Glaesemann wrote:

create unique index employment_history_pkey_idx
on employment_history (company, (during).from_date,
(during).to_date);
ERROR: syntax error at or near "." at character 89
LINE 2: on employment_history (company, (during).from_date,
(during)...
^

This works:

create unique index employment_history_pkey_idx
on employment_history (company, ((during).from_date),
((during).to_date));

Thanks, Tom and Michael. I thought I had been aggressive enough in
applying parentheses.

On Mar 4, 2006, at 13:31 , Tom Lane wrote:

Make sense now?

Yep!

Michael Glaesemann
grzm myrealbox com

#5Michael Glaesemann
grzm@seespotcode.net
In reply to: Michael Glaesemann (#4)
Re: Accessing composite type columns in indexes

On Mar 4, 2006, at 13:44 , Michael Glaesemann wrote:

On Mar 4, 2006, at 13:31 , Tom Lane wrote:

Make sense now?

Yep!

Except, why doesn't it work in the CREATE TABLE statement? One needs
to add the UNIQUE index as a separate command. For example,

-- doesn't work
create table foo
(
foo date_co_interval
, unique (((foo).from_date), ((foo).to_date))
);

-- fails (as expected)
create table foo
(
foo date_co_interval
, unique (((foo.foo).from_date), ((foo.foo).to_date))
);

-- works
create table foo (foo date_co_interval);
create unique index foo_idx on foo (((foo).from_date), ((foo).to_date));

Is this also excluded because of some parser ambiguity?

Michael Glaesemann
grzm myrealbox com

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Glaesemann (#5)
Re: Accessing composite type columns in indexes

Michael Glaesemann <grzm@myrealbox.com> writes:

Except, why doesn't it work in the CREATE TABLE statement?

The UNIQUE/PRIMARY KEY syntax only allows bare column names, per the SQL
standard. While there's not any technical reason why we couldn't extend
that syntax, there's a pretty large fear factor involved: we could find
ourselves behind the spec-compliance eight-ball if the SQL committee
exercises their prerogative to extend the syntax in some other
direction. CREATE INDEX is entirely outside the spec (as the whole
concept of indexes is outside the spec) and so we can pretty much do
what we please within that statement.

This is exactly the same reason why we don't support opclass names in
UNIQUE/PRIMARY KEY, as has been suggested several times recently, eg
http://archives.postgresql.org/pgsql-hackers/2006-03/msg00163.php

regards, tom lane

#7Michael Glaesemann
grzm@seespotcode.net
In reply to: Tom Lane (#6)
Re: Accessing composite type columns in indexes

On Mar 4, 2006, at 14:17 , Tom Lane wrote:

The UNIQUE/PRIMARY KEY syntax only allows bare column names, per
the SQL
standard. While there's not any technical reason why we couldn't
extend
that syntax, there's a pretty large fear factor involved: we could
find
ourselves behind the spec-compliance eight-ball if the SQL committee
exercises their prerogative to extend the syntax in some other
direction.

Cool. Thanks for the explanation.

Michael Glaesemann
grzm myrealbox com