* exec_move_row_from_fields Move arrays of field values into a record or row * * When assigning to a record, the caller must have already created a suitable * new expanded record object, newerh. Pass NULL when assigning to a row. * * tupdesc describes the input row, which might have different column * types and/or different dropped-column positions than the target. * values/nulls/tupdesc c
| 6952 | * exec_eval_cleanup to prevent long-term memory leaks. |
| 6953 | */ |
| 6954 | static void |
| 6955 | exec_move_row_from_fields(PLpgSQL_execstate *estate, |
| 6956 | PLpgSQL_variable *target, |
| 6957 | ExpandedRecordHeader *newerh, |
| 6958 | Datum *values, bool *nulls, |
| 6959 | TupleDesc tupdesc) |
| 6960 | { |
| 6961 | int td_natts = tupdesc ? tupdesc->natts : 0; |
| 6962 | int fnum; |
| 6963 | int anum; |
| 6964 | int strict_multiassignment_level = 0; |
| 6965 | |
| 6966 | /* |
| 6967 | * The extra check strict strict_multi_assignment can be active, only when |
| 6968 | * input tupdesc is specified. |
| 6969 | */ |
| 6970 | if (tupdesc != NULL) |
| 6971 | { |
| 6972 | if (plpgsql_extra_errors & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT) |
| 6973 | strict_multiassignment_level = ERROR; |
| 6974 | else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT) |
| 6975 | strict_multiassignment_level = WARNING; |
| 6976 | } |
| 6977 | |
| 6978 | /* Handle RECORD-target case */ |
| 6979 | if (target->dtype == PLPGSQL_DTYPE_REC) |
| 6980 | { |
| 6981 | PLpgSQL_rec *rec = (PLpgSQL_rec *) target; |
| 6982 | TupleDesc var_tupdesc; |
| 6983 | Datum newvalues_local[64]; |
| 6984 | bool newnulls_local[64]; |
| 6985 | |
| 6986 | Assert(newerh != NULL); /* caller must have built new object */ |
| 6987 | |
| 6988 | var_tupdesc = expanded_record_get_tupdesc(newerh); |
| 6989 | |
| 6990 | /* |
| 6991 | * Coerce field values if needed. This might involve dealing with |
| 6992 | * different sets of dropped columns and/or coercing individual column |
| 6993 | * types. That's sort of a pain, but historically plpgsql has allowed |
| 6994 | * it, so we preserve the behavior. However, it's worth a quick check |
| 6995 | * to see if the tupdescs are identical. (Since expandedrecord.c |
| 6996 | * prefers to use refcounted tupdescs from the typcache, expanded |
| 6997 | * records with the same rowtype will have pointer-equal tupdescs.) |
| 6998 | */ |
| 6999 | if (var_tupdesc != tupdesc) |
| 7000 | { |
| 7001 | int vtd_natts = var_tupdesc->natts; |
| 7002 | Datum *newvalues; |
| 7003 | bool *newnulls; |
| 7004 | |
| 7005 | /* |
| 7006 | * Need workspace arrays. If vtd_natts is small enough, use local |
| 7007 | * arrays to save doing a palloc. Even if it's not small, we can |
| 7008 | * allocate both the Datum and isnull arrays in one palloc chunk. |
| 7009 | */ |
| 7010 | if (vtd_natts <= lengthof(newvalues_local)) |
| 7011 | { |
no test coverage detected