mirror of
https://github.com/postgres/postgres.git
synced 2025-06-08 22:02:03 +03:00
Improve plpgsql's ability to report tuple incompatibility problems.
Volkan YAZICI
This commit is contained in:
parent
ead21631e8
commit
c06629c72e
@ -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,
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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,
|
|||||||
(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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user