+ <para> + If the last column is marked with <literal>PERIOD</literal>, + it is treated in a special way. + While the non-<literal>PERIOD</literal> columns are treated normally + (and there must be at least one of them), + the <literal>PERIOD</literal> column is not compared for equality. + Instead the constraint is considered satisfied + if the referenced table has matching records + (based on the non-<literal>PERIOD</literal> parts of the key) + whose combined <literal>PERIOD</literal> values completely cover + the referencing record's. + In other words, the reference must have a referent for its entire duration. + Normally this column would be a range or multirange type, + although any type whose GiST opclass has a "contained by" operator + and a <literal>referenced_agg</literal> support function is allowed. + (See <xref linkend="gist-extensibility"/>.) + In addition the referenced table must have a primary key + or unique constraint declared with <literal>WITHOUT PORTION</literal>. + </para>
typo "referenced_agg", in the gist-extensibility.html page is "referencedagg" <literal>WITHOUT PORTION</literal> should be <literal>WITHOUT OVERLAPS</literal> + While the non-<literal>PERIOD</literal> columns are treated normally + (and there must be at least one of them), + the <literal>PERIOD</literal> column is not compared for equality. the above sentence didn't say what is "normally"? maybe we can do the following: + While the non-<literal>PERIOD</literal> columns are treated + normally for equality + (and there must be at least one of them), + the <literal>PERIOD</literal> column is not compared for equality. +<programlisting> +Datum +my_range_agg_transfn(PG_FUNCTION_ARGS) +{ + MemoryContext aggContext; + Oid rngtypoid; + ArrayBuildState *state; + + if (!AggCheckCallContext(fcinfo, &aggContext)) + elog(ERROR, "range_agg_transfn called in non-aggregate context"); + + rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1); + if (!type_is_range(rngtypoid)) + elog(ERROR, "range_agg must be called with a range"); + + if (PG_ARGISNULL(0)) + state = initArrayResult(rngtypoid, aggContext, false); + else + state = (ArrayBuildState *) PG_GETARG_POINTER(0); + + /* skip NULLs */ + if (!PG_ARGISNULL(1)) + accumArrayResult(state, PG_GETARG_DATUM(1), false, rngtypoid, aggContext); + + PG_RETURN_POINTER(state); +} + +Datum +my_range_agg_finalfn(PG_FUNCTION_ARGS) +{ + MemoryContext aggContext; + Oid mltrngtypoid; + TypeCacheEntry *typcache; + ArrayBuildState *state; + int32 range_count; + RangeType **ranges; + int i; + + if (!AggCheckCallContext(fcinfo, &aggContext)) + elog(ERROR, "range_agg_finalfn called in non-aggregate context"); + + state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0); + if (state == NULL) + /* This shouldn't be possible, but just in case.... */ + PG_RETURN_NULL(); + + /* Also return NULL if we had zero inputs, like other aggregates */ + range_count = state->nelems; + if (range_count == 0) + PG_RETURN_NULL(); + + mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo); + typcache = multirange_get_typcache(fcinfo, mltrngtypoid); + + ranges = palloc0(range_count * sizeof(RangeType *)); + for (i = 0; i < range_count; i++) + ranges[i] = DatumGetRangeTypeP(state->dvalues[i]); + + PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypoid, typcache->rngtype, range_count, ranges)); +} my_range_agg_transfn error message is inconsistent? `elog(ERROR, "range_agg_transfn called in non-aggregate context");` `elog(ERROR, "range_agg must be called with a range");` maybe just `my_range_agg_transfn`, instead of mention {range_agg_transfn|range_agg} similarly my_range_agg_finalfn error is also inconsistent. my_range_agg_finalfn need `type_is_multirange(mltrngtypoid)`?