Be more consistent about reporting SPI errors in the various PLs.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 31 Jul 2004 20:55:45 +0000 (20:55 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 31 Jul 2004 20:55:45 +0000 (20:55 +0000)
Create a shared function to convert a SPI error code into a string
(replacing near-duplicate code in several PLs), and use it anywhere
that a SPI function call error is reported.

src/backend/executor/spi.c
src/include/executor/spi.h
src/pl/plperl/spi_internal.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_handler.c
src/pl/plpython/plpython.c
src/pl/tcl/pltcl.c

index f2fa0a43163ab5c12fd7b0bd693fa23fe741c575..7840f5f787afc86854c829bf87f414da83455f73 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.121 2004/07/27 05:10:51 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.122 2004/07/31 20:55:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -989,6 +989,68 @@ SPI_is_cursor_plan(void *plan)
    return false;
 }
 
+/*
+ * SPI_result_code_string --- convert any SPI return code to a string
+ *
+ * This is often useful in error messages.  Most callers will probably
+ * only pass negative (error-case) codes, but for generality we recognize
+ * the success codes too.
+ */
+const char *
+SPI_result_code_string(int code)
+{
+   static char buf[64];
+
+   switch (code)
+   {
+       case SPI_ERROR_CONNECT:
+           return "SPI_ERROR_CONNECT";
+       case SPI_ERROR_COPY:
+           return "SPI_ERROR_COPY";
+       case SPI_ERROR_OPUNKNOWN:
+           return "SPI_ERROR_OPUNKNOWN";
+       case SPI_ERROR_UNCONNECTED:
+           return "SPI_ERROR_UNCONNECTED";
+       case SPI_ERROR_CURSOR:
+           return "SPI_ERROR_CURSOR";
+       case SPI_ERROR_ARGUMENT:
+           return "SPI_ERROR_ARGUMENT";
+       case SPI_ERROR_PARAM:
+           return "SPI_ERROR_PARAM";
+       case SPI_ERROR_TRANSACTION:
+           return "SPI_ERROR_TRANSACTION";
+       case SPI_ERROR_NOATTRIBUTE:
+           return "SPI_ERROR_NOATTRIBUTE";
+       case SPI_ERROR_NOOUTFUNC:
+           return "SPI_ERROR_NOOUTFUNC";
+       case SPI_ERROR_TYPUNKNOWN:
+           return "SPI_ERROR_TYPUNKNOWN";
+       case SPI_OK_CONNECT:
+           return "SPI_OK_CONNECT";
+       case SPI_OK_FINISH:
+           return "SPI_OK_FINISH";
+       case SPI_OK_FETCH:
+           return "SPI_OK_FETCH";
+       case SPI_OK_UTILITY:
+           return "SPI_OK_UTILITY";
+       case SPI_OK_SELECT:
+           return "SPI_OK_SELECT";
+       case SPI_OK_SELINTO:
+           return "SPI_OK_SELINTO";
+       case SPI_OK_INSERT:
+           return "SPI_OK_INSERT";
+       case SPI_OK_DELETE:
+           return "SPI_OK_DELETE";
+       case SPI_OK_UPDATE:
+           return "SPI_OK_UPDATE";
+       case SPI_OK_CURSOR:
+           return "SPI_OK_CURSOR";
+   }
+   /* Unrecognized code ... return something useful ... */
+   sprintf(buf, "Unrecognized SPI code %d", code);
+   return buf;
+}
+
 /* =================== private functions =================== */
 
 /*
index e283b55cecd194a812905c48945058351edaa59f..a946efa64acf609e3e365dcd1d14a0e93066f5e5 100644 (file)
@@ -2,7 +2,7 @@
  *
  * spi.h
  *
- * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.45 2004/07/01 00:51:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.46 2004/07/31 20:55:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -93,6 +93,7 @@ extern int    SPI_freeplan(void *plan);
 extern Oid SPI_getargtypeid(void *plan, int argIndex);
 extern int SPI_getargcount(void *plan);
 extern bool SPI_is_cursor_plan(void *plan);
+extern const char *SPI_result_code_string(int code);
 
 extern HeapTuple SPI_copytuple(HeapTuple tuple);
 extern HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc);
index 57d95a10f1c0d533b673be3dcd3ea052652f9ce1..8d17af5b542c5f26ae7a4123d1495ab487141079 100644 (file)
@@ -9,10 +9,9 @@
 
 #include "spi_internal.h"
 
-static char* plperl_spi_status_string(int);
-
 static HV* plperl_spi_execute_fetch_result(SPITupleTable*, int, int );
 
+
 int
 spi_DEBUG(void)
 {
@@ -93,93 +92,35 @@ plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
 static HV*
 plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed, int status)
 {
-
    HV *result;
-    AV *rows;
-   int i;
 
    result = newHV();
-   rows = newAV();
 
-   if (status == SPI_OK_UTILITY)
-   {
-       hv_store(result, "status", strlen("status"), newSVpv("SPI_OK_UTILITY",0), 0);
-       hv_store(result, "processed", strlen("processed"), newSViv(processed), 0);
-   }
-   else if (status != SPI_OK_SELECT)
-   {
-       hv_store(result, "status", strlen("status"), newSVpv((char*)plperl_spi_status_string(status),0), 0);
-       hv_store(result, "processed", strlen("processed"), newSViv(processed), 0);
-   }
-   else
+   hv_store(result, "status", strlen("status"),
+            newSVpv((char*)SPI_result_code_string(status),0), 0);
+   hv_store(result, "processed", strlen("processed"),
+            newSViv(processed), 0);
+
+   if (status == SPI_OK_SELECT)
    {
-       hv_store(result, "status", strlen("status"), newSVpv((char*)plperl_spi_status_string(status),0), 0);
-       hv_store(result, "processed", strlen("processed"), newSViv(processed), 0);
        if (processed)
        {
+           AV *rows;
            HV *row;
+           int i;
+
+           rows = newAV();
            for (i = 0; i < processed; i++)
            {
                row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
-                av_store(rows, i, newRV_noinc((SV*)row));
+               av_store(rows, i, newRV_noinc((SV*)row));
            }
-           hv_store(result, "rows", strlen("rows"), newRV_noinc((SV*)rows), 0);
-           SPI_freetuptable(tuptable);
+           hv_store(result, "rows", strlen("rows"),
+                    newRV_noinc((SV*)rows), 0);
        }
    }
-   return result;
-}
 
-static char*
-plperl_spi_status_string(int status)
-{
-   switch(status){
-       /*errors*/
-       case SPI_ERROR_TYPUNKNOWN:
-           return "SPI_ERROR_TYPUNKNOWN";
-       case SPI_ERROR_NOOUTFUNC:
-           return "SPI_ERROR_NOOUTFUNC";
-       case SPI_ERROR_NOATTRIBUTE:
-           return "SPI_ERROR_NOATTRIBUTE";
-       case SPI_ERROR_TRANSACTION:
-           return "SPI_ERROR_TRANSACTION";
-       case SPI_ERROR_PARAM:
-           return "SPI_ERROR_PARAM";
-       case SPI_ERROR_ARGUMENT:
-           return "SPI_ERROR_ARGUMENT";
-       case SPI_ERROR_CURSOR:
-           return "SPI_ERROR_CURSOR";
-       case SPI_ERROR_UNCONNECTED:
-           return "SPI_ERROR_UNCONNECTED";
-       case SPI_ERROR_OPUNKNOWN:
-           return "SPI_ERROR_OPUNKNOWN";
-       case SPI_ERROR_COPY:
-           return "SPI_ERROR_COPY";
-       case SPI_ERROR_CONNECT:
-           return "SPI_ERROR_CONNECT";
-       /*ok*/
-       case SPI_OK_CONNECT:
-           return "SPI_OK_CONNECT";
-       case SPI_OK_FINISH:
-           return "SPI_OK_FINISH";
-       case SPI_OK_FETCH:
-           return "SPI_OK_FETCH";
-       case SPI_OK_UTILITY:
-           return "SPI_OK_UTILITY";
-       case SPI_OK_SELECT:
-           return "SPI_OK_SELECT";
-       case SPI_OK_SELINTO:
-           return "SPI_OK_SELINTO";
-       case SPI_OK_INSERT:
-           return "SPI_OK_INSERT";
-       case SPI_OK_DELETE:
-           return "SPI_OK_DELETE";
-       case SPI_OK_UPDATE:
-           return "SPI_OK_UPDATE";
-       case SPI_OK_CURSOR:
-           return "SPI_OK_CURSOR";
-   }
+   SPI_freetuptable(tuptable);
 
-   return "Unknown or Invalid code";
+   return result;
 }
-
index d8befe4d529cc5ea16eca827631eb2a08c3e7173..0950149a494763ef6d025b433a897b0f12872153 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.109 2004/07/31 07:39:20 tgl Exp $
+ *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.110 2004/07/31 20:55:44 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -904,6 +904,7 @@ exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block)
         */
        MemoryContext   oldcontext = CurrentMemoryContext;
        volatile bool   caught = false;
+       int     xrc;
 
        /*
         * Start a subtransaction, and re-connect to SPI within it
@@ -912,8 +913,9 @@ exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block)
        BeginInternalSubTransaction(NULL);
        /* Want to run statements inside function's memory context */
        MemoryContextSwitchTo(oldcontext);
-       if (SPI_connect() != SPI_OK_CONNECT)
-           elog(ERROR, "SPI_connect failed");
+       if ((xrc = SPI_connect()) != SPI_OK_CONNECT)
+           elog(ERROR, "SPI_connect failed: %s",
+                SPI_result_code_string(xrc));
 
        PG_TRY();
        {
@@ -961,8 +963,9 @@ exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block)
        /* Commit the inner transaction, return to outer xact context */
        if (!caught)
        {
-           if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish failed");
+           if ((xrc = SPI_finish()) != SPI_OK_FINISH)
+               elog(ERROR, "SPI_finish failed: %s",
+                    SPI_result_code_string(xrc));
            ReleaseCurrentSubTransaction();
            MemoryContextSwitchTo(oldcontext);
            SPI_pop();
@@ -2069,7 +2072,8 @@ exec_prepare_plan(PLpgSQL_execstate * estate,
     */
    plan = SPI_prepare(expr->query, expr->nparams, argtypes);
    if (plan == NULL)
-       elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query);
+       elog(ERROR, "SPI_prepare failed for \"%s\": %s",
+            expr->query, SPI_result_code_string(SPI_result));
    expr->plan = SPI_saveplan(plan);
    spi_plan = (_SPI_plan *) expr->plan;
    expr->plan_argtypes = spi_plan->argtypes;
@@ -2151,7 +2155,8 @@ exec_stmt_execsql(PLpgSQL_execstate * estate,
                     errhint("If you want to discard the results, use PERFORM instead.")));
 
        default:
-           elog(ERROR, "error executing query \"%s\"", expr->query);
+           elog(ERROR, "SPI_execp failed executing query \"%s\": %s",
+                expr->query, SPI_result_code_string(rc));
    }
 
    /*
@@ -2250,8 +2255,8 @@ exec_stmt_dynexecute(PLpgSQL_execstate * estate,
            }
 
        default:
-           elog(ERROR, "unexpected error %d in EXECUTE of query \"%s\"",
-                exec_res, querystr);
+           elog(ERROR, "SPI_exec failed executing query \"%s\": %s",
+                querystr, SPI_result_code_string(exec_res));
            break;
    }
 
@@ -2321,11 +2326,12 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
     */
    plan = SPI_prepare(querystr, 0, NULL);
    if (plan == NULL)
-       elog(ERROR, "SPI_prepare() failed for dynamic query \"%s\"", querystr);
+       elog(ERROR, "SPI_prepare failed for \"%s\": %s",
+            querystr, SPI_result_code_string(SPI_result));
    portal = SPI_cursor_open(NULL, plan, NULL, NULL);
    if (portal == NULL)
-       elog(ERROR, "failed to open implicit cursor for dynamic query \"%s\"",
-            querystr);
+       elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
+            querystr, SPI_result_code_string(SPI_result));
    pfree(querystr);
    SPI_freeplan(plan);
 
@@ -2512,11 +2518,12 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
         */
        curplan = SPI_prepare(querystr, 0, NULL);
        if (curplan == NULL)
-           elog(ERROR, "SPI_prepare() failed for dynamic query \"%s\"",
-                querystr);
+           elog(ERROR, "SPI_prepare failed for \"%s\": %s",
+                querystr, SPI_result_code_string(SPI_result));
        portal = SPI_cursor_open(curname, curplan, NULL, NULL);
        if (portal == NULL)
-           elog(ERROR, "failed to open cursor");
+           elog(ERROR, "could not open cursor for query \"%s\": %s",
+                querystr, SPI_result_code_string(SPI_result));
        pfree(querystr);
        SPI_freeplan(curplan);
 
@@ -2609,7 +2616,8 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
     */
    portal = SPI_cursor_open(curname, query->plan, values, nulls);
    if (portal == NULL)
-       elog(ERROR, "failed to open cursor");
+       elog(ERROR, "could not open cursor: %s",
+            SPI_result_code_string(SPI_result));
 
    pfree(values);
    pfree(nulls);
@@ -3454,8 +3462,8 @@ exec_run_select(PLpgSQL_execstate * estate,
    {
        *portalP = SPI_cursor_open(NULL, expr->plan, values, nulls);
        if (*portalP == NULL)
-           elog(ERROR, "failed to open implicit cursor for \"%s\"",
-                expr->query);
+           elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
+                expr->query, SPI_result_code_string(SPI_result));
        pfree(values);
        pfree(nulls);
        return SPI_OK_CURSOR;
index f7f08bedd031eacd3baca63838b882609e0fe1ec..5f6a83c11d6c2867490cfb91faa45c66ec27d89e 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.21 2004/03/22 03:15:33 momjian Exp $
+ *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.22 2004/07/31 20:55:44 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -102,6 +102,7 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
 {
    PLpgSQL_function *func;
    Datum       retval;
+   int         rc;
 
    /* perform initialization */
    plpgsql_init_all();
@@ -109,8 +110,8 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
    /*
     * Connect to SPI manager
     */
-   if (SPI_connect() != SPI_OK_CONNECT)
-       elog(ERROR, "SPI_connect failed");
+   if ((rc = SPI_connect()) != SPI_OK_CONNECT)
+       elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
 
    /* Find or compile the function */
    func = plpgsql_compile(fcinfo, false);
@@ -128,8 +129,8 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
    /*
     * Disconnect from SPI manager
     */
-   if (SPI_finish() != SPI_OK_FINISH)
-       elog(ERROR, "SPI_finish failed");
+   if ((rc = SPI_finish()) != SPI_OK_FINISH)
+       elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
 
    return retval;
 }
@@ -211,12 +212,13 @@ plpgsql_validator(PG_FUNCTION_ARGS)
        FunctionCallInfoData fake_fcinfo;
        FmgrInfo    flinfo;
        TriggerData trigdata;
+       int         rc;
 
        /*
         * Connect to SPI manager (is this needed for compilation?)
         */
-       if (SPI_connect() != SPI_OK_CONNECT)
-           elog(ERROR, "SPI_connect failed");
+       if ((rc = SPI_connect()) != SPI_OK_CONNECT)
+           elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
 
        /*
         * Set up a fake fcinfo with just enough info to satisfy
@@ -240,8 +242,8 @@ plpgsql_validator(PG_FUNCTION_ARGS)
        /*
         * Disconnect from SPI manager
         */
-       if (SPI_finish() != SPI_OK_FINISH)
-           elog(ERROR, "SPI_finish failed");
+       if ((rc = SPI_finish()) != SPI_OK_FINISH)
+           elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
    }
 
    ReleaseSysCache(tuple);
index db938c3395a9d9d665dd3588ca30735fddc30cbc..4d8a0aa87add1b733a8765f68f68410cebc87189 100644 (file)
@@ -29,7 +29,7 @@
  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.50 2004/07/31 00:45:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.51 2004/07/31 20:55:45 tgl Exp $
  *
  *********************************************************************
  */
@@ -1522,7 +1522,6 @@ static int    PLy_result_ass_slice(PyObject *, int, int, PyObject *);
 
 static PyObject *PLy_spi_prepare(PyObject *, PyObject *);
 static PyObject *PLy_spi_execute(PyObject *, PyObject *);
-static const char *PLy_spi_error_string(int);
 static PyObject *PLy_spi_execute_query(char *query, int limit);
 static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, int);
 static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int);
@@ -1911,16 +1910,16 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
 
    plan->plan = SPI_prepare(query, plan->nargs, plan->types);
    if (plan->plan == NULL)
-       elog(ERROR, "Unable to prepare plan. SPI_prepare failed -- %s.",
-            PLy_spi_error_string(SPI_result));
+       elog(ERROR, "SPI_prepare failed: %s",
+            SPI_result_code_string(SPI_result));
 
    /* transfer plan from procCxt to topCxt */
    tmpplan = plan->plan;
    plan->plan = SPI_saveplan(tmpplan);
    SPI_freeplan(tmpplan);
    if (plan->plan == NULL)
-       elog(ERROR, "Unable to save plan. SPI_saveplan failed -- %s.",
-            PLy_spi_error_string(SPI_result));
+       elog(ERROR, "SPI_saveplan failed: %s",
+            SPI_result_code_string(SPI_result));
    }
    PG_CATCH();
    {
@@ -2095,8 +2094,8 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit)
    if (rv < 0)
    {
        PLy_exception_set(PLy_exc_spi_error,
-                      "Unable to execute plan.  SPI_execp failed -- %s",
-                         PLy_spi_error_string(rv));
+                         "SPI_execp failed: %s",
+                         SPI_result_code_string(rv));
        return NULL;
    }
 
@@ -2130,8 +2129,8 @@ PLy_spi_execute_query(char *query, int limit)
    if (rv < 0)
    {
        PLy_exception_set(PLy_exc_spi_error,
-                      "Unable to execute query.  SPI_exec failed -- %s",
-                         PLy_spi_error_string(rv));
+                         "SPI_exec failed: %s",
+                         SPI_result_code_string(rv));
        return NULL;
    }
 
@@ -2206,38 +2205,9 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
    return (PyObject *) result;
 }
 
-static const char *
-PLy_spi_error_string(int code)
-{
-   switch (code)
-   {
-       case SPI_ERROR_TYPUNKNOWN:
-           return "SPI_ERROR_TYPUNKNOWN";
-       case SPI_ERROR_NOOUTFUNC:
-           return "SPI_ERROR_NOOUTFUNC";
-       case SPI_ERROR_NOATTRIBUTE:
-           return "SPI_ERROR_NOATTRIBUTE";
-       case SPI_ERROR_TRANSACTION:
-           return "SPI_ERROR_TRANSACTION";
-       case SPI_ERROR_PARAM:
-           return "SPI_ERROR_PARAM";
-       case SPI_ERROR_ARGUMENT:
-           return "SPI_ERROR_ARGUMENT";
-       case SPI_ERROR_CURSOR:
-           return "SPI_ERROR_CURSOR";
-       case SPI_ERROR_UNCONNECTED:
-           return "SPI_ERROR_UNCONNECTED";
-       case SPI_ERROR_OPUNKNOWN:
-           return "SPI_ERROR_OPUNKNOWN";
-       case SPI_ERROR_COPY:
-           return "SPI_ERROR_COPY";
-       case SPI_ERROR_CONNECT:
-           return "SPI_ERROR_CONNECT";
-   }
-   return "Unknown or Invalid code";
-}
-
-/* language handler and interpreter initialization
+
+/*
+ * language handler and interpreter initialization
  */
 
 /*
index 05c906f30f2b72cfccfd3237f021aad073cfe4d1..134291be4e95d876636b011ca481a78be7b90155 100644 (file)
@@ -31,7 +31,7 @@
  *   ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.87 2004/07/31 00:45:57 tgl Exp $
+ *   $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.88 2004/07/31 20:55:45 tgl Exp $
  *
  **********************************************************************/
 
@@ -1602,46 +1602,10 @@ pltcl_SPI_exec(ClientData cdata, Tcl_Interp *interp,
        case SPI_OK_SELECT:
            break;
 
-       case SPI_ERROR_ARGUMENT:
-           Tcl_SetResult(interp,
-                         "pltcl: SPI_exec() failed - SPI_ERROR_ARGUMENT",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_UNCONNECTED:
-           Tcl_SetResult(interp,
-                     "pltcl: SPI_exec() failed - SPI_ERROR_UNCONNECTED",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_COPY:
-           Tcl_SetResult(interp,
-                         "pltcl: SPI_exec() failed - SPI_ERROR_COPY",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_CURSOR:
-           Tcl_SetResult(interp,
-                         "pltcl: SPI_exec() failed - SPI_ERROR_CURSOR",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_TRANSACTION:
-           Tcl_SetResult(interp,
-                     "pltcl: SPI_exec() failed - SPI_ERROR_TRANSACTION",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_OPUNKNOWN:
-           Tcl_SetResult(interp,
-                       "pltcl: SPI_exec() failed - SPI_ERROR_OPUNKNOWN",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
        default:
-           snprintf(buf, sizeof(buf), "%d", spi_rc);
-           Tcl_AppendResult(interp, "pltcl: SPI_exec() failed - ",
-                            "unknown RC ", buf, NULL);
+           Tcl_AppendResult(interp, "pltcl: SPI_exec failed: ",
+                            SPI_result_code_string(spi_rc), NULL);
+           SPI_freetuptable(SPI_tuptable);
            return TCL_ERROR;
    }
 
@@ -2117,46 +2081,10 @@ pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
        case SPI_OK_SELECT:
            break;
 
-       case SPI_ERROR_ARGUMENT:
-           Tcl_SetResult(interp,
-                         "pltcl: SPI_exec() failed - SPI_ERROR_ARGUMENT",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_UNCONNECTED:
-           Tcl_SetResult(interp,
-                     "pltcl: SPI_exec() failed - SPI_ERROR_UNCONNECTED",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_COPY:
-           Tcl_SetResult(interp,
-                         "pltcl: SPI_exec() failed - SPI_ERROR_COPY",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_CURSOR:
-           Tcl_SetResult(interp,
-                         "pltcl: SPI_exec() failed - SPI_ERROR_CURSOR",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_TRANSACTION:
-           Tcl_SetResult(interp,
-                     "pltcl: SPI_exec() failed - SPI_ERROR_TRANSACTION",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
-       case SPI_ERROR_OPUNKNOWN:
-           Tcl_SetResult(interp,
-                       "pltcl: SPI_exec() failed - SPI_ERROR_OPUNKNOWN",
-                         TCL_VOLATILE);
-           return TCL_ERROR;
-
        default:
-           snprintf(buf, sizeof(buf), "%d", spi_rc);
-           Tcl_AppendResult(interp, "pltcl: SPI_exec() failed - ",
-                            "unknown RC ", buf, NULL);
+           Tcl_AppendResult(interp, "pltcl: SPI_execp failed: ",
+                            SPI_result_code_string(spi_rc), NULL);
+           SPI_freetuptable(SPI_tuptable);
            return TCL_ERROR;
    }