|
11 | 11 | * SQL aggregates. (Do not expect POSTQUEL semantics.) -- ay 2/95
|
12 | 12 | *
|
13 | 13 | * IDENTIFICATION
|
14 |
| - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.57 1999/10/08 03:49:55 tgl Exp $ |
| 14 | + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.58 1999/10/30 01:18:16 tgl Exp $ |
15 | 15 | *
|
16 | 16 | *-------------------------------------------------------------------------
|
17 | 17 | */
|
@@ -408,24 +408,43 @@ ExecAgg(Agg *node)
|
408 | 408 | return NULL;
|
409 | 409 | }
|
410 | 410 | else
|
| 411 | + { |
411 | 412 | aggstate->agg_done = true;
|
| 413 | + /* |
| 414 | + * If inputtuple==NULL (ie, the outerPlan didn't return anything), |
| 415 | + * create a dummy all-nulls input tuple for use by execProject. |
| 416 | + * 99.44% of the time this is a waste of cycles, because |
| 417 | + * ordinarily the projected output tuple's targetlist cannot |
| 418 | + * contain any direct (non-aggregated) references to input |
| 419 | + * columns, so the dummy tuple will not be referenced. However |
| 420 | + * there are special cases where this isn't so --- in particular |
| 421 | + * an UPDATE involving an aggregate will have a targetlist |
| 422 | + * reference to ctid. We need to return a null for ctid in that |
| 423 | + * situation, not coredump. |
| 424 | + * |
| 425 | + * The values returned for the aggregates will be the initial |
| 426 | + * values of the transition functions. |
| 427 | + */ |
| 428 | + if (inputTuple == NULL) |
| 429 | + { |
| 430 | + TupleDesc tupType; |
| 431 | + Datum *tupValue; |
| 432 | + char *null_array; |
| 433 | + AttrNumber attnum; |
| 434 | + |
| 435 | + tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor; |
| 436 | + tupValue = projInfo->pi_tupValue; |
| 437 | + null_array = (char *) palloc(sizeof(char) * tupType->natts); |
| 438 | + for (attnum = 0; attnum < tupType->natts; attnum++) |
| 439 | + null_array[attnum] = 'n'; |
| 440 | + inputTuple = heap_formtuple(tupType, tupValue, null_array); |
| 441 | + pfree(null_array); |
| 442 | + } |
| 443 | + } |
412 | 444 |
|
413 | 445 | /*
|
414 |
| - * We used to create a dummy all-nulls input tuple here if |
415 |
| - * inputTuple == NULL (ie, the outerPlan didn't return anything). |
416 |
| - * However, now that we don't return a bogus tuple in Group mode, |
417 |
| - * we can only get here with inputTuple == NULL in non-Group mode. |
418 |
| - * So, if the parser has done its job right, the projected output |
419 |
| - * tuple's targetList must not contain any direct references to |
420 |
| - * input columns, and so it's a waste of time to create an |
421 |
| - * all-nulls input tuple. We just let the tuple slot get set |
422 |
| - * to NULL instead. The values returned for the aggregates will |
423 |
| - * be the initial values of the transition functions. |
424 |
| - */ |
425 |
| - |
426 |
| - /* |
427 |
| - * Store the representative input tuple (or NULL, if none) |
428 |
| - * in the tuple table slot reserved for it. |
| 446 | + * Store the representative input tuple in the tuple table slot |
| 447 | + * reserved for it. |
429 | 448 | */
|
430 | 449 | ExecStoreTuple(inputTuple,
|
431 | 450 | aggstate->csstate.css_ScanTupleSlot,
|
|
0 commit comments