summaryrefslogtreecommitdiff
path: root/src/pl
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl')
-rw-r--r--src/pl/plpgsql/src/nls.mk4
-rw-r--r--src/pl/plpgsql/src/pl_exec.c101
2 files changed, 48 insertions, 57 deletions
diff --git a/src/pl/plpgsql/src/nls.mk b/src/pl/plpgsql/src/nls.mk
index 0dd837137a..a9151740bd 100644
--- a/src/pl/plpgsql/src/nls.mk
+++ b/src/pl/plpgsql/src/nls.mk
@@ -1,8 +1,8 @@
-# $PostgreSQL: pgsql/src/pl/plpgsql/src/nls.mk,v 1.9 2009/06/26 19:33:52 petere Exp $
+# $PostgreSQL: pgsql/src/pl/plpgsql/src/nls.mk,v 1.10 2009/08/06 20:44:31 tgl Exp $
CATALOG_NAME := plpgsql
AVAIL_LANGUAGES := de es fr ja ro
GETTEXT_FILES := pl_comp.c pl_exec.c pl_gram.c pl_funcs.c pl_handler.c pl_scan.c
-GETTEXT_TRIGGERS:= _ errmsg errmsg_plural:1,2 errdetail errdetail_log errdetail_plural:1,2 errhint errcontext validate_tupdesc_compat:3 yyerror plpgsql_yyerror
+GETTEXT_TRIGGERS:= _ errmsg errmsg_plural:1,2 errdetail errdetail_log errdetail_plural:1,2 errhint errcontext yyerror plpgsql_yyerror
.PHONY: gettext-files
gettext-files: distprep
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index d5ebe116db..a3a39e8e2d 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.247 2009/08/04 21:22:46 alvherre Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.248 2009/08/06 20:44:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
#include <ctype.h>
#include "access/transam.h"
+#include "access/tupconvert.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/spi_priv.h"
@@ -191,8 +192,6 @@ static Datum exec_simple_cast_value(Datum value, Oid valtype,
Oid reqtype, int32 reqtypmod,
bool isnull);
static void exec_init_tuple_store(PLpgSQL_execstate *estate);
-static void validate_tupdesc_compat(TupleDesc expected, TupleDesc returned,
- const char *msg);
static void exec_set_found(PLpgSQL_execstate *estate, bool state);
static void plpgsql_create_econtext(PLpgSQL_execstate *estate);
static void plpgsql_destroy_econtext(PLpgSQL_execstate *estate);
@@ -383,14 +382,21 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
* expected result type. XXX would be better to cache the tupdesc
* instead of repeating get_call_result_type()
*/
+ HeapTuple rettup = (HeapTuple) DatumGetPointer(estate.retval);
TupleDesc tupdesc;
+ TupleConversionMap *tupmap;
switch (get_call_result_type(fcinfo, NULL, &tupdesc))
{
case TYPEFUNC_COMPOSITE:
/* got the expected result rowtype, now check it */
- validate_tupdesc_compat(tupdesc, estate.rettupdesc,
- "returned record type does not match expected record type");
+ tupmap = convert_tuples_by_position(estate.rettupdesc,
+ tupdesc,
+ gettext_noop("returned record type does not match expected record type"));
+ /* it might need conversion */
+ if (tupmap)
+ rettup = do_convert_tuple(rettup, tupmap);
+ /* no need to free map, we're about to return anyway */
break;
case TYPEFUNC_RECORD:
@@ -415,9 +421,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
* Copy tuple to upper executor memory, as a tuple Datum. Make
* sure it is labeled with the caller-supplied tuple type.
*/
- estate.retval =
- PointerGetDatum(SPI_returntuple((HeapTuple) DatumGetPointer(estate.retval),
- tupdesc));
+ estate.retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
}
else
{
@@ -706,11 +710,20 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
rettup = NULL;
else
{
- validate_tupdesc_compat(trigdata->tg_relation->rd_att,
- estate.rettupdesc,
- "returned row structure does not match the structure of the triggering table");
+ TupleConversionMap *tupmap;
+
+ rettup = (HeapTuple) DatumGetPointer(estate.retval);
+ /* check rowtype compatibility */
+ tupmap = convert_tuples_by_position(estate.rettupdesc,
+ trigdata->tg_relation->rd_att,
+ gettext_noop("returned row structure does not match the structure of the triggering table"));
+ /* it might need conversion */
+ if (tupmap)
+ rettup = do_convert_tuple(rettup, tupmap);
+ /* no need to free map, we're about to return anyway */
+
/* Copy tuple to upper executor memory */
- rettup = SPI_copytuple((HeapTuple) DatumGetPointer(estate.retval));
+ rettup = SPI_copytuple(rettup);
}
/*
@@ -2192,6 +2205,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
case PLPGSQL_DTYPE_REC:
{
PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
+ TupleConversionMap *tupmap;
if (!HeapTupleIsValid(rec->tup))
ereport(ERROR,
@@ -2200,9 +2214,16 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
rec->refname),
errdetail("The tuple structure of a not-yet-assigned"
" record is indeterminate.")));
- validate_tupdesc_compat(tupdesc, rec->tupdesc,
- "wrong record type supplied in RETURN NEXT");
+ tupmap = convert_tuples_by_position(rec->tupdesc,
+ tupdesc,
+ gettext_noop("wrong record type supplied in RETURN NEXT"));
tuple = rec->tup;
+ /* it might need conversion */
+ if (tupmap)
+ {
+ tuple = do_convert_tuple(tuple, tupmap);
+ free_conversion_map(tupmap);
+ }
}
break;
@@ -2286,6 +2307,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
{
Portal portal;
uint32 processed = 0;
+ TupleConversionMap *tupmap;
if (!estate->retisset)
ereport(ERROR,
@@ -2308,8 +2330,9 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
stmt->params);
}
- validate_tupdesc_compat(estate->rettupdesc, portal->tupDesc,
- "structure of query does not match function result type");
+ tupmap = convert_tuples_by_position(portal->tupDesc,
+ estate->rettupdesc,
+ gettext_noop("structure of query does not match function result type"));
while (true)
{
@@ -2325,7 +2348,11 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
{
HeapTuple tuple = SPI_tuptable->vals[i];
+ if (tupmap)
+ tuple = do_convert_tuple(tuple, tupmap);
tuplestore_puttuple(estate->tuple_store, tuple);
+ if (tupmap)
+ heap_freetuple(tuple);
processed++;
}
MemoryContextSwitchTo(old_cxt);
@@ -2333,6 +2360,9 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
SPI_freetuptable(SPI_tuptable);
}
+ if (tupmap)
+ free_conversion_map(tupmap);
+
SPI_freetuptable(SPI_tuptable);
SPI_cursor_close(portal);
@@ -5121,45 +5151,6 @@ exec_simple_check_plan(PLpgSQL_expr *expr)
expr->expr_simple_type = exprType((Node *) tle->expr);
}
-/*
- * Validates compatibility of supplied TupleDesc pair by checking number and type
- * of attributes.
- */
-static void
-validate_tupdesc_compat(TupleDesc expected, TupleDesc returned, const char *msg)
-{
- int i;
- const char *dropped_column_type = gettext_noop("N/A (dropped column)");
-
- if (!expected || !returned)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("%s", _(msg))));
-
- if (expected->natts != returned->natts)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("%s", _(msg)),
- errdetail("Number of returned columns (%d) does not match "
- "expected column count (%d).",
- returned->natts, expected->natts)));
-
- 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))));
-}
-
/* ----------
* exec_set_found Set the global found variable
* to true/false