Skip to content
Snippets Groups Projects
Commit 04b40923 authored by Tom Lane's avatar Tom Lane
Browse files

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.
parent 55d85f42
No related branches found
No related tags found
No related merge requests found
...@@ -3,7 +3,7 @@ ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment