Skip to content

Commit 0f059e1

Browse files
committed
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.
1 parent 724c706 commit 0f059e1

File tree

2 files changed

+71
-28
lines changed

2 files changed

+71
-28
lines changed

src/pl/plpgsql/src/gram.y

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* procedural language
55
*
66
* IDENTIFICATION
7-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.54 2004/06/03 22:56:43 tgl Exp $
7+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.55 2004/06/04 00:07:52 tgl Exp $
88
*
99
* This software is copyrighted by Jan Wieck - Hamburg.
1010
*
@@ -1589,17 +1589,15 @@ read_sql_construct(int until,
15891589
break;
15901590

15911591
case T_ROW:
1592-
/* XXX make this work someday */
1593-
ereport(ERROR,
1594-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1595-
errmsg("passing a whole row variable into a SQL command is not implemented")));
1592+
params[nparams] = yylval.row->rowno;
1593+
snprintf(buf, sizeof(buf), " $%d ", ++nparams);
1594+
plpgsql_dstring_append(&ds, buf);
15961595
break;
15971596

15981597
case T_RECORD:
1599-
/* XXX make this work someday */
1600-
ereport(ERROR,
1601-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1602-
errmsg("passing a whole record variable into a SQL command is not implemented")));
1598+
params[nparams] = yylval.rec->recno;
1599+
snprintf(buf, sizeof(buf), " $%d ", ++nparams);
1600+
plpgsql_dstring_append(&ds, buf);
16031601
break;
16041602

16051603
default:
@@ -1810,17 +1808,15 @@ make_select_stmt(void)
18101808
break;
18111809

18121810
case T_ROW:
1813-
/* XXX make this work someday */
1814-
ereport(ERROR,
1815-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1816-
errmsg("passing a whole row variable into a SQL command is not implemented")));
1811+
params[nparams] = yylval.row->rowno;
1812+
snprintf(buf, sizeof(buf), " $%d ", ++nparams);
1813+
plpgsql_dstring_append(&ds, buf);
18171814
break;
18181815

18191816
case T_RECORD:
1820-
/* XXX make this work someday */
1821-
ereport(ERROR,
1822-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1823-
errmsg("passing a whole record variable into a SQL command is not implemented")));
1817+
params[nparams] = yylval.rec->recno;
1818+
snprintf(buf, sizeof(buf), " $%d ", ++nparams);
1819+
plpgsql_dstring_append(&ds, buf);
18241820
break;
18251821

18261822
default:

src/pl/plpgsql/src/pl_exec.c

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.102 2004/05/30 23:40:41 neilc Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.103 2004/06/04 00:07:52 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -2969,17 +2969,12 @@ exec_eval_datum(PLpgSQL_execstate * estate,
29692969
Datum *value,
29702970
bool *isnull)
29712971
{
2972-
PLpgSQL_var *var;
2973-
PLpgSQL_rec *rec;
2974-
PLpgSQL_recfield *recfield;
2975-
PLpgSQL_trigarg *trigarg;
2976-
int tgargno;
2977-
int fno;
2978-
29792972
switch (datum->dtype)
29802973
{
29812974
case PLPGSQL_DTYPE_VAR:
2982-
var = (PLpgSQL_var *) datum;
2975+
{
2976+
PLpgSQL_var *var = (PLpgSQL_var *) datum;
2977+
29832978
*typeid = var->datatype->typoid;
29842979
*value = var->value;
29852980
*isnull = var->isnull;
@@ -2989,9 +2984,56 @@ exec_eval_datum(PLpgSQL_execstate * estate,
29892984
errmsg("type of \"%s\" does not match that when preparing the plan",
29902985
var->refname)));
29912986
break;
2987+
}
2988+
2989+
case PLPGSQL_DTYPE_ROW:
2990+
{
2991+
PLpgSQL_row *row = (PLpgSQL_row *) datum;
2992+
HeapTuple tup;
2993+
2994+
if (!row->rowtupdesc) /* should not happen */
2995+
elog(ERROR, "row variable has no tupdesc");
2996+
tup = make_tuple_from_row(estate, row, row->rowtupdesc);
2997+
if (tup == NULL) /* should not happen */
2998+
elog(ERROR, "row not compatible with its own tupdesc");
2999+
*typeid = row->rowtupdesc->tdtypeid;
3000+
*value = HeapTupleGetDatum(tup);
3001+
*isnull = false;
3002+
if (expectedtypeid != InvalidOid && expectedtypeid != *typeid)
3003+
ereport(ERROR,
3004+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3005+
errmsg("type of \"%s\" does not match that when preparing the plan",
3006+
row->refname)));
3007+
break;
3008+
}
3009+
3010+
case PLPGSQL_DTYPE_REC:
3011+
{
3012+
PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
3013+
3014+
if (!HeapTupleIsValid(rec->tup))
3015+
ereport(ERROR,
3016+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3017+
errmsg("record \"%s\" is not assigned yet",
3018+
rec->refname),
3019+
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
3020+
*typeid = rec->tupdesc->tdtypeid;
3021+
*value = HeapTupleGetDatum(rec->tup);
3022+
*isnull = false;
3023+
if (expectedtypeid != InvalidOid && expectedtypeid != *typeid)
3024+
ereport(ERROR,
3025+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3026+
errmsg("type of \"%s\" does not match that when preparing the plan",
3027+
rec->refname)));
3028+
break;
3029+
}
29923030

29933031
case PLPGSQL_DTYPE_RECFIELD:
2994-
recfield = (PLpgSQL_recfield *) datum;
3032+
{
3033+
PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
3034+
PLpgSQL_rec *rec;
3035+
int fno;
3036+
29953037
rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
29963038
if (!HeapTupleIsValid(rec->tup))
29973039
ereport(ERROR,
@@ -3013,9 +3055,13 @@ exec_eval_datum(PLpgSQL_execstate * estate,
30133055
errmsg("type of \"%s.%s\" does not match that when preparing the plan",
30143056
rec->refname, recfield->fieldname)));
30153057
break;
3058+
}
30163059

30173060
case PLPGSQL_DTYPE_TRIGARG:
3018-
trigarg = (PLpgSQL_trigarg *) datum;
3061+
{
3062+
PLpgSQL_trigarg *trigarg = (PLpgSQL_trigarg *) datum;
3063+
int tgargno;
3064+
30193065
*typeid = TEXTOID;
30203066
tgargno = exec_eval_integer(estate, trigarg->argnum, isnull);
30213067
if (*isnull || tgargno < 0 || tgargno >= estate->trig_nargs)
@@ -3034,6 +3080,7 @@ exec_eval_datum(PLpgSQL_execstate * estate,
30343080
errmsg("type of tgargv[%d] does not match that when preparing the plan",
30353081
tgargno)));
30363082
break;
3083+
}
30373084

30383085
default:
30393086
elog(ERROR, "unrecognized dtype: %d", datum->dtype);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy