Commit c06629c7 authored by Alvaro Herrera's avatar Alvaro Herrera

Improve plpgsql's ability to report tuple incompatibility problems.

Volkan YAZICI
parent ead21631
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.219 2008/09/01 22:30:33 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.220 2008/09/09 15:14:08 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -188,7 +188,8 @@ static Datum exec_simple_cast_value(Datum value, Oid valtype, ...@@ -188,7 +188,8 @@ static Datum exec_simple_cast_value(Datum value, Oid valtype,
Oid reqtype, int32 reqtypmod, Oid reqtype, int32 reqtypmod,
bool isnull); bool isnull);
static void exec_init_tuple_store(PLpgSQL_execstate *estate); static void exec_init_tuple_store(PLpgSQL_execstate *estate);
static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2); static void validate_tupdesc_compat(TupleDesc expected, TupleDesc returned,
const char *msg);
static void exec_set_found(PLpgSQL_execstate *estate, bool state); static void exec_set_found(PLpgSQL_execstate *estate, bool state);
static void plpgsql_create_econtext(PLpgSQL_execstate *estate); static void plpgsql_create_econtext(PLpgSQL_execstate *estate);
static void free_var(PLpgSQL_var *var); static void free_var(PLpgSQL_var *var);
...@@ -384,11 +385,9 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo) ...@@ -384,11 +385,9 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
{ {
case TYPEFUNC_COMPOSITE: case TYPEFUNC_COMPOSITE:
/* got the expected result rowtype, now check it */ /* got the expected result rowtype, now check it */
if (estate.rettupdesc == NULL || validate_tupdesc_compat(tupdesc, estate.rettupdesc,
!compatible_tupdesc(estate.rettupdesc, tupdesc)) gettext_noop("returned record type does "
ereport(ERROR, "not match expected record type"));
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("returned record type does not match expected record type")));
break; break;
case TYPEFUNC_RECORD: case TYPEFUNC_RECORD:
...@@ -705,11 +704,10 @@ plpgsql_exec_trigger(PLpgSQL_function *func, ...@@ -705,11 +704,10 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
rettup = NULL; rettup = NULL;
else else
{ {
if (!compatible_tupdesc(estate.rettupdesc, validate_tupdesc_compat(trigdata->tg_relation->rd_att,
trigdata->tg_relation->rd_att)) estate.rettupdesc,
ereport(ERROR, gettext_noop("returned tuple structure does "
(errcode(ERRCODE_DATATYPE_MISMATCH), "not match table of trigger event"));
errmsg("returned tuple structure does not match table of trigger event")));
/* Copy tuple to upper executor memory */ /* Copy tuple to upper executor memory */
rettup = SPI_copytuple((HeapTuple) DatumGetPointer(estate.retval)); rettup = SPI_copytuple((HeapTuple) DatumGetPointer(estate.retval));
} }
...@@ -2199,11 +2197,11 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, ...@@ -2199,11 +2197,11 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("record \"%s\" is not assigned yet", errmsg("record \"%s\" is not assigned yet",
rec->refname), rec->refname),
errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); errdetail("The tuple structure of a not-yet-assigned"
if (!compatible_tupdesc(tupdesc, rec->tupdesc)) " record is indeterminate.")));
ereport(ERROR, validate_tupdesc_compat(tupdesc, rec->tupdesc,
(errcode(ERRCODE_DATATYPE_MISMATCH), gettext_noop("wrong record type supplied "
errmsg("wrong record type supplied in RETURN NEXT"))); "in RETURN NEXT"));
tuple = rec->tup; tuple = rec->tup;
} }
break; break;
...@@ -2309,10 +2307,9 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, ...@@ -2309,10 +2307,9 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
stmt->params); stmt->params);
} }
if (!compatible_tupdesc(estate->rettupdesc, portal->tupDesc)) validate_tupdesc_compat(estate->rettupdesc, portal->tupDesc,
ereport(ERROR, gettext_noop("structure of query does not match "
(errcode(ERRCODE_DATATYPE_MISMATCH), "function result type"));
errmsg("structure of query does not match function result type")));
while (true) while (true)
{ {
...@@ -5145,23 +5142,42 @@ exec_simple_check_plan(PLpgSQL_expr *expr) ...@@ -5145,23 +5142,42 @@ exec_simple_check_plan(PLpgSQL_expr *expr)
} }
/* /*
* Check two tupledescs have matching number and types of attributes * Validates compatibility of supplied TupleDesc pair by checking number and type
* of attributes.
*/ */
static bool static void
compatible_tupdesc(TupleDesc td1, TupleDesc td2) validate_tupdesc_compat(TupleDesc expected, TupleDesc returned, const char *msg)
{ {
int i; int i;
const char dropped_column_type[] = gettext_noop("n/a (dropped column)");
if (td1->natts != td2->natts) if (!expected || !returned)
return false; ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("%s", _(msg))));
for (i = 0; i < td1->natts; i++) if (expected->natts != returned->natts)
{ ereport(ERROR,
if (td1->attrs[i]->atttypid != td2->attrs[i]->atttypid) (errcode(ERRCODE_DATATYPE_MISMATCH),
return false; errmsg("%s", _(msg)),
} errdetail("Number of returned columns (%d) does not match "
"expected column count (%d).",
returned->natts, expected->natts)));
return true; for (i = 0; i < expected->natts; i++)
if (expected->attrs[i]->atttypid != returned->attrs[i]->atttypid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("%s", _(msg)),
errdetail("Returned type %s does not match expected type "
"%s in column %s.",
OidIsValid(returned->attrs[i]->atttypid) ?
format_type_be(returned->attrs[i]->atttypid) :
_(dropped_column_type),
OidIsValid(expected->attrs[i]->atttypid) ?
format_type_be(expected->attrs[i]->atttypid) :
_(dropped_column_type),
NameStr(expected->attrs[i]->attname))));
} }
/* ---------- /* ----------
......
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