Add code to check that IF/WHILE/EXIT test expressions are boolean,
authorTom Lane
Wed, 1 Oct 2003 21:47:42 +0000 (21:47 +0000)
committerTom Lane
Wed, 1 Oct 2003 21:47:42 +0000 (21:47 +0000)
and try to coerce the values to boolean if not.  Per recent discussions.

src/pl/plpgsql/src/pl_exec.c

index 824d638c7e724761ab2e8efc3c8720bf21c4bf3b..a69af302306155610d536883dc1fffc31796c745 100644 (file)
@@ -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 = "";
            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);
-
-   fmgr_info(typeStruct->typoutput, &finfo_output);
-   querystr = DatumGetCString(FunctionCall3(&finfo_output,
-                                            query,
-                                  ObjectIdGetDatum(typeStruct->typelem),
-                                            Int32GetDatum(-1)));
+   /* Get the C-String representation */
+   querystr = convert_value_to_string(query, restype);
 
-   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);
-
-       fmgr_info(typeStruct->typoutput, &finfo_output);
-       querystr = DatumGetCString(FunctionCall3(&finfo_output,
-                                                queryD,
-                                  ObjectIdGetDatum(typeStruct->typelem),
-                                                Int32GetDatum(-1)));
-
-       ReleaseSysCache(typetup);
+       /* Get the C-String representation */
+       querystr = convert_value_to_string(queryD, restype);
+
        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,