diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 535fea9257..a80235cd2a 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1267,9 +1267,11 @@ make_datum_param(PLpgSQL_expr *expr, int dno, int location) param = makeNode(Param); param->paramkind = PARAM_EXTERN; param->paramid = dno + 1; - param->paramtype = exec_get_datum_type(estate, datum); - param->paramtypmod = -1; - param->paramcollid = exec_get_datum_collation(estate, datum); + exec_get_datum_type_info(estate, + datum, + ¶m->paramtype, + ¶m->paramtypmod, + ¶m->paramcollid); param->location = location; return (Node *) param; diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 8ca9689efc..4331a5c8df 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -4307,29 +4307,63 @@ exec_get_datum_type(PLpgSQL_execstate *estate, } /* - * exec_get_datum_collation Get collation of a PLpgSQL_datum + * exec_get_datum_type_info Get datatype etc of a PLpgSQL_datum + * + * An extended version of exec_get_datum_type, which also retrieves the + * typmod and collation of the datum. */ -Oid -exec_get_datum_collation(PLpgSQL_execstate *estate, - PLpgSQL_datum *datum) +void +exec_get_datum_type_info(PLpgSQL_execstate *estate, + PLpgSQL_datum *datum, + Oid *typeid, int32 *typmod, Oid *collation) { - Oid collid; - switch (datum->dtype) { case PLPGSQL_DTYPE_VAR: { PLpgSQL_var *var = (PLpgSQL_var *) datum; - collid = var->datatype->collation; + *typeid = var->datatype->typoid; + *typmod = var->datatype->atttypmod; + *collation = var->datatype->collation; break; } case PLPGSQL_DTYPE_ROW: + { + PLpgSQL_row *row = (PLpgSQL_row *) datum; + + if (!row->rowtupdesc) /* should not happen */ + elog(ERROR, "row variable has no tupdesc"); + /* Make sure we have a valid type/typmod setting */ + BlessTupleDesc(row->rowtupdesc); + *typeid = row->rowtupdesc->tdtypeid; + /* do NOT return the mutable typmod of a RECORD variable */ + *typmod = -1; + /* composite types are never collatable */ + *collation = InvalidOid; + break; + } + case PLPGSQL_DTYPE_REC: - /* composite types are never collatable */ - collid = InvalidOid; - break; + { + PLpgSQL_rec *rec = (PLpgSQL_rec *) datum; + + if (rec->tupdesc == NULL) + 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."))); + /* Make sure we have a valid type/typmod setting */ + BlessTupleDesc(rec->tupdesc); + *typeid = rec->tupdesc->tdtypeid; + /* do NOT return the mutable typmod of a RECORD variable */ + *typmod = -1; + /* composite types are never collatable */ + *collation = InvalidOid; + break; + } case PLPGSQL_DTYPE_RECFIELD: { @@ -4350,21 +4384,27 @@ exec_get_datum_collation(PLpgSQL_execstate *estate, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("record \"%s\" has no field \"%s\"", rec->refname, recfield->fieldname))); - /* XXX there's no SPI_getcollid, as yet */ + *typeid = SPI_gettypeid(rec->tupdesc, fno); + /* XXX there's no SPI_gettypmod, for some reason */ if (fno > 0) - collid = rec->tupdesc->attrs[fno - 1]->attcollation; + *typmod = rec->tupdesc->attrs[fno - 1]->atttypmod; + else + *typmod = -1; + /* XXX there's no SPI_getcollation either */ + if (fno > 0) + *collation = rec->tupdesc->attrs[fno - 1]->attcollation; else /* no system column types have collation */ - collid = InvalidOid; + *collation = InvalidOid; break; } default: elog(ERROR, "unrecognized dtype: %d", datum->dtype); - collid = InvalidOid; /* keep compiler quiet */ + *typeid = InvalidOid; /* keep compiler quiet */ + *typmod = -1; + *collation = InvalidOid; break; } - - return collid; } /* ---------- diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index e50d7eb45f..89103aea8c 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -905,8 +905,9 @@ extern void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg); extern Oid exec_get_datum_type(PLpgSQL_execstate *estate, PLpgSQL_datum *datum); -extern Oid exec_get_datum_collation(PLpgSQL_execstate *estate, - PLpgSQL_datum *datum); +extern void exec_get_datum_type_info(PLpgSQL_execstate *estate, + PLpgSQL_datum *datum, + Oid *typeid, int32 *typmod, Oid *collation); /* ---------- * Functions for namespace handling in pl_funcs.c