Обсуждение: server crash: displaying sqlerrm in exception block
PostgreSQL version: 8.2.1
Operating system: Fedora 3
Description: server crash
Details:
I have compiled postgres 8.2.1 with gcc 4.1. and when executed this function
it crashes the server.
i also fetched the code from postgres repository (8.3devel) and tested this
code but it still crashing server.
Steps to produce
----------------------
CREATE OR REPLACE FUNCTION func2() RETURNS int as $$
BEGIN
RAISE EXCEPTION 'ex -----';
EXCEPTION
WHEN OTHERS THEN
RAISE INFO 'sql error msg %',sqlerrm;
DECLARE
v_msg VARCHAR(200) := sqlerrm;
BEGIN
RAISE INFO 'sql error msg %',sqlerrm;
ENd;
RETURN 0;
END;
$$ LANGUAGE plpgsql;
select func2();
Output
---------
INFO: sql error msg ex -----
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
"Asif Ali" <asifalirehman@gmail.com> writes:
> I have compiled postgres 8.2.1 with gcc 4.1. and when executed this function
> it crashes the server.
The attached patch (against HEAD) fixes your test case, but please see
whether it fixes your original problem; I'm not 100% confident in it
yet. There seem to be two different bugs here...
regards, tom lane
? libplpgsql.sl.1
Index: gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v
retrieving revision 1.97
diff -c -r1.97 gram.y
*** gram.y 1 Feb 2007 19:10:29 -0000 1.97
--- gram.y 8 Feb 2007 01:06:24 -0000
***************
*** 272,278 ****
$$.label = $1;
$$.n_initvars = 0;
$$.initvarnos = NULL;
- plpgsql_add_initdatums(NULL);
}
| opt_block_label decl_start
{
--- 272,277 ----
***************
*** 280,286 ****
$$.label = $1;
$$.n_initvars = 0;
$$.initvarnos = NULL;
- plpgsql_add_initdatums(NULL);
}
| opt_block_label decl_start decl_stmts
{
--- 279,284 ----
***************
*** 289,300 ****
--- 287,302 ----
$$.label = $3;
else
$$.label = $1;
+ /* Remember variables declared in decl_stmts */
$$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
}
;
decl_start : K_DECLARE
{
+ /* Forget any variables created before block */
+ plpgsql_add_initdatums(NULL);
+ /* Make variable names be local to block */
plpgsql_ns_setlocal(true);
}
;
***************
*** 990,998 ****
-1),
true);
- /* put the for-variable into the local block */
- plpgsql_add_initdatums(NULL);
-
new = palloc0(sizeof(PLpgSQL_stmt_fori));
new->cmd_type = PLPGSQL_STMT_FORI;
new->lineno = $1;
--- 992,997 ----
Index: pl_comp.c
===================================================================
RCS file: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v
retrieving revision 1.111
diff -c -r1.111 pl_comp.c
*** pl_comp.c 1 Feb 2007 19:10:29 -0000 1.111
--- pl_comp.c 8 Feb 2007 01:06:24 -0000
***************
*** 667,677 ****
function->found_varno = var->dno;
/*
- * Forget about the above created variables
- */
- plpgsql_add_initdatums(NULL);
-
- /*
* Now parse the function's text
*/
parse_rc = plpgsql_yyparse();
--- 667,672 ----
***************
*** 1893,1903 ****
/* ----------
! * plpgsql_add_initdatums Put all datum entries created
! * since the last call into the
! * finishing code block so the
! * block knows which variables to
! * reinitialize when entered.
* ----------
*/
int
--- 1888,1904 ----
/* ----------
! * plpgsql_add_initdatums Make an array of the datum numbers of
! * all the simple VAR datums created since the last call
! * to this function.
! *
! * If varnos is NULL, we just forget any datum entries created since the
! * last call.
! *
! * This is used around a DECLARE section to create a list of the VARs
! * that have to be initialized at block entry. Note that VARs can also
! * be created elsewhere than DECLARE, eg by a FOR-loop, but it is then
! * the responsibility of special-purpose code to initialize them.
* ----------
*/
int
Index: pl_exec.c
===================================================================
RCS file: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.187
diff -c -r1.187 pl_exec.c
*** pl_exec.c 1 Feb 2007 19:22:07 -0000 1.187
--- pl_exec.c 8 Feb 2007 01:06:25 -0000
***************
*** 885,927 ****
{
PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);
free_var(var);
! if (!var->isconst || var->isnull)
{
! if (var->default_val == NULL)
{
! /* Initially it contains a NULL */
! var->value = (Datum) 0;
! var->isnull = true;
! /*
! * If needed, give the datatype a chance to reject
! * NULLs, by assigning a NULL to the variable.
! * We claim the value is of type UNKNOWN, not the
! * var's datatype, else coercion will be skipped.
! * (Do this before the notnull check to be
! * consistent with exec_assign_value.)
! */
! if (!var->datatype->typinput.fn_strict)
! {
! bool valIsNull = true;
!
! exec_assign_value(estate,
! (PLpgSQL_datum *) var,
! (Datum) 0,
! UNKNOWNOID,
! &valIsNull);
! }
! if (var->notnull)
! ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",
var->refname)));
! }
! else
! {
! exec_assign_expr(estate, (PLpgSQL_datum *) var,
! var->default_val);
! }
}
}
break;
--- 885,927 ----
{
PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);
+ /* free any old value, in case re-entering block */
free_var(var);
!
! /* Initially it contains a NULL */
! var->value = (Datum) 0;
! var->isnull = true;
!
! if (var->default_val == NULL)
{
! /*
! * If needed, give the datatype a chance to reject
! * NULLs, by assigning a NULL to the variable.
! * We claim the value is of type UNKNOWN, not the
! * var's datatype, else coercion will be skipped.
! * (Do this before the notnull check to be
! * consistent with exec_assign_value.)
! */
! if (!var->datatype->typinput.fn_strict)
{
! bool valIsNull = true;
!
! exec_assign_value(estate,
! (PLpgSQL_datum *) var,
! (Datum) 0,
! UNKNOWNOID,
! &valIsNull);
! }
! if (var->notnull)
! ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",
var->refname)));
! }
! else
! {
! exec_assign_expr(estate, (PLpgSQL_datum *) var,
! var->default_val);
}
}
break;
***************
*** 1065,1071 ****
--- 1065,1073 ----
rc = exec_stmts(estate, exception->action);
free_var(state_var);
+ state_var->value = (Datum) 0;
free_var(errm_var);
+ errm_var->value = (Datum) 0;
break;
}
}
***************
*** 4867,4872 ****
--- 4869,4880 ----
}
}
+ /*
+ * free_var --- pfree any pass-by-reference value of the variable.
+ *
+ * This should always be followed by some assignment to var->value,
+ * as it leaves a dangling pointer.
+ */
static void
free_var(PLpgSQL_var *var)
{
"Asif Ali" <asifalirehman@gmail.com> writes:
> your patch fixes the crash but instead of displaying the sqlerrm value, it
> is displaying <NULL> in
> pl block, declared inside exception block.
Hm, not what I see here. Could you submit a test case that does that?
regards, tom lane
here is the test case CREATE OR REPLACE FUNCTION func() RETURNS int as $$ BEGIN RAISE EXCEPTION 'ex -----'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'sql error msg %',sqlerrm; DECLARE v_msg VARCHAR(200) := sqlerrm; BEGIN RAISE INFO 'sql error msg %',sqlerrm; -- it show's <NULL> RAISE INFO 'sql error v_msg %',v_msg; -- it show's <NULL> ENd; RETURN 0; END; $$ LANGUAGE plpgsql; Regards, --Asif On 2/8/07, Tom Lane <tgl@sss.pgh.pa.us> wrote: > > "Asif Ali" <asifalirehman@gmail.com> writes: > > your patch fixes the crash but instead of displaying the sqlerrm value, > it > > is displaying <NULL> in > > pl block, declared inside exception block. > > Hm, not what I see here. Could you submit a test case that does that? > > regards, tom lane > -- Regards, --Asif Ali Rehman
"Asif Ali" <asifalirehman@gmail.com> writes:
> here is the test case
It works for me:
regression=# select func();
INFO: sql error msg ex -----
INFO: sql error msg ex -----
INFO: sql error v_msg ex -----
func
------
0
(1 row)
Are you sure you applied the patch correctly? In particular, you'd need
a working version of bison to rebuild the gram.y file --- the behavior
you're reporting sounds like what would happen if that hadn't gotten
rebuilt.
regards, tom lane
Hi, well i just updated the code and found your patch is applied in there and it's working. may be i missed something while applying your patch. Regards, --Asif On 2/8/07, Tom Lane <tgl@sss.pgh.pa.us> wrote: > > "Asif Ali" <asifalirehman@gmail.com> writes: > > here is the test case > > It works for me: > > regression=# select func(); > INFO: sql error msg ex ----- > INFO: sql error msg ex ----- > INFO: sql error v_msg ex ----- > func > ------ > 0 > (1 row) > > Are you sure you applied the patch correctly? In particular, you'd need > a working version of bison to rebuild the gram.y file --- the behavior > you're reporting sounds like what would happen if that hadn't gotten > rebuilt. > > regards, tom lane > -- Regards, --Asif Ali Rehman