* exec_move_row_from_datum Move a composite Datum into a record or row * * This is equivalent to deconstruct_composite_datum() followed by * exec_move_row(), but we can optimize things if the Datum is an * expanded-record reference. * * Note: it's caller's responsibility to be sure value is of composite type. */
| 7348 | * Note: it's caller's responsibility to be sure value is of composite type. |
| 7349 | */ |
| 7350 | static void |
| 7351 | exec_move_row_from_datum(PLpgSQL_execstate *estate, |
| 7352 | PLpgSQL_variable *target, |
| 7353 | Datum value) |
| 7354 | { |
| 7355 | /* Check to see if source is an expanded record */ |
| 7356 | if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value))) |
| 7357 | { |
| 7358 | ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(value); |
| 7359 | ExpandedRecordHeader *newerh = NULL; |
| 7360 | |
| 7361 | Assert(erh->er_magic == ER_MAGIC); |
| 7362 | |
| 7363 | /* These cases apply if the target is record not row... */ |
| 7364 | if (target->dtype == PLPGSQL_DTYPE_REC) |
| 7365 | { |
| 7366 | PLpgSQL_rec *rec = (PLpgSQL_rec *) target; |
| 7367 | |
| 7368 | /* |
| 7369 | * If it's the same record already stored in the variable, do |
| 7370 | * nothing. This would happen only in silly cases like "r := r", |
| 7371 | * but we need some check to avoid possibly freeing the variable's |
| 7372 | * live value below. Note that this applies even if what we have |
| 7373 | * is a R/O pointer. |
| 7374 | */ |
| 7375 | if (erh == rec->erh) |
| 7376 | return; |
| 7377 | |
| 7378 | /* |
| 7379 | * Make sure rec->rectypeid is up-to-date before using it. |
| 7380 | */ |
| 7381 | revalidate_rectypeid(rec); |
| 7382 | |
| 7383 | /* |
| 7384 | * If we have a R/W pointer, we're allowed to just commandeer |
| 7385 | * ownership of the expanded record. If it's of the right type to |
| 7386 | * put into the record variable, do that. (Note we don't accept |
| 7387 | * an expanded record of a composite-domain type as a RECORD |
| 7388 | * value. We'll treat it as the base composite type instead; |
| 7389 | * compare logic in make_expanded_record_for_rec.) |
| 7390 | */ |
| 7391 | if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(value)) && |
| 7392 | (rec->rectypeid == erh->er_decltypeid || |
| 7393 | (rec->rectypeid == RECORDOID && |
| 7394 | !ExpandedRecordIsDomain(erh)))) |
| 7395 | { |
| 7396 | assign_record_var(estate, rec, erh); |
| 7397 | return; |
| 7398 | } |
| 7399 | |
| 7400 | /* |
| 7401 | * If we already have an expanded record object in the target |
| 7402 | * variable, and the source record contains a valid tuple |
| 7403 | * representation with the right rowtype, then we can skip making |
| 7404 | * a new expanded record and just assign the tuple with |
| 7405 | * expanded_record_set_tuple. (We can't do the equivalent if we |
| 7406 | * have to do field-by-field assignment, since that wouldn't be |
| 7407 | * atomic if there's an error.) We consider that there's a |
no test coverage detected