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:
Tom Lane 2003-10-01 21:47:42 +00:00
parent 55d85f42a8
commit 04b40923d6

View File

@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -52,7 +52,6 @@
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h"
static const char *const raise_skip_msg = "RAISE"; 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, static int exec_eval_integer(PLpgSQL_execstate * estate,
PLpgSQL_expr * expr, PLpgSQL_expr * expr,
bool *isNull); bool *isNull);
static bool exec_eval_boolean(PLpgSQL_execstate * estate,
PLpgSQL_expr * expr,
bool *isNull);
static Datum exec_eval_expr(PLpgSQL_execstate * estate, static Datum exec_eval_expr(PLpgSQL_execstate * estate,
PLpgSQL_expr * expr, PLpgSQL_expr * expr,
bool *isNull, bool *isNull,
@ -164,6 +166,7 @@ static void exec_move_row(PLpgSQL_execstate * estate,
static HeapTuple make_tuple_from_row(PLpgSQL_execstate * estate, static HeapTuple make_tuple_from_row(PLpgSQL_execstate * estate,
PLpgSQL_row * row, PLpgSQL_row * row,
TupleDesc tupdesc); TupleDesc tupdesc);
static char *convert_value_to_string(Datum value, Oid valtype);
static Datum exec_cast_value(Datum value, Oid valtype, static Datum exec_cast_value(Datum value, Oid valtype,
Oid reqtype, Oid reqtype,
FmgrInfo *reqinput, FmgrInfo *reqinput,
@ -1111,14 +1114,13 @@ exec_stmt_getdiag(PLpgSQL_execstate * estate, PLpgSQL_stmt_getdiag * stmt)
static int static int
exec_stmt_if(PLpgSQL_execstate * estate, PLpgSQL_stmt_if * stmt) exec_stmt_if(PLpgSQL_execstate * estate, PLpgSQL_stmt_if * stmt)
{ {
Datum value; bool value;
Oid valtype;
bool isnull = false; bool isnull = false;
value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); value = exec_eval_boolean(estate, stmt->cond, &isnull);
exec_eval_cleanup(estate); exec_eval_cleanup(estate);
if (!isnull && DatumGetBool(value)) if (!isnull && value)
{ {
if (stmt->true_body != NULL) if (stmt->true_body != NULL)
return exec_stmts(estate, stmt->true_body); return exec_stmts(estate, stmt->true_body);
@ -1183,16 +1185,16 @@ exec_stmt_loop(PLpgSQL_execstate * estate, PLpgSQL_stmt_loop * stmt)
static int static int
exec_stmt_while(PLpgSQL_execstate * estate, PLpgSQL_stmt_while * stmt) exec_stmt_while(PLpgSQL_execstate * estate, PLpgSQL_stmt_while * stmt)
{ {
Datum value; bool value;
Oid valtype;
bool isnull = false; bool isnull = false;
int rc; int rc;
for (;;) for (;;)
{ {
value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); value = exec_eval_boolean(estate, stmt->cond, &isnull);
exec_eval_cleanup(estate); exec_eval_cleanup(estate);
if (isnull || !DatumGetBool(value))
if (isnull || !value)
break; break;
rc = exec_stmts(estate, stmt->body); rc = exec_stmts(estate, stmt->body);
@ -1540,18 +1542,17 @@ exec_stmt_select(PLpgSQL_execstate * estate, PLpgSQL_stmt_select * stmt)
static int static int
exec_stmt_exit(PLpgSQL_execstate * estate, PLpgSQL_stmt_exit * stmt) 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 the exit has a condition, check that it's true
*/ */
if (stmt->cond != NULL) 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); exec_eval_cleanup(estate);
if (isnull || !DatumGetBool(value)) if (isnull || !value)
return PLPGSQL_RC_OK; return PLPGSQL_RC_OK;
} }
@ -1785,9 +1786,6 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
Oid paramtypeid; Oid paramtypeid;
Datum paramvalue; Datum paramvalue;
bool paramisnull; bool paramisnull;
HeapTuple typetup;
Form_pg_type typeStruct;
FmgrInfo finfo_output;
char *extval; char *extval;
int pidx = 0; int pidx = 0;
char c[2] = {0, 0}; char c[2] = {0, 0};
@ -1822,22 +1820,7 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
if (paramisnull) if (paramisnull)
extval = "<NULL>"; extval = "<NULL>";
else else
{ extval = convert_value_to_string(paramvalue, paramtypeid);
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);
}
plpgsql_dstring_append(&ds, extval); plpgsql_dstring_append(&ds, extval);
pidx++; pidx++;
continue; continue;
@ -2091,9 +2074,6 @@ exec_stmt_dynexecute(PLpgSQL_execstate * estate,
bool isnull = false; bool isnull = false;
Oid restype; Oid restype;
char *querystr; char *querystr;
HeapTuple typetup;
Form_pg_type typeStruct;
FmgrInfo finfo_output;
int exec_res; int exec_res;
/* /*
@ -2106,23 +2086,9 @@ exec_stmt_dynexecute(PLpgSQL_execstate * estate,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("cannot EXECUTE a null querystring"))); errmsg("cannot EXECUTE a null querystring")));
/* /* Get the C-String representation */
* Get the C-String representation. querystr = convert_value_to_string(query, restype);
*/
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);
fmgr_info(typeStruct->typoutput, &finfo_output);
querystr = DatumGetCString(FunctionCall3(&finfo_output,
query,
ObjectIdGetDatum(typeStruct->typelem),
Int32GetDatum(-1)));
ReleaseSysCache(typetup);
exec_eval_cleanup(estate); exec_eval_cleanup(estate);
/* /*
@ -2211,9 +2177,6 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
int rc = PLPGSQL_RC_OK; int rc = PLPGSQL_RC_OK;
int i; int i;
int n; int n;
HeapTuple typetup;
Form_pg_type typeStruct;
FmgrInfo finfo_output;
void *plan; void *plan;
Portal portal; Portal portal;
bool found = false; bool found = false;
@ -2238,23 +2201,9 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("cannot EXECUTE a null querystring"))); errmsg("cannot EXECUTE a null querystring")));
/* /* Get the C-String representation */
* Get the C-String representation. querystr = convert_value_to_string(query, restype);
*/
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);
fmgr_info(typeStruct->typoutput, &finfo_output);
querystr = DatumGetCString(FunctionCall3(&finfo_output,
query,
ObjectIdGetDatum(typeStruct->typelem),
Int32GetDatum(-1)));
ReleaseSysCache(typetup);
exec_eval_cleanup(estate); exec_eval_cleanup(estate);
/* /*
@ -2428,9 +2377,6 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
Datum queryD; Datum queryD;
Oid restype; Oid restype;
char *querystr; char *querystr;
HeapTuple typetup;
Form_pg_type typeStruct;
FmgrInfo finfo_output;
void *curplan; void *curplan;
/* ---------- /* ----------
@ -2445,24 +2391,9 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("cannot EXECUTE a null querystring"))); errmsg("cannot EXECUTE a null querystring")));
/* ---------- /* Get the C-String representation */
* Get the C-String representation. querystr = convert_value_to_string(queryD, restype);
* ----------
*/
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);
fmgr_info(typeStruct->typoutput, &finfo_output);
querystr = DatumGetCString(FunctionCall3(&finfo_output,
queryD,
ObjectIdGetDatum(typeStruct->typelem),
Int32GetDatum(-1)));
ReleaseSysCache(typetup);
exec_eval_cleanup(estate); exec_eval_cleanup(estate);
/* ---------- /* ----------
@ -3131,6 +3062,28 @@ exec_eval_integer(PLpgSQL_execstate * estate,
return DatumGetInt32(exprdatum); 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 * exec_eval_expr Evaluate an expression and return
* the result Datum. * the result Datum.
@ -3560,6 +3513,31 @@ make_tuple_from_row(PLpgSQL_execstate * estate,
return tuple; 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 * exec_cast_value Cast a value if required
* ---------- * ----------
@ -3580,29 +3558,14 @@ exec_cast_value(Datum value, Oid valtype,
*/ */
if (valtype != reqtype || reqtypmod != -1) if (valtype != reqtype || reqtypmod != -1)
{ {
HeapTuple typetup;
Form_pg_type typeStruct;
FmgrInfo finfo_output;
char *extval; char *extval;
typetup = SearchSysCache(TYPEOID, extval = convert_value_to_string(value, valtype);
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)));
value = FunctionCall3(reqinput, value = FunctionCall3(reqinput,
CStringGetDatum(extval), CStringGetDatum(extval),
ObjectIdGetDatum(reqtypelem), ObjectIdGetDatum(reqtypelem),
Int32GetDatum(reqtypmod)); Int32GetDatum(reqtypmod));
pfree(extval); pfree(extval);
ReleaseSysCache(typetup);
} }
} }
@ -3631,6 +3594,7 @@ exec_simple_cast_value(Datum value, Oid valtype,
FmgrInfo finfo_input; FmgrInfo finfo_input;
getTypeInputInfo(reqtype, &typInput, &typElem); getTypeInputInfo(reqtype, &typInput, &typElem);
fmgr_info(typInput, &finfo_input); fmgr_info(typInput, &finfo_input);
value = exec_cast_value(value, value = exec_cast_value(value,