|
8 | 8 | * |
9 | 9 | * |
10 | 10 | * IDENTIFICATION |
11 | | - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.219 2008/09/01 22:30:33 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.220 2008/09/09 15:14:08 alvherre Exp $ |
12 | 12 | * |
13 | 13 | *------------------------------------------------------------------------- |
14 | 14 | */ |
@@ -188,7 +188,8 @@ static Datum exec_simple_cast_value(Datum value, Oid valtype, |
188 | 188 | Oidreqtype,int32reqtypmod, |
189 | 189 | boolisnull); |
190 | 190 | staticvoidexec_init_tuple_store(PLpgSQL_execstate*estate); |
191 | | -staticboolcompatible_tupdesc(TupleDesctd1,TupleDesctd2); |
| 191 | +staticvoidvalidate_tupdesc_compat(TupleDescexpected,TupleDescreturned, |
| 192 | +constchar*msg); |
192 | 193 | staticvoidexec_set_found(PLpgSQL_execstate*estate,boolstate); |
193 | 194 | staticvoidplpgsql_create_econtext(PLpgSQL_execstate*estate); |
194 | 195 | staticvoidfree_var(PLpgSQL_var*var); |
@@ -384,11 +385,9 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo) |
384 | 385 | { |
385 | 386 | caseTYPEFUNC_COMPOSITE: |
386 | 387 | /* got the expected result rowtype, now check it */ |
387 | | -if (estate.rettupdesc==NULL|| |
388 | | -!compatible_tupdesc(estate.rettupdesc,tupdesc)) |
389 | | -ereport(ERROR, |
390 | | -(errcode(ERRCODE_DATATYPE_MISMATCH), |
391 | | -errmsg("returned record type does not match expected record type"))); |
| 388 | +validate_tupdesc_compat(tupdesc,estate.rettupdesc, |
| 389 | +gettext_noop("returned record type does " |
| 390 | +"not match expected record type")); |
392 | 391 | break; |
393 | 392 | caseTYPEFUNC_RECORD: |
394 | 393 |
|
@@ -705,11 +704,10 @@ plpgsql_exec_trigger(PLpgSQL_function *func, |
705 | 704 | rettup=NULL; |
706 | 705 | else |
707 | 706 | { |
708 | | -if (!compatible_tupdesc(estate.rettupdesc, |
709 | | -trigdata->tg_relation->rd_att)) |
710 | | -ereport(ERROR, |
711 | | -(errcode(ERRCODE_DATATYPE_MISMATCH), |
712 | | -errmsg("returned tuple structure does not match table of trigger event"))); |
| 707 | +validate_tupdesc_compat(trigdata->tg_relation->rd_att, |
| 708 | +estate.rettupdesc, |
| 709 | +gettext_noop("returned tuple structure does " |
| 710 | +"not match table of trigger event")); |
713 | 711 | /* Copy tuple to upper executor memory */ |
714 | 712 | rettup=SPI_copytuple((HeapTuple)DatumGetPointer(estate.retval)); |
715 | 713 | } |
@@ -2199,11 +2197,11 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, |
2199 | 2197 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
2200 | 2198 | errmsg("record \"%s\" is not assigned yet", |
2201 | 2199 | rec->refname), |
2202 | | -errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); |
2203 | | -if (!compatible_tupdesc(tupdesc,rec->tupdesc)) |
2204 | | -ereport(ERROR, |
2205 | | -(errcode(ERRCODE_DATATYPE_MISMATCH), |
2206 | | -errmsg("wrong record type suppliedin RETURN NEXT"))); |
| 2200 | +errdetail("The tuple structure of a not-yet-assigned" |
| 2201 | +" record is indeterminate."))); |
| 2202 | +validate_tupdesc_compat(tupdesc,rec->tupdesc, |
| 2203 | +gettext_noop("wrong record type supplied " |
| 2204 | +"in RETURN NEXT")); |
2207 | 2205 | tuple=rec->tup; |
2208 | 2206 | } |
2209 | 2207 | break; |
@@ -2309,10 +2307,9 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, |
2309 | 2307 | stmt->params); |
2310 | 2308 | } |
2311 | 2309 |
|
2312 | | -if (!compatible_tupdesc(estate->rettupdesc,portal->tupDesc)) |
2313 | | -ereport(ERROR, |
2314 | | -(errcode(ERRCODE_DATATYPE_MISMATCH), |
2315 | | -errmsg("structure of query does not match function result type"))); |
| 2310 | +validate_tupdesc_compat(estate->rettupdesc,portal->tupDesc, |
| 2311 | +gettext_noop("structure of query does not match " |
| 2312 | +"function result type")); |
2316 | 2313 |
|
2317 | 2314 | while (true) |
2318 | 2315 | { |
@@ -5145,23 +5142,42 @@ exec_simple_check_plan(PLpgSQL_expr *expr) |
5145 | 5142 | } |
5146 | 5143 |
|
5147 | 5144 | /* |
5148 | | - * Check two tupledescs have matching number and types of attributes |
| 5145 | + * Validates compatibility of supplied TupleDesc pair by checking number and type |
| 5146 | + * of attributes. |
5149 | 5147 | */ |
5150 | | -staticbool |
5151 | | -compatible_tupdesc(TupleDesctd1,TupleDesctd2) |
| 5148 | +staticvoid |
| 5149 | +validate_tupdesc_compat(TupleDescexpected,TupleDescreturned,constchar*msg) |
5152 | 5150 | { |
5153 | | -inti; |
| 5151 | +inti; |
| 5152 | +constchardropped_column_type[]=gettext_noop("n/a (dropped column)"); |
5154 | 5153 |
|
5155 | | -if (td1->natts!=td2->natts) |
5156 | | -return false; |
| 5154 | +if (!expected|| !returned) |
| 5155 | +ereport(ERROR, |
| 5156 | +(errcode(ERRCODE_DATATYPE_MISMATCH), |
| 5157 | +errmsg("%s",_(msg)))); |
5157 | 5158 |
|
5158 | | -for (i=0;i<td1->natts;i++) |
5159 | | -{ |
5160 | | -if (td1->attrs[i]->atttypid!=td2->attrs[i]->atttypid) |
5161 | | -return false; |
5162 | | -} |
| 5159 | +if (expected->natts!=returned->natts) |
| 5160 | +ereport(ERROR, |
| 5161 | +(errcode(ERRCODE_DATATYPE_MISMATCH), |
| 5162 | +errmsg("%s",_(msg)), |
| 5163 | +errdetail("Number of returned columns (%d) does not match " |
| 5164 | +"expected column count (%d).", |
| 5165 | +returned->natts,expected->natts))); |
5163 | 5166 |
|
5164 | | -return true; |
| 5167 | +for (i=0;i<expected->natts;i++) |
| 5168 | +if (expected->attrs[i]->atttypid!=returned->attrs[i]->atttypid) |
| 5169 | +ereport(ERROR, |
| 5170 | +(errcode(ERRCODE_DATATYPE_MISMATCH), |
| 5171 | +errmsg("%s",_(msg)), |
| 5172 | +errdetail("Returned type %s does not match expected type " |
| 5173 | +"%s in column %s.", |
| 5174 | +OidIsValid(returned->attrs[i]->atttypid) ? |
| 5175 | +format_type_be(returned->attrs[i]->atttypid) : |
| 5176 | +_(dropped_column_type), |
| 5177 | +OidIsValid(expected->attrs[i]->atttypid) ? |
| 5178 | +format_type_be(expected->attrs[i]->atttypid) : |
| 5179 | +_(dropped_column_type), |
| 5180 | +NameStr(expected->attrs[i]->attname)))); |
5165 | 5181 | } |
5166 | 5182 |
|
5167 | 5183 | /* ---------- |
|