* Helper for plpgsql_exec_function: coerce composite result to the specified * tuple descriptor, and copy it out to upper executor memory. This is split * out mostly for cosmetic reasons --- the logic would be very deeply nested * otherwise. * * estate->retval is updated in-place. */
| 792 | * estate->retval is updated in-place. |
| 793 | */ |
| 794 | static void |
| 795 | coerce_function_result_tuple(PLpgSQL_execstate *estate, TupleDesc tupdesc) |
| 796 | { |
| 797 | HeapTuple rettup; |
| 798 | TupleDesc retdesc; |
| 799 | TupleConversionMap *tupmap; |
| 800 | |
| 801 | /* We assume exec_stmt_return verified that result is composite */ |
| 802 | Assert(type_is_rowtype(estate->rettype)); |
| 803 | |
| 804 | /* We can special-case expanded records for speed */ |
| 805 | if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(estate->retval))) |
| 806 | { |
| 807 | ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(estate->retval); |
| 808 | |
| 809 | Assert(erh->er_magic == ER_MAGIC); |
| 810 | |
| 811 | /* Extract record's TupleDesc */ |
| 812 | retdesc = expanded_record_get_tupdesc(erh); |
| 813 | |
| 814 | /* check rowtype compatibility */ |
| 815 | tupmap = convert_tuples_by_position(retdesc, |
| 816 | tupdesc, |
| 817 | gettext_noop("returned record type does not match expected record type")); |
| 818 | |
| 819 | /* it might need conversion */ |
| 820 | if (tupmap) |
| 821 | { |
| 822 | rettup = expanded_record_get_tuple(erh); |
| 823 | Assert(rettup); |
| 824 | rettup = execute_attr_map_tuple(rettup, tupmap); |
| 825 | |
| 826 | /* |
| 827 | * Copy tuple to upper executor memory, as a tuple Datum. Make |
| 828 | * sure it is labeled with the caller-supplied tuple type. |
| 829 | */ |
| 830 | estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc)); |
| 831 | /* no need to free map, we're about to return anyway */ |
| 832 | } |
| 833 | else if (!(tupdesc->tdtypeid == erh->er_decltypeid || |
| 834 | (tupdesc->tdtypeid == RECORDOID && |
| 835 | !ExpandedRecordIsDomain(erh)))) |
| 836 | { |
| 837 | /* |
| 838 | * The expanded record has the right physical tupdesc, but the |
| 839 | * wrong type ID. (Typically, the expanded record is RECORDOID |
| 840 | * but the function is declared to return a named composite type. |
| 841 | * As in exec_move_row_from_datum, we don't allow returning a |
| 842 | * composite-domain record from a function declared to return |
| 843 | * RECORD.) So we must flatten the record to a tuple datum and |
| 844 | * overwrite its type fields with the right thing. spi.c doesn't |
| 845 | * provide any easy way to deal with this case, so we end up |
| 846 | * duplicating the guts of datumCopy() :-( |
| 847 | */ |
| 848 | Size resultsize; |
| 849 | HeapTupleHeader tuphdr; |
| 850 | |
| 851 | resultsize = EOH_get_flat_size(&erh->hdr); |
no test coverage detected