Thread: BUG #5548: ERROR: invalid attnum ## for rangetable entry on EXPLAIN VERBOSE, not on EXPLAIN

The following bug has been logged online:

Bug reference:      5548
Logged by:          Daniel Grace
Email address:      dgrace@wingsnw.com
PostgreSQL version: 9.0beta2
Operating system:   Windows XP 32-bit
Description:        ERROR: invalid attnum ## for rangetable entry  on
EXPLAIN VERBOSE, not on EXPLAIN
Details:

I apologize for not including detailed schema information.  It took a lot to
get this to reduce to the point it did, and hopefully this is enough
information to find a bug.  If not, email me back and I'll see how much
schema information I can provide.

When using EXPLAIN [ANALYZE] VERBOSE on the below query:

SELECT t.*
FROM (
    SELECT
        TRUE AS is_enrolled,

        acal.weight::REAL / (SELECT SUM(acal2.weight) FROM allocation_calendar AS
acal2 WHERE acal.year=acal2.year)::REAL AS calc_weight,
        (
            TRUNC(EXTRACT(EPOCH FROM LENGTH(
                PERIOD(
                    GREATEST(FIRST(acal.daterange), acd.tstime),
                    LEAST(NEXT(acal.daterange), FIRST_VALUE(acd.tstime) OVER nextdate)
                )
            ))) / TRUNC(EXTRACT(EPOCH FROM LENGTH(acal.daterange)))
        ) AS calc_duration,

        NULL::integer AS group_id
    FROM
        allocation_calculated_dates AS acd
        INNER JOIN allocation_calendar AS acal ON acd.acalid=acal.id
        INNER JOIN log_status AS ls ON ls.sid=acd.sid AND ls.tsrange ~ acd.tstime
    WINDOW
        nextdate AS ( PARTITION BY acd.sid, acd.acalid ORDER BY acd.tstime ASC
ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING )
) AS t
CROSS JOIN yearinfo AS yi  -- ON t.year=yi.year
LEFT JOIN group_info AS gi ON gi.id=t.group_id
WHERE t.is_enrolled /* AND yi.allocation_lock=0 */

I receive the following result:

ERROR: invalid attnum 5 for rangetable entry t

This appears to be originating from get_rte_attribute_name() in
parse_relation.c (which might need to consider RTE_SUBQUERY?)

Stripping the final WHERE clause out (WHERE t.is_enrolled) causes the error
to go away, as do most modifications to joined tables.

When ran as a regular SELECT, the query runs fine and produces correct
outputs.

A regular EXPLAIN yields:
"Nested Loop  (cost=1136.45..1146.96 rows=16 width=17)"
"  ->  Subquery Scan on t  (cost=1136.45..1145.71 rows=4 width=17)"
"        Filter: t.is_enrolled"
"        ->  WindowAgg  (cost=1136.45..1145.63 rows=8 width=38)"
"              ->  Sort  (cost=1136.45..1136.47 rows=8 width=38)"
"                    Sort Key: s.id, wings_demo.allocation_calendar.id,
(GREATEST(first(ls.tsrange), first(CASE WHEN
(wings_demo.allocation_calendar.countdate IS NULL) THEN
wings_demo.allocation_calendar.daterange ELSE
period_cc((wings_demo.allocation_calendar.countdate)::timestamp with time
zone, (wings_demo.allocation_calendar.countdate)::timestamp with time zone)
END)))"
"                    ->  Hash Join  (cost=1055.63..1136.33 rows=8
width=38)"
"                          Hash Cond: (ls.sid = s.id)"
"                          Join Filter: (ls.tsrange ~
(GREATEST(first(ls.tsrange), first(CASE WHEN
(wings_demo.allocation_calendar.countdate IS NULL) THEN
wings_demo.allocation_calendar.daterange ELSE
period_cc((wings_demo.allocation_calendar.countdate)::timestamp with time
zone, (wings_demo.allocation_calendar.countdate)::timestamp with time zone)
END))))"
"                          ->  Seq Scan on log_status ls  (cost=0.00..76.26
rows=1126 width=20)"
"                          ->  Hash  (cost=1055.56..1055.56 rows=6
width=38)"
"                                ->  Hash Join  (cost=1055.07..1055.56
rows=6 width=38)"
"                                      Hash Cond:
(wings_demo.allocation_calendar.id = acal.id)"
"                                      ->  HashAggregate
(cost=1053.93..1054.11 rows=18 width=46)"
"                                            ->  Append
(cost=561.01..1053.75 rows=18 width=46)"
"                                                  ->  Merge Left Join
(cost=561.01..596.61 rows=17 width=46)"
"                                                        Merge Cond: ((s.id
= ao.sid) AND (wings_demo.allocation_calendar.year = ao.year))"
"                                                        Filter: (ao.amount
IS NULL)"
"                                                        ->  Sort
(cost=472.83..481.28 rows=3378 width=46)"
"                                                              Sort Key:
s.id, wings_demo.allocation_calendar.year"
"                                                              ->  Nested
Loop  (cost=30.02..274.85 rows=3378 width=46)"
"                                                                    Join
Filter: (CASE WHEN (wings_demo.allocation_calendar.countdate IS NULL) THEN
wings_demo.allocation_calendar.daterange ELSE
period_cc((wings_demo.allocation_calendar.countdate)::timestamp with time
zone, (wings_demo.allocation_calendar.countdate)::timestamp with time zone)
END && ls.tsrange)"
"                                                                    ->
Hash Join  (cost=30.02..121.77 rows=1126 width=20)"
"
Hash Cond: (ls.sid = s.id)"
"
->  Seq Scan on log_status ls  (cost=0.00..76.26 rows=1126 width=20)"
"
->  Hash  (cost=25.01..25.01 rows=401 width=4)"
"
    ->  Seq Scan on student s  (cost=0.00..25.01 rows=401 width=4)"
"                                                                    ->
Materialize  (cost=0.00..1.09 rows=6 width=26)"
"
->  Seq Scan on allocation_calendar  (cost=0.00..1.06 rows=6 width=26)"
"                                                        ->  Sort
(cost=88.17..91.35 rows=1270 width=19)"
"                                                              Sort Key:
ao.sid, ao.year"
"                                                              ->  Seq Scan
on allocation_override ao  (cost=0.00..22.70 rows=1270 width=19)"
"                                                  ->  Hash Left Join
(cost=350.15..456.97 rows=1 width=54)"
"                                                        Hash Cond: (lg.sid
= lgprior.sid)"
"                                                        Join Filter:
((lgprior.id <> lg.id) AND (COALESCE(lgprior.allocation_priority,
giprior.allocation_priority) > COALESCE(lg.allocation_priority,
gi.allocation_priority)) AND (lgprior.tsrange ~ first(lg.tsrange)))"
"                                                        Filter: (((ao.sid
IS NULL) AND (lgprior.id IS NULL)) OR ((lgnext.id IS NULL) AND (NOT
lg.ignore_allocation_method) AND (gi.allocation_method_id IS NOT NULL)))"
"                                                        ->  Hash Left Join
(cost=313.79..382.24 rows=963 width=75)"
"                                                              Hash Cond:
(lg.sid = lgnext.sid)"
"                                                              Join Filter:
((lgnext.id <> lg.id) AND (COALESCE(lgnext.allocation_priority,
ginext.allocation_priority) > COALESCE(lg.allocation_priority,
gi.allocation_priority)) AND (lgnext.tsrange ~ last(lg.tsrange)))"
"                                                              ->  Hash Join
 (cost=277.42..307.56 rows=963 width=71)"
"                                                                    Hash
Cond: (lg.gid = gi.id)"
"                                                                    ->
Merge Left Join  (cost=276.33..293.23 rows=963 width=67)"
"
Merge Cond: ((s.id = ao.sid) AND (wings_demo.allocation_calendar.year =
ao.year))"
"
->  Sort  (cost=188.16..190.57 rows=963 width=63)"
"
    Sort Key: lg.sid, wings_demo.allocation_calendar.year"
"
    ->  Hash Join  (cost=35.64..140.44 rows=963 width=63)"
"
          Hash Cond: (lg.sid = s.id)"
"
          ->  Nested Loop  (cost=5.61..97.17 rows=963 width=59)"
"
                Join Filter: (NOT (lg.tsrange @> CASE WHEN
(wings_demo.allocation_calendar.countdate IS NULL) THEN
wings_demo.allocation_calendar.daterange ELSE
period_cc((wings_demo.allocation_calendar.countdate)::timestamp with time
zone, (wings_demo.allocation_calendar.countdate)::timestamp with time zone)
END))"
"
                ->  Seq Scan on allocation_calendar  (cost=0.00..1.06 rows=6
width=26)"
"
                ->  Bitmap Heap Scan on log_group lg  (cost=5.61..15.93
rows=3 width=33)"
"
                      Recheck Cond: (CASE WHEN
(wings_demo.allocation_calendar.countdate IS NULL) THEN
wings_demo.allocation_calendar.daterange ELSE
period_cc((wings_demo.allocation_calendar.countdate)::timestamp with time
zone, (wings_demo.allocation_calendar.countdate)::timestamp with time zone)
END && lg.tsrange)"
"
                      ->  Bitmap Index Scan on log_group_gix_tsrange
(cost=0.00..5.61 rows=3 width=0)"
"
                            Index Cond: (CASE WHEN
(wings_demo.allocation_calendar.countdate IS NULL) THEN
wings_demo.allocation_calendar.daterange ELSE
period_cc((wings_demo.allocation_calendar.countdate)::timestamp with time
zone, (wings_demo.allocation_calendar.countdate)::timestamp with time zone)
END && lg.tsrange)"
"
          ->  Hash  (cost=25.01..25.01 rows=401 width=4)"
"
                ->  Seq Scan on student s  (cost=0.00..25.01 rows=401
width=4)"
"
->  Sort  (cost=88.17..91.35 rows=1270 width=8)"
"
    Sort Key: ao.sid, ao.year"
"
    ->  Seq Scan on allocation_override ao  (cost=0.00..22.70 rows=1270
width=8)"
"                                                                    ->
Hash  (cost=1.04..1.04 rows=4 width=12)"
"
->  Seq Scan on group_info gi  (cost=0.00..1.04 rows=4 width=12)"
"                                                              ->  Hash
(cost=28.34..28.34 rows=642 width=32)"
"                                                                    ->
Hash Join  (cost=1.09..28.34 rows=642 width=32)"
"
Hash Cond: (lgnext.gid = ginext.id)"
"
->  Seq Scan on log_group lgnext  (cost=0.00..18.42 rows=642 width=32)"
"
    Filter: (NOT ignore_allocation_method)"
"
->  Hash  (cost=1.04..1.04 rows=4 width=8)"
"
    ->  Seq Scan on group_info ginext  (cost=0.00..1.04 rows=4 width=8)"
"
          Filter: (allocation_method_id IS NOT NULL)"
"                                                        ->  Hash
(cost=28.34..28.34 rows=642 width=32)"
"                                                              ->  Hash Join
 (cost=1.09..28.34 rows=642 width=32)"
"                                                                    Hash
Cond: (lgprior.gid = giprior.id)"
"                                                                    ->  Seq
Scan on log_group lgprior  (cost=0.00..18.42 rows=642 width=32)"
"
Filter: (NOT ignore_allocation_method)"
"                                                                    ->
Hash  (cost=1.04..1.04 rows=4 width=8)"
"
->  Seq Scan on group_info giprior  (cost=0.00..1.04 rows=4 width=8)"
"
    Filter: (allocation_method_id IS NOT NULL)"
"                                      ->  Hash  (cost=1.06..1.06 rows=6
width=26)"
"                                            ->  Seq Scan on
allocation_calendar acal  (cost=0.00..1.06 rows=6 width=26)"
"              SubPlan 1"
"                ->  Aggregate  (cost=1.08..1.09 rows=1 width=4)"
"                      ->  Seq Scan on allocation_calendar acal2
(cost=0.00..1.08 rows=2 width=4)"
"                            Filter: ($0 = year)"
"  ->  Materialize  (cost=0.00..1.06 rows=4 width=0)"
"        ->  Seq Scan on yearinfo yi  (cost=0.00..1.04 rows=4 width=0)"
"Daniel Grace" <dgrace@wingsnw.com> writes:
> I apologize for not including detailed schema information.  It took a lot to
> get this to reduce to the point it did, and hopefully this is enough
> information to find a bug.

It is not.  You haven't provided anywhere near enough information
for someone else to reproduce the failure.  We're not going to
guess at the tables or views that underlie your query ...

            regards, tom lane
On Thu, Jul 8, 2010 at 10:52 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> "Daniel Grace" <dgrace@wingsnw.com> writes:
>> I apologize for not including detailed schema information. =A0It took a =
lot to
>> get this to reduce to the point it did, and hopefully this is enough
>> information to find a bug.
>
> It is not. =A0You haven't provided anywhere near enough information
> for someone else to reproduce the failure. =A0We're not going to
> guess at the tables or views that underlie your query ...
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0regards, tom lane
>

So I've spent the greater portion of the last two hours trying to slim
down the schema and query enough to provide something that can
reproduce this.

While I can reproduce it 100% of the time with live data, I can't get
it to reproduce at all with test data -- though I've included a few
schemas below.  It seems to be based on what plan ends up being
constructed for the query.

This doesn't really affect me at this point -- but my concern is that
it might cause actual problems when paired with the auto_explain
contrib module.

Basic stripped-down schema:
DROP SCHEMA IF EXISTS test CASCADE;
CREATE SCHEMA test;
SET SEARCH_PATH=3Dtest,public;

CREATE TABLE allocation_calendar
(
  id serial NOT NULL,
  "year" smallint NOT NULL,
  "name" character varying(64) NOT NULL,
  countdate date,
  availabledate date NOT NULL,
  weight integer NOT NULL,
  daterange integer NOT NULL,    -- Was a PERIOD, but not required to reproduce
  CONSTRAINT allocation_calendar_pkey PRIMARY KEY (id),
  CONSTRAINT allocation_calendar_ux_year UNIQUE (year, name)
);
CREATE INDEX allocation_calendar_ix_year_3 ON allocation_calendar
(year, countdate);
CREATE INDEX allocation_calendar_ix_year_4 ON allocation_calendar
(year, availabledate);

CREATE TABLE yearinfo (
  id serial NOT NULL,
  year smallint NOT NULL,
  CONSTRAINT yearinfo_ux_year UNIQUE (year)
);

INSERT INTO yearinfo (year) SELECT * FROM GENERATE_SERIES(1000, 2000);
INSERT INTO allocation_calendar (year, name, countdate, availabledate,
weight, daterange) SELECT f.v, 'Year ' || f.v, NULL, '-infinity', 1, 2
FROM GENERATE_SERIES(1000, 5000) AS f(v);

ANALYZE allocation_calendar;
REINDEX TABLE yearinfo;
REINDEX TABLE allocation_calendar;

CREATE OR REPLACE VIEW allocation_calculated_dates AS
SELECT acal.id AS acalid, acal.year AS year, null::integer AS tstime
FROM
    allocation_calendar AS acal
;

EXPLAIN ANALYZE SELECT t.*
FROM (
    SELECT
        FIRST_VALUE(acd.tstime) OVER nextdate AS foo
    FROM
        allocation_calculated_dates AS acd
        INNER JOIN allocation_calendar AS acal ON acd.acalid=3Dacal.id
    WINDOW
        nextdate AS ( PARTITION BY acd.acalid ORDER BY acd.tstime ASC ROWS
BETWEEN 1 FOLLOWING AND 1 FOLLOWING )
) AS t
CROSS JOIN yearinfo AS yi  -- ON t.year=3Dyi.year
WHERE t.foo IS NULL



Plan that fails on EXPLAIN VERBOSE:
"Nested Loop  (cost=3D0.00..132.35 rows=3D24 width=3D4)"
"  ->  Subquery Scan on t  (cost=3D0.00..131.00 rows=3D6 width=3D4)"
"        Filter: (t.foo IS NULL)"
"        ->  WindowAgg  (cost=3D0.00..119.50 rows=3D1150 width=3D4)"
"              ->  Merge Join  (cost=3D0.00..102.25 rows=3D1150 width=3D4)"
"                    Merge Cond: (acal.id =3D acal.id)"
"                    ->  Index Scan using allocation_calendar_pkey on
allocation_calendar acal  (cost=3D0.00..42.50 rows=3D1150 width=3D4)"
"                    ->  Index Scan using allocation_calendar_pkey on
allocation_calendar acal  (cost=3D0.00..42.50 rows=3D1150 width=3D4)"
"  ->  Materialize  (cost=3D0.00..1.06 rows=3D4 width=3D0)"
"        ->  Seq Scan on yearinfo yi  (cost=3D0.00..1.04 rows=3D4 width=3D0=
)"
--> ERROR:  invalid attnum 2 for rangetable entry t
Note: The attnum in question always seems to be 1 more than the number
of columns in t.


Plan that succeeds on EXPLAIN VERBOSE:
"Nested Loop  (cost=3D0.00..827.88 rows=3D20020 width=3D4) (actual
time=3D0.036..2566.818 rows=3D4005001 loops=3D1)"
"  ->  Seq Scan on yearinfo yi  (cost=3D0.00..15.01 rows=3D1001 width=3D0)
(actual time=3D0.007..0.429 rows=3D1001 loops=3D1)"
"  ->  Materialize  (cost=3D0.00..562.67 rows=3D20 width=3D4) (actual
time=3D0.000..0.850 rows=3D4001 loops=3D1001)"
"        ->  Subquery Scan on t  (cost=3D0.00..562.57 rows=3D20 width=3D4)
(actual time=3D0.026..14.731 rows=3D4001 loops=3D1)"
"              Filter: (t.foo IS NULL)"
"              ->  WindowAgg  (cost=3D0.00..522.56 rows=3D4001 width=3D4)
(actual time=3D0.025..12.637 rows=3D4001 loops=3D1)"
"                    ->  Merge Join  (cost=3D0.00..462.55 rows=3D4001
width=3D4) (actual time=3D0.016..7.715 rows=3D4001 loops=3D1)"
"                          Merge Cond: (acal.id =3D acal.id)"
"                          ->  Index Scan using
allocation_calendar_pkey on allocation_calendar acal
(cost=3D0.00..201.27 rows=3D4001 width=3D4) (actual time=3D0.007..1.481
rows=3D4001 loops=3D1)"
"                          ->  Index Scan using
allocation_calendar_pkey on allocation_calendar acal
(cost=3D0.00..201.27 rows=3D4001 width=3D4) (actual time=3D0.006..2.035
rows=3D4001 loops=3D1)"
"Total runtime: 3288.843 ms"

Hope this helps at least somewhat.  I know it's not as clear cut as
I'd like.  (Normally I'd like to send a 100% working reproduce case,
but I just can't seem to get one here)

--=20
Daniel Grace
Daniel Grace <dgrace@wingsnw.com> writes:
> So I've spent the greater portion of the last two hours trying to slim
> down the schema and query enough to provide something that can
> reproduce this.

> While I can reproduce it 100% of the time with live data, I can't get
> it to reproduce at all with test data -- though I've included a few
> schemas below.  It seems to be based on what plan ends up being
> constructed for the query.

Maybe you could force it for the test data with some suitable
combination of the enable_plantype switches.

            regards, tom lane
Daniel Grace <dgrace@wingsnw.com> writes:
> Plan that fails on EXPLAIN VERBOSE:
> "Nested Loop  (cost=0.00..132.35 rows=24 width=4)"
> "  ->  Subquery Scan on t  (cost=0.00..131.00 rows=6 width=4)"
> "        Filter: (t.foo IS NULL)"
> "        ->  WindowAgg  (cost=0.00..119.50 rows=1150 width=4)"
> "              ->  Merge Join  (cost=0.00..102.25 rows=1150 width=4)"
> "                    Merge Cond: (acal.id = acal.id)"
> "                    ->  Index Scan using allocation_calendar_pkey on
> allocation_calendar acal  (cost=0.00..42.50 rows=1150 width=4)"
> "                    ->  Index Scan using allocation_calendar_pkey on
> allocation_calendar acal  (cost=0.00..42.50 rows=1150 width=4)"
> "  ->  Materialize  (cost=0.00..1.06 rows=4 width=0)"
> "        ->  Seq Scan on yearinfo yi  (cost=0.00..1.04 rows=4 width=0)"
> --> ERROR:  invalid attnum 2 for rangetable entry t

I've applied a patch for this; it'll be in 9.0beta4.  Thanks for the
report!

            regards, tom lane