Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit acb2d7d

Browse files
committed
plpgsql: report proper line number for errors in variable initialization.
Previously, we pointed at the surrounding block's BEGIN keyword. If there are multiple variables being initialized in a DECLARE section, this isn't good enough: it can be quite confusing and unhelpful. We do know where the variable's declaration started, so it just takes a tiny bit more error-reporting infrastructure to use that. Discussion: https://postgr.es/m/713975.1635530414@sss.pgh.pa.us
1 parent fd27065 commit acb2d7d

File tree

6 files changed

+49
-31
lines changed

6 files changed

+49
-31
lines changed

src/pl/plpgsql/src/expected/plpgsql_domain.out

+7-7
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ SELECT * FROM test_assign_booltrue(true, true);
3333

3434
SELECT * FROM test_assign_booltrue(false, true);
3535
ERROR: value for domain booltrue violates check constraint "booltrue_check"
36-
CONTEXT: PL/pgSQL function test_assign_booltrue(boolean,boolean) line 3 during statement block local variable initialization
36+
CONTEXT: PL/pgSQL function test_assign_booltrue(boolean,boolean) line 2 during statement block local variable initialization
3737
SELECT * FROM test_assign_booltrue(true, false);
3838
ERROR: value for domain booltrue violates check constraint "booltrue_check"
3939
CONTEXT: PL/pgSQL function test_assign_booltrue(boolean,boolean) line 4 at assignment
@@ -76,7 +76,7 @@ ERROR: value for domain uint2 violates check constraint "uint2_check"
7676
CONTEXT: PL/pgSQL function test_assign_uint2(integer,integer) line 4 at assignment
7777
SELECT * FROM test_assign_uint2(-100, 50);
7878
ERROR: value for domain uint2 violates check constraint "uint2_check"
79-
CONTEXT: PL/pgSQL function test_assign_uint2(integer,integer) line 3 during statement block local variable initialization
79+
CONTEXT: PL/pgSQL function test_assign_uint2(integer,integer) line 2 during statement block local variable initialization
8080
SELECT * FROM test_assign_uint2(null, 1);
8181
test_assign_uint2
8282
-------------------
@@ -115,7 +115,7 @@ SELECT * FROM test_assign_nnint(10, 20);
115115

116116
SELECT * FROM test_assign_nnint(null, 20);
117117
ERROR: domain nnint does not allow null values
118-
CONTEXT: PL/pgSQL function test_assign_nnint(integer,integer) line 3 during statement block local variable initialization
118+
CONTEXT: PL/pgSQL function test_assign_nnint(integer,integer) line 2 during statement block local variable initialization
119119
SELECT * FROM test_assign_nnint(10, null);
120120
ERROR: domain nnint does not allow null values
121121
CONTEXT: PL/pgSQL function test_assign_nnint(integer,integer) line 4 at assignment
@@ -168,7 +168,7 @@ ERROR: value for domain ordered_pair_domain violates check constraint "ordered_
168168
CONTEXT: PL/pgSQL function test_assign_ordered_pair_domain(integer,integer,integer) line 4 at assignment
169169
SELECT * FROM test_assign_ordered_pair_domain(2,1,3);
170170
ERROR: value for domain ordered_pair_domain violates check constraint "ordered_pair_domain_check"
171-
CONTEXT: PL/pgSQL function test_assign_ordered_pair_domain(integer,integer,integer) line 3 during statement block local variable initialization
171+
CONTEXT: PL/pgSQL function test_assign_ordered_pair_domain(integer,integer,integer) line 2 during statement block local variable initialization
172172
--
173173
-- Arrays of domains
174174
--
@@ -276,7 +276,7 @@ ERROR: domain nnint does not allow null values
276276
CONTEXT: PL/pgSQL function test_assign_nnint_container(integer,integer,integer) line 4 at assignment
277277
SELECT * FROM test_assign_nnint_container(1,null,3);
278278
ERROR: domain nnint does not allow null values
279-
CONTEXT: PL/pgSQL function test_assign_nnint_container(integer,integer,integer) line 3 during statement block local variable initialization
279+
CONTEXT: PL/pgSQL function test_assign_nnint_container(integer,integer,integer) line 2 during statement block local variable initialization
280280
-- Since core system allows this:
281281
SELECT null::nnint_container;
282282
nnint_container
@@ -356,7 +356,7 @@ ERROR: value for domain ordered_named_pair violates check constraint "ordered_n
356356
CONTEXT: PL/pgSQL function test_assign_ordered_named_pair(integer,integer,integer) line 4 at assignment
357357
SELECT * FROM test_assign_ordered_named_pair(2,1,3);
358358
ERROR: value for domain ordered_named_pair violates check constraint "ordered_named_pair_check"
359-
CONTEXT: PL/pgSQL function test_assign_ordered_named_pair(integer,integer,integer) line 3 during statement block local variable initialization
359+
CONTEXT: PL/pgSQL function test_assign_ordered_named_pair(integer,integer,integer) line 2 during statement block local variable initialization
360360
CREATE FUNCTION build_ordered_named_pairs(i int, j int) RETURNS ordered_named_pair[] AS $$
361361
begin
362362
return array[row(i, j), row(i, j+1)];
@@ -388,7 +388,7 @@ SELECT * FROM test_assign_ordered_named_pairs(1,2,3);
388388

389389
SELECT * FROM test_assign_ordered_named_pairs(2,1,3);
390390
ERROR: value for domain ordered_named_pair violates check constraint "ordered_named_pair_check"
391-
CONTEXT: PL/pgSQL function test_assign_ordered_named_pairs(integer,integer,integer) line 3 during statement block local variable initialization
391+
CONTEXT: PL/pgSQL function test_assign_ordered_named_pairs(integer,integer,integer) line 2 during statement block local variable initialization
392392
SELECT * FROM test_assign_ordered_named_pairs(1,2,0); -- should fail someday
393393
test_assign_ordered_named_pairs
394394
---------------------------------

src/pl/plpgsql/src/expected/plpgsql_varprops.out

+11-11
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ begin
7777
end$$;
7878
ERROR: division by zero
7979
CONTEXT: SQL expression "1/0"
80-
PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
80+
PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
8181
do $$
8282
declare x bigint[] := array[1,3,5];
8383
begin
@@ -120,7 +120,7 @@ begin
120120
raise notice 'x = %', x;
121121
end$$;
122122
ERROR: null value cannot be assigned to variable "x" declared NOT NULL
123-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
123+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
124124
do $$
125125
declare x record not null; -- fail
126126
begin
@@ -147,7 +147,7 @@ begin
147147
raise notice 'x = %', x;
148148
end$$;
149149
ERROR: null value cannot be assigned to variable "x" declared NOT NULL
150-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
150+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
151151
do $$
152152
declare x var_record not null; -- fail
153153
begin
@@ -174,7 +174,7 @@ begin
174174
raise notice 'x = %', x;
175175
end$$;
176176
ERROR: null value cannot be assigned to variable "x" declared NOT NULL
177-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
177+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
178178
-- Check that variables are reinitialized on block re-entry.
179179
do $$
180180
begin
@@ -216,14 +216,14 @@ begin
216216
raise notice 'x = %', x;
217217
end$$;
218218
ERROR: domain int_nn does not allow null values
219-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
219+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
220220
do $$
221221
declare x int_nn := null; -- fail
222222
begin
223223
raise notice 'x = %', x;
224224
end$$;
225225
ERROR: domain int_nn does not allow null values
226-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
226+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
227227
do $$
228228
declare x int_nn := 42;
229229
begin
@@ -239,14 +239,14 @@ begin
239239
raise notice 'x = %', x;
240240
end$$;
241241
ERROR: domain var_record_nn does not allow null values
242-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
242+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
243243
do $$
244244
declare x var_record_nn := null; -- fail
245245
begin
246246
raise notice 'x = %', x;
247247
end$$;
248248
ERROR: domain var_record_nn does not allow null values
249-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
249+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
250250
do $$
251251
declare x var_record_nn := row(1,2);
252252
begin
@@ -263,21 +263,21 @@ begin
263263
raise notice 'x = %', x;
264264
end$$;
265265
ERROR: value for domain var_record_colnn violates check constraint "var_record_colnn_check"
266-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
266+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
267267
do $$
268268
declare x var_record_colnn := null; -- fail
269269
begin
270270
raise notice 'x = %', x;
271271
end$$;
272272
ERROR: value for domain var_record_colnn violates check constraint "var_record_colnn_check"
273-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
273+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
274274
do $$
275275
declare x var_record_colnn := row(1,null); -- fail
276276
begin
277277
raise notice 'x = %', x;
278278
end$$;
279279
ERROR: value for domain var_record_colnn violates check constraint "var_record_colnn_check"
280-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
280+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
281281
do $$
282282
declare x var_record_colnn := row(1,2);
283283
begin

src/pl/plpgsql/src/pl_exec.c

+26-9
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,20 @@ static void
12141214
plpgsql_exec_error_callback(void *arg)
12151215
{
12161216
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
1217+
int err_lineno;
1218+
1219+
/*
1220+
* If err_var is set, report the variable's declaration line number.
1221+
* Otherwise, if err_stmt is set, report the err_stmt's line number. When
1222+
* err_stmt is not set, we're in function entry/exit, or some such place
1223+
* not attached to a specific line number.
1224+
*/
1225+
if (estate->err_var != NULL)
1226+
err_lineno = estate->err_var->lineno;
1227+
else if (estate->err_stmt != NULL)
1228+
err_lineno = estate->err_stmt->lineno;
1229+
else
1230+
err_lineno = 0;
12171231

12181232
if (estate->err_text != NULL)
12191233
{
@@ -1222,21 +1236,16 @@ plpgsql_exec_error_callback(void *arg)
12221236
* actually need it. Therefore, places that set up err_text should
12231237
* use gettext_noop() to ensure the strings get recorded in the
12241238
* message dictionary.
1225-
*
1226-
* If both err_text and err_stmt are set, use the err_text as
1227-
* description, but report the err_stmt's line number. When err_stmt
1228-
* is not set, we're in function entry/exit, or some such place not
1229-
* attached to a specific line number.
12301239
*/
1231-
if (estate->err_stmt != NULL)
1240+
if (err_lineno > 0)
12321241
{
12331242
/*
12341243
* translator: last %s is a phrase such as "during statement block
12351244
* local variable initialization"
12361245
*/
12371246
errcontext("PL/pgSQL function %s line %d %s",
12381247
estate->func->fn_signature,
1239-
estate->err_stmt->lineno,
1248+
err_lineno,
12401249
_(estate->err_text));
12411250
}
12421251
else
@@ -1250,12 +1259,12 @@ plpgsql_exec_error_callback(void *arg)
12501259
_(estate->err_text));
12511260
}
12521261
}
1253-
else if (estate->err_stmt != NULL)
1262+
else if (estate->err_stmt != NULL && err_lineno > 0)
12541263
{
12551264
/* translator: last %s is a plpgsql statement type name */
12561265
errcontext("PL/pgSQL function %s line %d at %s",
12571266
estate->func->fn_signature,
1258-
estate->err_stmt->lineno,
1267+
err_lineno,
12591268
plpgsql_stmt_typename(estate->err_stmt));
12601269
}
12611270
else
@@ -1643,7 +1652,12 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
16431652
* Note that we currently don't support promise datums within blocks,
16441653
* only at a function's outermost scope, so we needn't handle those
16451654
* here.
1655+
*
1656+
* Since RECFIELD isn't a supported case either, it's okay to cast the
1657+
* PLpgSQL_datum to PLpgSQL_variable.
16461658
*/
1659+
estate->err_var = (PLpgSQL_variable *) datum;
1660+
16471661
switch (datum->dtype)
16481662
{
16491663
case PLPGSQL_DTYPE_VAR:
@@ -1717,6 +1731,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
17171731
}
17181732
}
17191733

1734+
estate->err_var = NULL;
1735+
17201736
if (block->exceptions)
17211737
{
17221738
/*
@@ -4041,6 +4057,7 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
40414057
estate->eval_econtext = NULL;
40424058

40434059
estate->err_stmt = NULL;
4060+
estate->err_var = NULL;
40444061
estate->err_text = NULL;
40454062

40464063
estate->plugin_info = NULL;

src/pl/plpgsql/src/plpgsql.h

+1
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,7 @@ typedef struct PLpgSQL_execstate
10881088

10891089
/* status information for error context reporting */
10901090
PLpgSQL_stmt *err_stmt; /* current stmt */
1091+
PLpgSQL_variable *err_var; /* current variable, if in a DECLARE section */
10911092
const char *err_text; /* additional state info */
10921093

10931094
void *plugin_info; /* reserved for use by optional plugin */

src/test/regress/expected/domain.out

+2-2
Original file line numberDiff line numberDiff line change
@@ -847,15 +847,15 @@ begin
847847
end$$ language plpgsql;
848848
select doubledecrement(3); -- fail because of implicit null assignment
849849
ERROR: domain pos_int does not allow null values
850-
CONTEXT: PL/pgSQL function doubledecrement(pos_int) line 3 during statement block local variable initialization
850+
CONTEXT: PL/pgSQL function doubledecrement(pos_int) line 2 during statement block local variable initialization
851851
create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
852852
declare v pos_int := 0;
853853
begin
854854
return p1;
855855
end$$ language plpgsql;
856856
select doubledecrement(3); -- fail at initialization assignment
857857
ERROR: value for domain pos_int violates check constraint "pos_int_check"
858-
CONTEXT: PL/pgSQL function doubledecrement(pos_int) line 3 during statement block local variable initialization
858+
CONTEXT: PL/pgSQL function doubledecrement(pos_int) line 2 during statement block local variable initialization
859859
create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
860860
declare v pos_int := 1;
861861
begin

src/test/regress/expected/plpgsql.out

+2-2
Original file line numberDiff line numberDiff line change
@@ -4648,7 +4648,7 @@ ERROR: column "x" does not exist
46484648
LINE 1: x + 1
46494649
^
46504650
QUERY: x + 1
4651-
CONTEXT: PL/pgSQL function inline_code_block line 3 during statement block local variable initialization
4651+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
46524652
do $$
46534653
declare y int := x + 1; -- error
46544654
x int := 42;
@@ -4660,7 +4660,7 @@ ERROR: column "x" does not exist
46604660
LINE 1: x + 1
46614661
^
46624662
QUERY: x + 1
4663-
CONTEXT: PL/pgSQL function inline_code_block line 4 during statement block local variable initialization
4663+
CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
46644664
do $$
46654665
declare x int := 42;
46664666
y int := x + 1;

0 commit comments

Comments
 (0)