Commit 0f059e1d authored by Tom Lane's avatar Tom Lane

Allow plpgsql to pass composite-type arguments (ie, whole-row variables)

into SQL expressions.  At present this only works usefully for variables
of named rowtypes, not RECORD variables, since the SQL parser can't infer
anything about datatypes from a RECORD Param.  Still, it's a step forward.
parent 724c7064
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.54 2004/06/03 22:56:43 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.55 2004/06/04 00:07:52 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -1589,17 +1589,15 @@ read_sql_construct(int until, ...@@ -1589,17 +1589,15 @@ read_sql_construct(int until,
break; break;
case T_ROW: case T_ROW:
/* XXX make this work someday */ params[nparams] = yylval.row->rowno;
ereport(ERROR, snprintf(buf, sizeof(buf), " $%d ", ++nparams);
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), plpgsql_dstring_append(&ds, buf);
errmsg("passing a whole row variable into a SQL command is not implemented")));
break; break;
case T_RECORD: case T_RECORD:
/* XXX make this work someday */ params[nparams] = yylval.rec->recno;
ereport(ERROR, snprintf(buf, sizeof(buf), " $%d ", ++nparams);
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), plpgsql_dstring_append(&ds, buf);
errmsg("passing a whole record variable into a SQL command is not implemented")));
break; break;
default: default:
...@@ -1810,17 +1808,15 @@ make_select_stmt(void) ...@@ -1810,17 +1808,15 @@ make_select_stmt(void)
break; break;
case T_ROW: case T_ROW:
/* XXX make this work someday */ params[nparams] = yylval.row->rowno;
ereport(ERROR, snprintf(buf, sizeof(buf), " $%d ", ++nparams);
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), plpgsql_dstring_append(&ds, buf);
errmsg("passing a whole row variable into a SQL command is not implemented")));
break; break;
case T_RECORD: case T_RECORD:
/* XXX make this work someday */ params[nparams] = yylval.rec->recno;
ereport(ERROR, snprintf(buf, sizeof(buf), " $%d ", ++nparams);
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), plpgsql_dstring_append(&ds, buf);
errmsg("passing a whole record variable into a SQL command is not implemented")));
break; break;
default: default:
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.102 2004/05/30 23:40:41 neilc Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.103 2004/06/04 00:07:52 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -2969,17 +2969,12 @@ exec_eval_datum(PLpgSQL_execstate * estate, ...@@ -2969,17 +2969,12 @@ exec_eval_datum(PLpgSQL_execstate * estate,
Datum *value, Datum *value,
bool *isnull) bool *isnull)
{ {
PLpgSQL_var *var;
PLpgSQL_rec *rec;
PLpgSQL_recfield *recfield;
PLpgSQL_trigarg *trigarg;
int tgargno;
int fno;
switch (datum->dtype) switch (datum->dtype)
{ {
case PLPGSQL_DTYPE_VAR: case PLPGSQL_DTYPE_VAR:
var = (PLpgSQL_var *) datum; {
PLpgSQL_var *var = (PLpgSQL_var *) datum;
*typeid = var->datatype->typoid; *typeid = var->datatype->typoid;
*value = var->value; *value = var->value;
*isnull = var->isnull; *isnull = var->isnull;
...@@ -2989,9 +2984,56 @@ exec_eval_datum(PLpgSQL_execstate * estate, ...@@ -2989,9 +2984,56 @@ exec_eval_datum(PLpgSQL_execstate * estate,
errmsg("type of \"%s\" does not match that when preparing the plan", errmsg("type of \"%s\" does not match that when preparing the plan",
var->refname))); var->refname)));
break; break;
}
case PLPGSQL_DTYPE_ROW:
{
PLpgSQL_row *row = (PLpgSQL_row *) datum;
HeapTuple tup;
if (!row->rowtupdesc) /* should not happen */
elog(ERROR, "row variable has no tupdesc");
tup = make_tuple_from_row(estate, row, row->rowtupdesc);
if (tup == NULL) /* should not happen */
elog(ERROR, "row not compatible with its own tupdesc");
*typeid = row->rowtupdesc->tdtypeid;
*value = HeapTupleGetDatum(tup);
*isnull = false;
if (expectedtypeid != InvalidOid && expectedtypeid != *typeid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type of \"%s\" does not match that when preparing the plan",
row->refname)));
break;
}
case PLPGSQL_DTYPE_REC:
{
PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
if (!HeapTupleIsValid(rec->tup))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("record \"%s\" is not assigned yet",
rec->refname),
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
*typeid = rec->tupdesc->tdtypeid;
*value = HeapTupleGetDatum(rec->tup);
*isnull = false;
if (expectedtypeid != InvalidOid && expectedtypeid != *typeid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type of \"%s\" does not match that when preparing the plan",
rec->refname)));
break;
}
case PLPGSQL_DTYPE_RECFIELD: case PLPGSQL_DTYPE_RECFIELD:
recfield = (PLpgSQL_recfield *) datum; {
PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
PLpgSQL_rec *rec;
int fno;
rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]); rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
if (!HeapTupleIsValid(rec->tup)) if (!HeapTupleIsValid(rec->tup))
ereport(ERROR, ereport(ERROR,
...@@ -3013,9 +3055,13 @@ exec_eval_datum(PLpgSQL_execstate * estate, ...@@ -3013,9 +3055,13 @@ exec_eval_datum(PLpgSQL_execstate * estate,
errmsg("type of \"%s.%s\" does not match that when preparing the plan", errmsg("type of \"%s.%s\" does not match that when preparing the plan",
rec->refname, recfield->fieldname))); rec->refname, recfield->fieldname)));
break; break;
}
case PLPGSQL_DTYPE_TRIGARG: case PLPGSQL_DTYPE_TRIGARG:
trigarg = (PLpgSQL_trigarg *) datum; {
PLpgSQL_trigarg *trigarg = (PLpgSQL_trigarg *) datum;
int tgargno;
*typeid = TEXTOID; *typeid = TEXTOID;
tgargno = exec_eval_integer(estate, trigarg->argnum, isnull); tgargno = exec_eval_integer(estate, trigarg->argnum, isnull);
if (*isnull || tgargno < 0 || tgargno >= estate->trig_nargs) if (*isnull || tgargno < 0 || tgargno >= estate->trig_nargs)
...@@ -3034,6 +3080,7 @@ exec_eval_datum(PLpgSQL_execstate * estate, ...@@ -3034,6 +3080,7 @@ exec_eval_datum(PLpgSQL_execstate * estate,
errmsg("type of tgargv[%d] does not match that when preparing the plan", errmsg("type of tgargv[%d] does not match that when preparing the plan",
tgargno))); tgargno)));
break; break;
}
default: default:
elog(ERROR, "unrecognized dtype: %d", datum->dtype); elog(ERROR, "unrecognized dtype: %d", datum->dtype);
......
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