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
|
* 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,
|
||||||
|
Loading…
Reference in New Issue
Block a user