Allow plpgsql to pass composite-type arguments (ie, whole-row variables)
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Jun 2004 00:07:52 +0000 (00:07 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Jun 2004 00:07:52 +0000 (00:07 +0000)
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.

src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/pl_exec.c

index 36427e2ceaa3be5cb79612d625b33dfcb1c61bcf..7abc1e19b83d0ab379fc312f77a3465b8ed90e01 100644 (file)
@@ -4,7 +4,7 @@
  *                                               procedural language
  *
  * 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.
  *
@@ -1589,17 +1589,15 @@ read_sql_construct(int until,
                                break;
 
                        case T_ROW:
-                               /* XXX make this work someday */
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                errmsg("passing a whole row variable into a SQL command is not implemented")));
+                               params[nparams] = yylval.row->rowno;
+                               snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
                                break;
 
                        case T_RECORD:
-                               /* XXX make this work someday */
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                errmsg("passing a whole record variable into a SQL command is not implemented")));
+                               params[nparams] = yylval.rec->recno;
+                               snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
                                break;
 
                        default:
@@ -1810,17 +1808,15 @@ make_select_stmt(void)
                                break;
 
                        case T_ROW:
-                               /* XXX make this work someday */
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                errmsg("passing a whole row variable into a SQL command is not implemented")));
+                               params[nparams] = yylval.row->rowno;
+                               snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
                                break;
 
                        case T_RECORD:
-                               /* XXX make this work someday */
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                errmsg("passing a whole record variable into a SQL command is not implemented")));
+                               params[nparams] = yylval.rec->recno;
+                               snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
                                break;
 
                        default:
index 7fa1eecaca2d6a47e32acec891abbea8e89bff42..149c96ec7baccc5d9c3a4d5c5b274227d32ff5e4 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * 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.
  *
@@ -2969,17 +2969,12 @@ exec_eval_datum(PLpgSQL_execstate * estate,
                                Datum *value,
                                bool *isnull)
 {
-       PLpgSQL_var *var;
-       PLpgSQL_rec *rec;
-       PLpgSQL_recfield *recfield;
-       PLpgSQL_trigarg *trigarg;
-       int                     tgargno;
-       int                     fno;
-
        switch (datum->dtype)
        {
                case PLPGSQL_DTYPE_VAR:
-                       var = (PLpgSQL_var *) datum;
+               {
+                       PLpgSQL_var *var = (PLpgSQL_var *) datum;
+
                        *typeid = var->datatype->typoid;
                        *value = var->value;
                        *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",
                                                                var->refname)));
                        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:
-                       recfield = (PLpgSQL_recfield *) datum;
+               {
+                       PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
+                       PLpgSQL_rec *rec;
+                       int                     fno;
+
                        rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
                        if (!HeapTupleIsValid(rec->tup))
                                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",
                                                                rec->refname, recfield->fieldname)));
                        break;
+               }
 
                case PLPGSQL_DTYPE_TRIGARG:
-                       trigarg = (PLpgSQL_trigarg *) datum;
+               {
+                       PLpgSQL_trigarg *trigarg = (PLpgSQL_trigarg *) datum;
+                       int                     tgargno;
+
                        *typeid = TEXTOID;
                        tgargno = exec_eval_integer(estate, trigarg->argnum, isnull);
                        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",
                                                                tgargno)));
                        break;
+               }
 
                default:
                        elog(ERROR, "unrecognized dtype: %d", datum->dtype);