mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
Add code to check that IF/WHILE/EXIT test expressions are boolean,
and try to coerce the values to boolean if not. Per recent discussions.
This commit is contained in:
parent
55d85f42a8
commit
04b40923d6
@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.92 2003/09/28 23:37:45 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93 2003/10/01 21:47:42 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -52,7 +52,6 @@
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static const char *const raise_skip_msg = "RAISE";
|
||||
@ -151,6 +150,9 @@ static void exec_eval_datum(PLpgSQL_execstate * estate,
|
||||
static int exec_eval_integer(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr,
|
||||
bool *isNull);
|
||||
static bool exec_eval_boolean(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr,
|
||||
bool *isNull);
|
||||
static Datum exec_eval_expr(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr,
|
||||
bool *isNull,
|
||||
@ -164,6 +166,7 @@ static void exec_move_row(PLpgSQL_execstate * estate,
|
||||
static HeapTuple make_tuple_from_row(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_row * row,
|
||||
TupleDesc tupdesc);
|
||||
static char *convert_value_to_string(Datum value, Oid valtype);
|
||||
static Datum exec_cast_value(Datum value, Oid valtype,
|
||||
Oid reqtype,
|
||||
FmgrInfo *reqinput,
|
||||
@ -1111,14 +1114,13 @@ exec_stmt_getdiag(PLpgSQL_execstate * estate, PLpgSQL_stmt_getdiag * stmt)
|
||||
static int
|
||||
exec_stmt_if(PLpgSQL_execstate * estate, PLpgSQL_stmt_if * stmt)
|
||||
{
|
||||
Datum value;
|
||||
Oid valtype;
|
||||
bool value;
|
||||
bool isnull = false;
|
||||
|
||||
value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype);
|
||||
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
||||
exec_eval_cleanup(estate);
|
||||
|
||||
if (!isnull && DatumGetBool(value))
|
||||
if (!isnull && value)
|
||||
{
|
||||
if (stmt->true_body != NULL)
|
||||
return exec_stmts(estate, stmt->true_body);
|
||||
@ -1183,16 +1185,16 @@ exec_stmt_loop(PLpgSQL_execstate * estate, PLpgSQL_stmt_loop * stmt)
|
||||
static int
|
||||
exec_stmt_while(PLpgSQL_execstate * estate, PLpgSQL_stmt_while * stmt)
|
||||
{
|
||||
Datum value;
|
||||
Oid valtype;
|
||||
bool value;
|
||||
bool isnull = false;
|
||||
int rc;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype);
|
||||
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
||||
exec_eval_cleanup(estate);
|
||||
if (isnull || !DatumGetBool(value))
|
||||
|
||||
if (isnull || !value)
|
||||
break;
|
||||
|
||||
rc = exec_stmts(estate, stmt->body);
|
||||
@ -1540,18 +1542,17 @@ exec_stmt_select(PLpgSQL_execstate * estate, PLpgSQL_stmt_select * stmt)
|
||||
static int
|
||||
exec_stmt_exit(PLpgSQL_execstate * estate, PLpgSQL_stmt_exit * stmt)
|
||||
{
|
||||
Datum value;
|
||||
Oid valtype;
|
||||
bool isnull = false;
|
||||
|
||||
/*
|
||||
* If the exit has a condition, check that it's true
|
||||
*/
|
||||
if (stmt->cond != NULL)
|
||||
{
|
||||
value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype);
|
||||
bool value;
|
||||
bool isnull = false;
|
||||
|
||||
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
||||
exec_eval_cleanup(estate);
|
||||
if (isnull || !DatumGetBool(value))
|
||||
if (isnull || !value)
|
||||
return PLPGSQL_RC_OK;
|
||||
}
|
||||
|
||||
@ -1785,9 +1786,6 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
|
||||
Oid paramtypeid;
|
||||
Datum paramvalue;
|
||||
bool paramisnull;
|
||||
HeapTuple typetup;
|
||||
Form_pg_type typeStruct;
|
||||
FmgrInfo finfo_output;
|
||||
char *extval;
|
||||
int pidx = 0;
|
||||
char c[2] = {0, 0};
|
||||
@ -1822,22 +1820,7 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
|
||||
if (paramisnull)
|
||||
extval = "<NULL>";
|
||||
else
|
||||
{
|
||||
typetup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(paramtypeid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typetup))
|
||||
elog(ERROR, "cache lookup failed for type %u",
|
||||
paramtypeid);
|
||||
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
||||
|
||||
fmgr_info(typeStruct->typoutput, &finfo_output);
|
||||
extval = DatumGetCString(FunctionCall3(&finfo_output,
|
||||
paramvalue,
|
||||
ObjectIdGetDatum(typeStruct->typelem),
|
||||
Int32GetDatum(-1)));
|
||||
ReleaseSysCache(typetup);
|
||||
}
|
||||
extval = convert_value_to_string(paramvalue, paramtypeid);
|
||||
plpgsql_dstring_append(&ds, extval);
|
||||
pidx++;
|
||||
continue;
|
||||
@ -2091,9 +2074,6 @@ exec_stmt_dynexecute(PLpgSQL_execstate * estate,
|
||||
bool isnull = false;
|
||||
Oid restype;
|
||||
char *querystr;
|
||||
HeapTuple typetup;
|
||||
Form_pg_type typeStruct;
|
||||
FmgrInfo finfo_output;
|
||||
int exec_res;
|
||||
|
||||
/*
|
||||
@ -2106,23 +2086,9 @@ exec_stmt_dynexecute(PLpgSQL_execstate * estate,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("cannot EXECUTE a null querystring")));
|
||||
|
||||
/*
|
||||
* Get the C-String representation.
|
||||
*/
|
||||
typetup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(restype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typetup))
|
||||
elog(ERROR, "cache lookup failed for type %u", restype);
|
||||
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
||||
/* Get the C-String representation */
|
||||
querystr = convert_value_to_string(query, restype);
|
||||
|
||||
fmgr_info(typeStruct->typoutput, &finfo_output);
|
||||
querystr = DatumGetCString(FunctionCall3(&finfo_output,
|
||||
query,
|
||||
ObjectIdGetDatum(typeStruct->typelem),
|
||||
Int32GetDatum(-1)));
|
||||
|
||||
ReleaseSysCache(typetup);
|
||||
exec_eval_cleanup(estate);
|
||||
|
||||
/*
|
||||
@ -2211,9 +2177,6 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
|
||||
int rc = PLPGSQL_RC_OK;
|
||||
int i;
|
||||
int n;
|
||||
HeapTuple typetup;
|
||||
Form_pg_type typeStruct;
|
||||
FmgrInfo finfo_output;
|
||||
void *plan;
|
||||
Portal portal;
|
||||
bool found = false;
|
||||
@ -2238,23 +2201,9 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("cannot EXECUTE a null querystring")));
|
||||
|
||||
/*
|
||||
* Get the C-String representation.
|
||||
*/
|
||||
typetup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(restype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typetup))
|
||||
elog(ERROR, "cache lookup failed for type %u", restype);
|
||||
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
||||
/* Get the C-String representation */
|
||||
querystr = convert_value_to_string(query, restype);
|
||||
|
||||
fmgr_info(typeStruct->typoutput, &finfo_output);
|
||||
querystr = DatumGetCString(FunctionCall3(&finfo_output,
|
||||
query,
|
||||
ObjectIdGetDatum(typeStruct->typelem),
|
||||
Int32GetDatum(-1)));
|
||||
|
||||
ReleaseSysCache(typetup);
|
||||
exec_eval_cleanup(estate);
|
||||
|
||||
/*
|
||||
@ -2428,9 +2377,6 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
|
||||
Datum queryD;
|
||||
Oid restype;
|
||||
char *querystr;
|
||||
HeapTuple typetup;
|
||||
Form_pg_type typeStruct;
|
||||
FmgrInfo finfo_output;
|
||||
void *curplan;
|
||||
|
||||
/* ----------
|
||||
@ -2445,24 +2391,9 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("cannot EXECUTE a null querystring")));
|
||||
|
||||
/* ----------
|
||||
* Get the C-String representation.
|
||||
* ----------
|
||||
*/
|
||||
typetup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(restype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typetup))
|
||||
elog(ERROR, "cache lookup failed for type %u", restype);
|
||||
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
||||
/* Get the C-String representation */
|
||||
querystr = convert_value_to_string(queryD, restype);
|
||||
|
||||
fmgr_info(typeStruct->typoutput, &finfo_output);
|
||||
querystr = DatumGetCString(FunctionCall3(&finfo_output,
|
||||
queryD,
|
||||
ObjectIdGetDatum(typeStruct->typelem),
|
||||
Int32GetDatum(-1)));
|
||||
|
||||
ReleaseSysCache(typetup);
|
||||
exec_eval_cleanup(estate);
|
||||
|
||||
/* ----------
|
||||
@ -3131,6 +3062,28 @@ exec_eval_integer(PLpgSQL_execstate * estate,
|
||||
return DatumGetInt32(exprdatum);
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* exec_eval_boolean Evaluate an expression, coerce result to bool
|
||||
*
|
||||
* Note we do not do exec_eval_cleanup here; the caller must do it at
|
||||
* some later point.
|
||||
* ----------
|
||||
*/
|
||||
static bool
|
||||
exec_eval_boolean(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr,
|
||||
bool *isNull)
|
||||
{
|
||||
Datum exprdatum;
|
||||
Oid exprtypeid;
|
||||
|
||||
exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
|
||||
exprdatum = exec_simple_cast_value(exprdatum, exprtypeid,
|
||||
BOOLOID, -1,
|
||||
isNull);
|
||||
return DatumGetBool(exprdatum);
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* exec_eval_expr Evaluate an expression and return
|
||||
* the result Datum.
|
||||
@ -3560,6 +3513,31 @@ make_tuple_from_row(PLpgSQL_execstate * estate,
|
||||
return tuple;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* convert_value_to_string Convert a non-null Datum to C string
|
||||
*
|
||||
* Note: callers generally assume that the result is a palloc'd string and
|
||||
* should be pfree'd. This is not all that safe an assumption ...
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
convert_value_to_string(Datum value, Oid valtype)
|
||||
{
|
||||
Oid typOutput;
|
||||
Oid typElem;
|
||||
bool typIsVarlena;
|
||||
FmgrInfo finfo_output;
|
||||
|
||||
getTypeOutputInfo(valtype, &typOutput, &typElem, &typIsVarlena);
|
||||
|
||||
fmgr_info(typOutput, &finfo_output);
|
||||
|
||||
return DatumGetCString(FunctionCall3(&finfo_output,
|
||||
value,
|
||||
ObjectIdGetDatum(typElem),
|
||||
Int32GetDatum(-1)));
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* exec_cast_value Cast a value if required
|
||||
* ----------
|
||||
@ -3580,29 +3558,14 @@ exec_cast_value(Datum value, Oid valtype,
|
||||
*/
|
||||
if (valtype != reqtype || reqtypmod != -1)
|
||||
{
|
||||
HeapTuple typetup;
|
||||
Form_pg_type typeStruct;
|
||||
FmgrInfo finfo_output;
|
||||
char *extval;
|
||||
|
||||
typetup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(valtype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typetup))
|
||||
elog(ERROR, "cache lookup failed for type %u", valtype);
|
||||
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
||||
|
||||
fmgr_info(typeStruct->typoutput, &finfo_output);
|
||||
extval = DatumGetCString(FunctionCall3(&finfo_output,
|
||||
value,
|
||||
ObjectIdGetDatum(typeStruct->typelem),
|
||||
Int32GetDatum(-1)));
|
||||
extval = convert_value_to_string(value, valtype);
|
||||
value = FunctionCall3(reqinput,
|
||||
CStringGetDatum(extval),
|
||||
ObjectIdGetDatum(reqtypelem),
|
||||
Int32GetDatum(reqtypmod));
|
||||
pfree(extval);
|
||||
ReleaseSysCache(typetup);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3631,6 +3594,7 @@ exec_simple_cast_value(Datum value, Oid valtype,
|
||||
FmgrInfo finfo_input;
|
||||
|
||||
getTypeInputInfo(reqtype, &typInput, &typElem);
|
||||
|
||||
fmgr_info(typInput, &finfo_input);
|
||||
|
||||
value = exec_cast_value(value,
|
||||
|
Loading…
Reference in New Issue
Block a user