Skip to content

Commit

Permalink
Properly set function column count for table value functions in Orca
Browse files Browse the repository at this point in the history
The funccolcount value wasn't being set by Orca when populating the plan
to execute, which caused running explain <qry> for such queries to fail
with "invalid attnum 2 for relation".  Interestingly, the queries I
tested would execute fine--only explain would fail.
  • Loading branch information
chrishajas committed Feb 16, 2024
1 parent acdb2c1 commit 456f6cf
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1683,6 +1683,7 @@ CTranslatorDXLToPlStmt::TranslateDXLTvf(
rtfunc->funccoltypes = NIL;
rtfunc->funccoltypmods = NIL;
rtfunc->funccolcollations = NIL;
rtfunc->funccolcount = gpdb::ListLength(target_list);
ForEach(lc_target_entry, target_list)
{
TargetEntry *target_entry = (TargetEntry *) lfirst(lc_target_entry);
Expand Down Expand Up @@ -1785,7 +1786,6 @@ CTranslatorDXLToPlStmt::TranslateDXLTvfToRangeTblEntry(
const_expr->constvalue = gpdb::DatumFromPointer(str);

rtfunc->funcexpr = (Node *) const_expr;
rtfunc->funccolcount = (int) num_of_cols;
}
else
{
Expand Down Expand Up @@ -1832,6 +1832,7 @@ CTranslatorDXLToPlStmt::TranslateDXLTvfToRangeTblEntry(
rtfunc->funcexpr = (Node *) func_expr;
}

rtfunc->funccolcount = (int) num_of_cols;
rtfunc->funcparams = funcparams;
// GPDB_91_MERGE_FIXME: collation
// set rtfunc->funccoltypemods & rtfunc->funccolcollations?
Expand Down
40 changes: 40 additions & 0 deletions src/test/regress/expected/gporca.out
Original file line number Diff line number Diff line change
Expand Up @@ -14921,5 +14921,45 @@ set session authorization ruser;
set gp_max_system_slices=10;
ERROR: permission denied to set parameter "gp_max_system_slices"
reset session authorization;
-- Test that set returning function with multiple columns works with explain
CREATE FUNCTION srf_attnum() RETURNS TABLE(v1 int, v2 int)
LANGUAGE plpgsql NO SQL
AS $_$
BEGIN
DROP TABLE IF EXISTS tbl_2_cols;
CREATE TEMP TABLE tbl_2_cols (col1 int, col2 int) DISTRIBUTED RANDOMLY;
RETURN QUERY SELECT * from tbl_2_cols;
END;
$_$;
NOTICE: specifying "NO SQL" acts as no operation.
explain select distinct v1 from srf_attnum();
QUERY PLAN
-------------------------------------------------------------------------
HashAggregate (cost=12.75..22.75 rows=1000 width=4)
Group Key: v1
-> Function Scan on srf_attnum (cost=0.25..10.25 rows=1000 width=4)
Optimizer: Postgres-based planner
(4 rows)

select distinct v1 from srf_attnum();
NOTICE: table "tbl_2_cols" does not exist, skipping
v1
----
(0 rows)

explain select distinct v2 from srf_attnum();
QUERY PLAN
-------------------------------------------------------------------------
HashAggregate (cost=12.75..22.75 rows=1000 width=4)
Group Key: v2
-> Function Scan on srf_attnum (cost=0.25..10.25 rows=1000 width=4)
Optimizer: Postgres-based planner
(4 rows)

select distinct v2 from srf_attnum();
v2
----
(0 rows)

drop user ruser;
drop table foo, bar;
40 changes: 40 additions & 0 deletions src/test/regress/expected/gporca_optimizer.out
Original file line number Diff line number Diff line change
Expand Up @@ -15016,5 +15016,45 @@ set session authorization ruser;
set gp_max_system_slices=10;
ERROR: permission denied to set parameter "gp_max_system_slices"
reset session authorization;
-- Test that set returning function with multiple columns works with explain
CREATE FUNCTION srf_attnum() RETURNS TABLE(v1 int, v2 int)
LANGUAGE plpgsql NO SQL
AS $_$
BEGIN
DROP TABLE IF EXISTS tbl_2_cols;
CREATE TEMP TABLE tbl_2_cols (col1 int, col2 int) DISTRIBUTED RANDOMLY;
RETURN QUERY SELECT * from tbl_2_cols;
END;
$_$;
NOTICE: specifying "NO SQL" acts as no operation.
explain select distinct v1 from srf_attnum();
QUERY PLAN
------------------------------------------------------------------------
HashAggregate (cost=0.00..0.13 rows=1000 width=4)
Group Key: v1
-> Function Scan on srf_attnum (cost=0.00..0.00 rows=1000 width=4)
Optimizer: GPORCA
(4 rows)

select distinct v1 from srf_attnum();
NOTICE: table "tbl_2_cols" does not exist, skipping
v1
----
(0 rows)

explain select distinct v2 from srf_attnum();
QUERY PLAN
------------------------------------------------------------------------
HashAggregate (cost=0.00..0.13 rows=1000 width=4)
Group Key: v2
-> Function Scan on srf_attnum (cost=0.00..0.00 rows=1000 width=4)
Optimizer: GPORCA
(4 rows)

select distinct v2 from srf_attnum();
v2
----
(0 rows)

drop user ruser;
drop table foo, bar;
15 changes: 15 additions & 0 deletions src/test/regress/sql/gporca.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3688,6 +3688,21 @@ set session authorization ruser;
set gp_max_system_slices=10;
reset session authorization;

-- Test that set returning function with multiple columns works with explain
CREATE FUNCTION srf_attnum() RETURNS TABLE(v1 int, v2 int)
LANGUAGE plpgsql NO SQL
AS $_$
BEGIN
DROP TABLE IF EXISTS tbl_2_cols;
CREATE TEMP TABLE tbl_2_cols (col1 int, col2 int) DISTRIBUTED RANDOMLY;
RETURN QUERY SELECT * from tbl_2_cols;
END;
$_$;
explain select distinct v1 from srf_attnum();
select distinct v1 from srf_attnum();
explain select distinct v2 from srf_attnum();
select distinct v2 from srf_attnum();

drop user ruser;
drop table foo, bar;

Expand Down

0 comments on commit 456f6cf

Please sign in to comment.