summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorTomas Vondra2018-07-24 23:09:03 +0000
committerTomas Vondra2018-07-24 23:46:32 +0000
commit167075be3ab1547e186096bb8e6e448cd8eea5af (patch)
treebf406f5eb63f2ea68c60c673d832a95c903c0c8d /src/test
parent2d3067595299d2ac1f29bbc26a83a99d59b33d4e (diff)
Add strict_multi_assignment and too_many_rows plpgsql checks
Until now shadowed_variables was the only plpgsql check supported by plpgsql.extra_warnings and plpgsql.extra_errors. This patch introduces two new checks - strict_multi_assignment and too_many_rows. Unlike shadowed_variables, these new checks are enforced at run-time. strict_multi_assignment checks that commands allowing multi-assignment (for example SELECT INTO) have the same number of sources and targets. too_many_rows checks that queries with an INTO clause return one row exactly. These checks are aimed at cases that are technically valid and allowed, but are often a sign of a bug. Therefore those checks are expected to be enabled primarily in development and testing environments. Author: Pavel Stehule Reviewed-by: Stephen Frost, Tomas Vondra Discussion: https://www.postgresql.org/message-id/flat/CAFj8pRA2kKRDKpUNwLY0GeG1OqOp+tLS2yQA1V41gzuSz-hCng@mail.gmail.com
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/plpgsql.out107
-rw-r--r--src/test/regress/sql/plpgsql.sql89
2 files changed, 196 insertions, 0 deletions
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index dde2cc4bd09..f78db4aae53 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2778,6 +2778,7 @@ begin
end$$ language plpgsql;
select stricttest();
ERROR: query returned more than one row
+HINT: Make sure the query returns a single row, or use LIMIT 1
CONTEXT: PL/pgSQL function stricttest() line 5 at SQL statement
create or replace function stricttest() returns void as $$
declare x record;
@@ -2851,6 +2852,7 @@ begin
end$$ language plpgsql;
select stricttest();
ERROR: query returned more than one row
+HINT: Make sure the query returns a single row, or use LIMIT 1
CONTEXT: PL/pgSQL function stricttest() line 5 at SQL statement
create or replace function stricttest() returns void as $$
declare x record;
@@ -2916,6 +2918,7 @@ end$$ language plpgsql;
select stricttest();
ERROR: query returned more than one row
DETAIL: parameters: p1 = '2', p3 = 'foo'
+HINT: Make sure the query returns a single row, or use LIMIT 1
CONTEXT: PL/pgSQL function stricttest() line 8 at SQL statement
create or replace function stricttest() returns void as $$
declare x record;
@@ -2926,6 +2929,7 @@ begin
end$$ language plpgsql;
select stricttest();
ERROR: query returned more than one row
+HINT: Make sure the query returns a single row, or use LIMIT 1
CONTEXT: PL/pgSQL function stricttest() line 5 at SQL statement
create or replace function stricttest() returns void as $$
declare x record;
@@ -2973,6 +2977,7 @@ begin
end$$ language plpgsql;
select stricttest();
ERROR: query returned more than one row
+HINT: Make sure the query returns a single row, or use LIMIT 1
CONTEXT: PL/pgSQL function stricttest() line 10 at SQL statement
reset plpgsql.print_strict_params;
create or replace function stricttest() returns void as $$
@@ -2990,6 +2995,7 @@ end$$ language plpgsql;
select stricttest();
ERROR: query returned more than one row
DETAIL: parameters: p1 = '2', p3 = 'foo'
+HINT: Make sure the query returns a single row, or use LIMIT 1
CONTEXT: PL/pgSQL function stricttest() line 10 at SQL statement
-- test warnings and errors
set plpgsql.extra_warnings to 'all';
@@ -3113,6 +3119,107 @@ select shadowtest(1);
t
(1 row)
+-- runtime extra checks
+set plpgsql.extra_warnings to 'too_many_rows';
+do $$
+declare x int;
+begin
+ select v from generate_series(1,2) g(v) into x;
+end;
+$$;
+WARNING: query returned more than one row
+HINT: Make sure the query returns a single row, or use LIMIT 1
+set plpgsql.extra_errors to 'too_many_rows';
+do $$
+declare x int;
+begin
+ select v from generate_series(1,2) g(v) into x;
+end;
+$$;
+ERROR: query returned more than one row
+HINT: Make sure the query returns a single row, or use LIMIT 1
+CONTEXT: PL/pgSQL function inline_code_block line 4 at SQL statement
+reset plpgsql.extra_errors;
+reset plpgsql.extra_warnings;
+set plpgsql.extra_warnings to 'strict_multi_assignment';
+do $$
+declare
+ x int;
+ y int;
+begin
+ select 1 into x, y;
+ select 1,2 into x, y;
+ select 1,2,3 into x, y;
+end
+$$;
+WARNING: number of source and target fields in assignment do not match
+DETAIL: strict_multi_assignment check of extra_warnings is active.
+HINT: Make sure the query returns the exact list of columns.
+WARNING: number of source and target fields in assignment do not match
+DETAIL: strict_multi_assignment check of extra_warnings is active.
+HINT: Make sure the query returns the exact list of columns.
+set plpgsql.extra_errors to 'strict_multi_assignment';
+do $$
+declare
+ x int;
+ y int;
+begin
+ select 1 into x, y;
+ select 1,2 into x, y;
+ select 1,2,3 into x, y;
+end
+$$;
+ERROR: number of source and target fields in assignment do not match
+DETAIL: strict_multi_assignment check of extra_errors is active.
+HINT: Make sure the query returns the exact list of columns.
+CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement
+create table test_01(a int, b int, c int);
+alter table test_01 drop column a;
+-- the check is active only when source table is not empty
+insert into test_01 values(10,20);
+do $$
+declare
+ x int;
+ y int;
+begin
+ select * from test_01 into x, y; -- should be ok
+ raise notice 'ok';
+ select * from test_01 into x; -- should to fail
+end;
+$$;
+NOTICE: ok
+ERROR: number of source and target fields in assignment do not match
+DETAIL: strict_multi_assignment check of extra_errors is active.
+HINT: Make sure the query returns the exact list of columns.
+CONTEXT: PL/pgSQL function inline_code_block line 8 at SQL statement
+do $$
+declare
+ t test_01;
+begin
+ select 1, 2 into t; -- should be ok
+ raise notice 'ok';
+ select 1, 2, 3 into t; -- should fail;
+end;
+$$;
+NOTICE: ok
+ERROR: number of source and target fields in assignment do not match
+DETAIL: strict_multi_assignment check of extra_errors is active.
+HINT: Make sure the query returns the exact list of columns.
+CONTEXT: PL/pgSQL function inline_code_block line 7 at SQL statement
+do $$
+declare
+ t test_01;
+begin
+ select 1 into t; -- should fail;
+end;
+$$;
+ERROR: number of source and target fields in assignment do not match
+DETAIL: strict_multi_assignment check of extra_errors is active.
+HINT: Make sure the query returns the exact list of columns.
+CONTEXT: PL/pgSQL function inline_code_block line 5 at SQL statement
+drop table test_01;
+reset plpgsql.extra_errors;
+reset plpgsql.extra_warnings;
-- test scrollable cursor support
create function sc_test() returns setof integer as $$
declare
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index e71d072aa98..01239e26bed 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -2627,6 +2627,95 @@ declare f1 int; begin return 1; end $$ language plpgsql;
select shadowtest(1);
+-- runtime extra checks
+set plpgsql.extra_warnings to 'too_many_rows';
+
+do $$
+declare x int;
+begin
+ select v from generate_series(1,2) g(v) into x;
+end;
+$$;
+
+set plpgsql.extra_errors to 'too_many_rows';
+
+do $$
+declare x int;
+begin
+ select v from generate_series(1,2) g(v) into x;
+end;
+$$;
+
+reset plpgsql.extra_errors;
+reset plpgsql.extra_warnings;
+
+set plpgsql.extra_warnings to 'strict_multi_assignment';
+
+do $$
+declare
+ x int;
+ y int;
+begin
+ select 1 into x, y;
+ select 1,2 into x, y;
+ select 1,2,3 into x, y;
+end
+$$;
+
+set plpgsql.extra_errors to 'strict_multi_assignment';
+
+do $$
+declare
+ x int;
+ y int;
+begin
+ select 1 into x, y;
+ select 1,2 into x, y;
+ select 1,2,3 into x, y;
+end
+$$;
+
+create table test_01(a int, b int, c int);
+
+alter table test_01 drop column a;
+
+-- the check is active only when source table is not empty
+insert into test_01 values(10,20);
+
+do $$
+declare
+ x int;
+ y int;
+begin
+ select * from test_01 into x, y; -- should be ok
+ raise notice 'ok';
+ select * from test_01 into x; -- should to fail
+end;
+$$;
+
+do $$
+declare
+ t test_01;
+begin
+ select 1, 2 into t; -- should be ok
+ raise notice 'ok';
+ select 1, 2, 3 into t; -- should fail;
+end;
+$$;
+
+do $$
+declare
+ t test_01;
+begin
+ select 1 into t; -- should fail;
+end;
+$$;
+
+drop table test_01;
+
+reset plpgsql.extra_errors;
+reset plpgsql.extra_warnings;
+
-- test scrollable cursor support
create function sc_test() returns setof integer as $$