* Compute stored generated columns for a tuple */
| 322 | * Compute stored generated columns for a tuple |
| 323 | */ |
| 324 | void |
| 325 | ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, |
| 326 | EState *estate, TupleTableSlot *slot, |
| 327 | CmdType cmdtype) |
| 328 | { |
| 329 | Relation rel = resultRelInfo->ri_RelationDesc; |
| 330 | TupleDesc tupdesc = RelationGetDescr(rel); |
| 331 | int natts = tupdesc->natts; |
| 332 | MemoryContext oldContext; |
| 333 | Datum *values; |
| 334 | bool *nulls; |
| 335 | |
| 336 | Assert(tupdesc->constr && tupdesc->constr->has_generated_stored); |
| 337 | |
| 338 | /* |
| 339 | * If first time through for this result relation, build expression |
| 340 | * nodetrees for rel's stored generation expressions. Keep them in the |
| 341 | * per-query memory context so they'll survive throughout the query. |
| 342 | */ |
| 343 | if (resultRelInfo->ri_GeneratedExprs == NULL) |
| 344 | { |
| 345 | oldContext = MemoryContextSwitchTo(estate->es_query_cxt); |
| 346 | |
| 347 | resultRelInfo->ri_GeneratedExprs = |
| 348 | (ExprState **) palloc(natts * sizeof(ExprState *)); |
| 349 | resultRelInfo->ri_NumGeneratedNeeded = 0; |
| 350 | |
| 351 | for (int i = 0; i < natts; i++) |
| 352 | { |
| 353 | if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED) |
| 354 | { |
| 355 | Expr *expr; |
| 356 | |
| 357 | /* |
| 358 | * If it's an update and the current column was not marked as |
| 359 | * being updated, then we can skip the computation. But if |
| 360 | * there is a BEFORE ROW UPDATE trigger, we cannot skip |
| 361 | * because the trigger might affect additional columns. |
| 362 | */ |
| 363 | if (cmdtype == CMD_UPDATE && |
| 364 | !(rel->trigdesc && rel->trigdesc->trig_update_before_row) && |
| 365 | !bms_is_member(i + 1 - FirstLowInvalidHeapAttributeNumber, |
| 366 | ExecGetExtraUpdatedCols(resultRelInfo, estate))) |
| 367 | { |
| 368 | resultRelInfo->ri_GeneratedExprs[i] = NULL; |
| 369 | continue; |
| 370 | } |
| 371 | |
| 372 | expr = (Expr *) build_column_default(rel, i + 1); |
| 373 | if (expr == NULL) |
| 374 | elog(ERROR, "no generation expression found for column number %d of table \"%s\"", |
| 375 | i + 1, RelationGetRelationName(rel)); |
| 376 | |
| 377 | resultRelInfo->ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate); |
| 378 | resultRelInfo->ri_NumGeneratedNeeded++; |
| 379 | } |
| 380 | } |
| 381 |
no test coverage detected