Commit ffaaf27e authored by Neil Conway's avatar Neil Conway

Provide a more descriptive error message when the return type of an SRF

does not match what the query expected. From Brendan Jurd, minor
editorializing by Neil Conway.
parent f07b9689
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.29 2004/12/31 21:59:45 pgsql Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.30 2005/01/27 06:36:42 neilc Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,12 +31,13 @@ ...@@ -31,12 +31,13 @@
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/typcache.h" #include "utils/typcache.h"
static TupleTableSlot *FunctionNext(FunctionScanState *node); static TupleTableSlot *FunctionNext(FunctionScanState *node);
static bool tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc); static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* Scan Support * Scan Support
...@@ -87,10 +88,8 @@ FunctionNext(FunctionScanState *node) ...@@ -87,10 +88,8 @@ FunctionNext(FunctionScanState *node)
* need to do this for functions returning RECORD, but might as * need to do this for functions returning RECORD, but might as
* well do it always. * well do it always.
*/ */
if (funcTupdesc && !tupledesc_match(node->tupdesc, funcTupdesc)) if (funcTupdesc)
ereport(ERROR, tupledesc_match(node->tupdesc, funcTupdesc);
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("query-specified return row and actual function return row do not match")));
} }
/* /*
...@@ -349,21 +348,26 @@ ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt) ...@@ -349,21 +348,26 @@ ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
} }
/* /*
* Check that function result tuple type (src_tupdesc) matches or can be * Check that function result tuple type (src_tupdesc) matches or can
* considered to match what the query expects (dst_tupdesc). * be considered to match what the query expects (dst_tupdesc). If
* they don't match, ereport.
* *
* We really only care about number of attributes and data type. * We really only care about number of attributes and data type.
* Also, we can ignore type mismatch on columns that are dropped in the * Also, we can ignore type mismatch on columns that are dropped in the
* destination type, so long as the physical storage matches. This is * destination type, so long as the physical storage matches. This is
* helpful in some cases involving out-of-date cached plans. * helpful in some cases involving out-of-date cached plans.
*/ */
static bool static void
tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc) tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
{ {
int i; int i;
if (dst_tupdesc->natts != src_tupdesc->natts) if (dst_tupdesc->natts != src_tupdesc->natts)
return false; ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function return row and query-specified return row do not match"),
errdetail("Returned row contains %d attributes, but query expects %d.",
src_tupdesc->natts, dst_tupdesc->natts)));
for (i = 0; i < dst_tupdesc->natts; i++) for (i = 0; i < dst_tupdesc->natts; i++)
{ {
...@@ -373,11 +377,20 @@ tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc) ...@@ -373,11 +377,20 @@ tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
if (dattr->atttypid == sattr->atttypid) if (dattr->atttypid == sattr->atttypid)
continue; /* no worries */ continue; /* no worries */
if (!dattr->attisdropped) if (!dattr->attisdropped)
return false; ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function return row and query-specified return row do not match"),
errdetail("Returned type %s at ordinal position %d, but query expects %s.",
format_type_be(sattr->atttypid),
i + 1,
format_type_be(dattr->atttypid))));
if (dattr->attlen != sattr->attlen || if (dattr->attlen != sattr->attlen ||
dattr->attalign != sattr->attalign) dattr->attalign != sattr->attalign)
return false; ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function return row and query-specified return row do not match"),
errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
i + 1)));
} }
return true;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment