mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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.
This commit is contained in:
@ -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,
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user