Обсуждение: Accessing composite type columns in indexes

Поиск
Список
Период
Сортировка

Accessing composite type columns in indexes

От
Michael Glaesemann
Дата:
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




Re: Accessing composite type columns in indexes

От
Tom Lane
Дата:
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

Re: Accessing composite type columns in indexes

От
Michael Fuhr
Дата:
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

Re: Accessing composite type columns in indexes

От
Michael Glaesemann
Дата:
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




Re: Accessing composite type columns in indexes

От
Michael Glaesemann
Дата:
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




Re: Accessing composite type columns in indexes

От
Tom Lane
Дата:
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

Re: Accessing composite type columns in indexes

От
Michael Glaesemann
Дата:
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