|
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 | returnNULL; |
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 | +TupleDesctupType; |
| 431 | +Datum*tupValue; |
| 432 | +char*null_array; |
| 433 | +AttrNumberattnum; |
| 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, |
|