Teach PL/pgSQL about partitioned tables.
authorDean Rasheed <[email protected]>
Wed, 14 Jun 2017 08:00:01 +0000 (09:00 +0100)
committerDean Rasheed <[email protected]>
Wed, 14 Jun 2017 08:00:01 +0000 (09:00 +0100)
Table partitioning, introduced in commit f0e44751d7, added a new
relkind - RELKIND_PARTITIONED_TABLE. Update a couple of places in
PL/pgSQL to handle it. Specifically plpgsql_parse_cwordtype() and
build_row_from_class() needed updating in order to make table%ROWTYPE
and table.col%TYPE work for partitioned tables.

Dean Rasheed, reviewed by Amit Langote.

Discussion: https://postgr.es/m/CAEZATCUnNOKN8sLML9jUzxecALWpEXK3a3W7y0PgFR4%2Buhgc%3Dg%40mail.gmail.com

src/pl/plpgsql/src/pl_comp.c
src/test/regress/expected/plpgsql.out
src/test/regress/sql/plpgsql.sql

index a6375511f61f9423b4d2c471aeb605bb1cfd0490..cc093556e5b2e987fb24c7a384f0741ddef2f93e 100644 (file)
@@ -1761,7 +1761,8 @@ plpgsql_parse_cwordtype(List *idents)
        classStruct->relkind != RELKIND_VIEW &&
        classStruct->relkind != RELKIND_MATVIEW &&
        classStruct->relkind != RELKIND_COMPOSITE_TYPE &&
-       classStruct->relkind != RELKIND_FOREIGN_TABLE)
+       classStruct->relkind != RELKIND_FOREIGN_TABLE &&
+       classStruct->relkind != RELKIND_PARTITIONED_TABLE)
        goto done;
 
    /*
@@ -1987,7 +1988,8 @@ build_row_from_class(Oid classOid)
        classStruct->relkind != RELKIND_VIEW &&
        classStruct->relkind != RELKIND_MATVIEW &&
        classStruct->relkind != RELKIND_COMPOSITE_TYPE &&
-       classStruct->relkind != RELKIND_FOREIGN_TABLE)
+       classStruct->relkind != RELKIND_FOREIGN_TABLE &&
+       classStruct->relkind != RELKIND_PARTITIONED_TABLE)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("relation \"%s\" is not a table", relname)));
index 7ebbde60d3034998abc217928ea860b56cf64e24..35b83f7b009797f1ffe954f6f252a07aa5dfb156 100644 (file)
@@ -5979,3 +5979,48 @@ LINE 1: SELECT (SELECT string_agg(id || '=' || name, ',') FROM d)
                                                ^
 QUERY:  SELECT (SELECT string_agg(id || '=' || name, ',') FROM d)
 CONTEXT:  PL/pgSQL function alter_table_under_transition_tables_upd_func() line 3 at RAISE
+--
+-- Check type parsing and record fetching from partitioned tables
+--
+CREATE TABLE partitioned_table (a int, b text) PARTITION BY LIST (a);
+CREATE TABLE pt_part1 PARTITION OF partitioned_table FOR VALUES IN (1);
+CREATE TABLE pt_part2 PARTITION OF partitioned_table FOR VALUES IN (2);
+INSERT INTO partitioned_table VALUES (1, 'Row 1');
+INSERT INTO partitioned_table VALUES (2, 'Row 2');
+CREATE OR REPLACE FUNCTION get_from_partitioned_table(partitioned_table.a%type)
+RETURNS partitioned_table AS $$
+DECLARE
+    a_val partitioned_table.a%TYPE;
+    result partitioned_table%ROWTYPE;
+BEGIN
+    a_val := $1;
+    SELECT * INTO result FROM partitioned_table WHERE a = a_val;
+    RETURN result;
+END; $$ LANGUAGE plpgsql;
+NOTICE:  type reference partitioned_table.a%TYPE converted to integer
+SELECT * FROM get_from_partitioned_table(1) AS t;
+ a |   b   
+---+-------
+ 1 | Row 1
+(1 row)
+
+CREATE OR REPLACE FUNCTION list_partitioned_table()
+RETURNS SETOF partitioned_table.a%TYPE AS $$
+DECLARE
+    row partitioned_table%ROWTYPE;
+    a_val partitioned_table.a%TYPE;
+BEGIN
+    FOR row IN SELECT * FROM partitioned_table ORDER BY a LOOP
+        a_val := row.a;
+        RETURN NEXT a_val;
+    END LOOP;
+    RETURN;
+END; $$ LANGUAGE plpgsql;
+NOTICE:  type reference partitioned_table.a%TYPE converted to integer
+SELECT * FROM list_partitioned_table() AS t;
+ t 
+---
+ 1
+ 2
+(2 rows)
+
index 60d1d38e346023a8e30cb6fcefe890588d4a955e..f957d70c5ff5f8f63d25f239fffa6b0a81f771f4 100644 (file)
@@ -4766,3 +4766,42 @@ ALTER TABLE alter_table_under_transition_tables
   DROP column name;
 UPDATE alter_table_under_transition_tables
   SET id = id;
+
+--
+-- Check type parsing and record fetching from partitioned tables
+--
+
+CREATE TABLE partitioned_table (a int, b text) PARTITION BY LIST (a);
+CREATE TABLE pt_part1 PARTITION OF partitioned_table FOR VALUES IN (1);
+CREATE TABLE pt_part2 PARTITION OF partitioned_table FOR VALUES IN (2);
+
+INSERT INTO partitioned_table VALUES (1, 'Row 1');
+INSERT INTO partitioned_table VALUES (2, 'Row 2');
+
+CREATE OR REPLACE FUNCTION get_from_partitioned_table(partitioned_table.a%type)
+RETURNS partitioned_table AS $$
+DECLARE
+    a_val partitioned_table.a%TYPE;
+    result partitioned_table%ROWTYPE;
+BEGIN
+    a_val := $1;
+    SELECT * INTO result FROM partitioned_table WHERE a = a_val;
+    RETURN result;
+END; $$ LANGUAGE plpgsql;
+
+SELECT * FROM get_from_partitioned_table(1) AS t;
+
+CREATE OR REPLACE FUNCTION list_partitioned_table()
+RETURNS SETOF partitioned_table.a%TYPE AS $$
+DECLARE
+    row partitioned_table%ROWTYPE;
+    a_val partitioned_table.a%TYPE;
+BEGIN
+    FOR row IN SELECT * FROM partitioned_table ORDER BY a LOOP
+        a_val := row.a;
+        RETURN NEXT a_val;
+    END LOOP;
+    RETURN;
+END; $$ LANGUAGE plpgsql;
+
+SELECT * FROM list_partitioned_table() AS t;