diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index d771a265b34..196472c05d0 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -246,10 +246,11 @@ CreateTupleDescCopy(TupleDesc tupdesc) desc = CreateTemplateTupleDesc(tupdesc->natts); - /* Flat-copy the attribute array */ - memcpy(TupleDescAttr(desc, 0), - TupleDescAttr(tupdesc, 0), - desc->natts * sizeof(FormData_pg_attribute)); + /* Flat-copy the attribute array (unless there are no attributes) */ + if (desc->natts > 0) + memcpy(TupleDescAttr(desc, 0), + TupleDescAttr(tupdesc, 0), + desc->natts * sizeof(FormData_pg_attribute)); /* * Since we're not copying constraints and defaults, clear fields @@ -294,10 +295,11 @@ CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts) desc = CreateTemplateTupleDesc(natts); - /* Flat-copy the attribute array */ - memcpy(TupleDescAttr(desc, 0), - TupleDescAttr(tupdesc, 0), - desc->natts * sizeof(FormData_pg_attribute)); + /* Flat-copy the attribute array (unless there are no attributes) */ + if (desc->natts > 0) + memcpy(TupleDescAttr(desc, 0), + TupleDescAttr(tupdesc, 0), + desc->natts * sizeof(FormData_pg_attribute)); /* * Since we're not copying constraints and defaults, clear fields @@ -339,10 +341,11 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) desc = CreateTemplateTupleDesc(tupdesc->natts); - /* Flat-copy the attribute array */ - memcpy(TupleDescAttr(desc, 0), - TupleDescAttr(tupdesc, 0), - desc->natts * sizeof(FormData_pg_attribute)); + /* Flat-copy the attribute array (unless there are no attributes) */ + if (desc->natts > 0) + memcpy(TupleDescAttr(desc, 0), + TupleDescAttr(tupdesc, 0), + desc->natts * sizeof(FormData_pg_attribute)); for (i = 0; i < desc->natts; i++) { diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 62ef6b38497..d26287271e9 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -179,6 +179,8 @@ TupleDescAttr(TupleDesc tupdesc, int i) { FormData_pg_attribute *attrs = TupleDescAttrAddress(tupdesc); + Assert(i >= 0 && i < tupdesc->natts); + return &attrs[i]; } diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index c5f11b874c7..06ebffa111c 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -1093,7 +1093,7 @@ plperl_build_tuple_result(HV *perlhash, TupleDesc td) SV *val = HeVAL(he); char *key = hek2cstr(he); int attn = SPI_fnumber(td, key); - Form_pg_attribute attr = TupleDescAttr(td, attn - 1); + Form_pg_attribute attr; if (attn == SPI_ERROR_NOATTRIBUTE) ereport(ERROR, @@ -1106,6 +1106,7 @@ plperl_build_tuple_result(HV *perlhash, TupleDesc td) errmsg("cannot set system attribute \"%s\"", key))); + attr = TupleDescAttr(td, attn - 1); values[attn - 1] = plperl_sv_to_datum(val, attr->atttypid, attr->atttypmod, @@ -1799,7 +1800,7 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) char *key = hek2cstr(he); SV *val = HeVAL(he); int attn = SPI_fnumber(tupdesc, key); - Form_pg_attribute attr = TupleDescAttr(tupdesc, attn - 1); + Form_pg_attribute attr; if (attn == SPI_ERROR_NOATTRIBUTE) ereport(ERROR, @@ -1811,6 +1812,8 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot set system attribute \"%s\"", key))); + + attr = TupleDescAttr(tupdesc, attn - 1); if (attr->attgenerated) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 45d667428f4..65b0fd0790f 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3401,7 +3401,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_var *var = (PLpgSQL_var *) retvar; Datum retval = var->value; bool isNull = var->isnull; - Form_pg_attribute attr = TupleDescAttr(tupdesc, 0); + Form_pg_attribute attr; if (natts != 1) ereport(ERROR, @@ -3414,6 +3414,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, var->datatype->typlen); /* coerce type if needed */ + attr = TupleDescAttr(tupdesc, 0); retval = exec_cast_value(estate, retval, &isNull, @@ -3532,7 +3533,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, } else { - Form_pg_attribute attr = TupleDescAttr(tupdesc, 0); + Form_pg_attribute attr; /* Simple scalar result */ if (natts != 1) @@ -3541,6 +3542,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, errmsg("wrong result type supplied in RETURN NEXT"))); /* coerce type if needed */ + attr = TupleDescAttr(tupdesc, 0); retval = exec_cast_value(estate, retval, &isNull,