2010/9/21 Robert Haas <robertmh...@gmail.com>: > On Tue, Sep 21, 2010 at 4:28 PM, Pavel Stehule <pavel.steh...@gmail.com> > wrote: >>> * Cosmetic coding style should be more appropriate, including trailing >>> white spaces and indentation positions. >> >> can you specify where, please? > > I noticed a lot of problems in this area when working on your \ef / > \sf patch, too. Trailing whitespace is nearly always bad, and it's > not hard to find - just grep the diff for it. As for indentation, try > to match the surrounding code.
is updated patch better? Pavel > > -- > Robert Haas > EnterpriseDB: http://www.enterprisedb.com > The Enterprise Postgres Company >
*** ./contrib/Makefile.orig 2010-06-14 18:17:56.000000000 +0200 --- ./contrib/Makefile 2010-09-21 19:24:59.211190814 +0200 *************** *** 23,28 **** --- 23,29 ---- isn \ lo \ ltree \ + median \ oid2name \ pageinspect \ passwordcheck \ *** ./contrib/median/expected/median.out.orig 2010-09-21 22:03:24.749899797 +0200 --- ./contrib/median/expected/median.out 2010-09-21 23:01:31.162022861 +0200 *************** *** 0 **** --- 1,30 ---- + -- import library + SET client_min_messages = warning; + \set ECHO none + -- check result for numeric datatypes + create table median_test( + a int, + b int8, + c float, + d numeric, + e double precision + ); + insert into median_test + select i,i,i,i,i + from generate_series(1,10) g(i); + select median(a), median(b), median(c), median(d), median(e) from median_test; + median | median | median | median | median + --------------------+--------------------+--------+--------------------+-------- + 5.5000000000000000 | 5.5000000000000000 | 5.5 | 5.5000000000000000 | 5.5 + (1 row) + + truncate table median_test; + insert into median_test + select i,i,i,i,i + from generate_series(1,11) g(i); + select median(a), median(b), median(c), median(d), median(e) from median_test; + median | median | median | median | median + --------+--------+--------+--------+-------- + 6 | 6 | 6 | 6 | 6 + (1 row) + *** ./contrib/median/Makefile.orig 2010-08-19 12:38:56.144777253 +0200 --- ./contrib/median/Makefile 2010-08-18 20:23:39.180156339 +0200 *************** *** 0 **** --- 1,17 ---- + # $PostgreSQL: pgsql/contrib/median/Makefile,v 1.1 2008/07/29 18:31:20 tgl Exp $ + + MODULES = median + DATA_built = median.sql + DATA = uninstall_median.sql + REGRESS = median + + ifdef USE_PGXS + PG_CONFIG = pg_config + PGXS := $(shell $(PG_CONFIG) --pgxs) + include $(PGXS) + else + subdir = contrib/median + top_builddir = ../.. + include $(top_builddir)/src/Makefile.global + include $(top_srcdir)/contrib/contrib-global.mk + endif *** ./contrib/median/median.c.orig 2010-08-19 12:39:01.456650776 +0200 --- ./contrib/median/median.c 2010-09-21 23:00:17.962025215 +0200 *************** *** 0 **** --- 1,283 ---- + /* + * $PostgreSQL: pgsql/contrib/citext/citext.c,v 1.2 2009/06/11 14:48:50 momjian Exp $ + */ + #include "postgres.h" + + #include "funcapi.h" + #include "miscadmin.h" + #include "catalog/pg_type.h" + #include "parser/parse_coerce.h" + #include "parser/parse_oper.h" + #include "utils/builtins.h" + #include "utils/numeric.h" + #include "utils/tuplesort.h" + + Datum median_transfn(PG_FUNCTION_ARGS); + Datum median_finalfn_double(PG_FUNCTION_ARGS); + Datum median_finalfn_numeric(PG_FUNCTION_ARGS); + + Datum percentile_transfn(PG_FUNCTION_ARGS); + Datum percentile_finalfn(PG_FUNCTION_ARGS); + + #ifdef PG_MODULE_MAGIC + PG_MODULE_MAGIC; + #endif + + PG_FUNCTION_INFO_V1(median_transfn); + PG_FUNCTION_INFO_V1(median_finalfn_double); + PG_FUNCTION_INFO_V1(median_finalfn_numeric); + + typedef struct + { + int nelems; /* number of valid entries */ + Tuplesortstate *sortstate; + FmgrInfo cast_func_finfo; + int p; /* nth for percentille */ + MemoryContext aggcontext; + } StatAggState; + + static StatAggState * + makeStatAggState(FunctionCallInfo fcinfo) + { + MemoryContext oldctx; + MemoryContext aggcontext; + StatAggState *aggstate; + Oid sortop, + castfunc; + Oid valtype; + Oid targettype = InvalidOid; + CoercionPathType pathtype; + + /* + * A tuplesort creates a child Memory Context "TupleSort", but + * a current implementation of window functions drops all child + * context every iteration, and therefore this function cannot + * be called as windows function for this moment. + */ + if (fcinfo->context && IsA(fcinfo->context, WindowAggState)) + { + /* cannot be called inside like windowAggregates */ + elog(ERROR, "median_transfn called in windows aggregate context"); + } + + if (!AggCheckCallContext(fcinfo, &aggcontext)) + { + /* cannot be called directly because of internal-type argument */ + elog(ERROR, "string_agg_transfn called in non-aggregate context"); + } + + oldctx = MemoryContextSwitchTo(aggcontext); + + aggstate = (StatAggState *) palloc0(sizeof(StatAggState)); + aggstate->nelems = 0; + aggstate->aggcontext = aggcontext; + + valtype = get_fn_expr_argtype(fcinfo->flinfo, 1); + get_sort_group_operators(valtype, + true, false, false, + &sortop, NULL, NULL); + + aggstate->sortstate = tuplesort_begin_datum(valtype, + sortop, + SORTBY_NULLS_DEFAULT, + work_mem, false); + + MemoryContextSwitchTo(oldctx); + + /* + * The result type will be numeric for integer types and for numeric type. + * For other types resulting type is double precission. This is consistent + * with other aggregates like AVG,.. + */ + switch (valtype) + { + case FLOAT8OID: + case FLOAT4OID: + targettype = FLOAT8OID; + break; + + case INT2OID: + case INT4OID: + case INT8OID: + case NUMERICOID: + targettype = NUMERICOID; + break; + + default: + elog(ERROR, "unsupported data type with oid %d", valtype); + } + if (valtype != targettype) + { + /* find a cast function */ + pathtype = find_coercion_pathway(targettype, valtype, + COERCION_EXPLICIT, + &castfunc); + if (pathtype == COERCION_PATH_FUNC) + { + Assert(OidIsValid(castfunc)); + fmgr_info_cxt(castfunc, &aggstate->cast_func_finfo, + aggcontext); + } + else if (pathtype == COERCION_PATH_RELABELTYPE) + { + aggstate->cast_func_finfo.fn_oid = InvalidOid; + } + else + elog(ERROR, "no conversion function from %s %s", + format_type_be(valtype), + format_type_be(targettype)); + } + + return aggstate; + } + + /* + * append a non NULL value to tuplesort + */ + Datum + median_transfn(PG_FUNCTION_ARGS) + { + StatAggState *aggstate; + + aggstate = PG_ARGISNULL(0) ? NULL : (StatAggState *) PG_GETARG_POINTER(0); + + if (!PG_ARGISNULL(1)) + { + if (aggstate == NULL) + aggstate = makeStatAggState(fcinfo); + + tuplesort_putdatum(aggstate->sortstate, PG_GETARG_DATUM(1), false); + aggstate->nelems++; + } + + PG_RETURN_POINTER(aggstate); + } + + static double + to_double(Datum value, FmgrInfo *cast_func_finfo) + { + /* when valtype is same as target type, returns directly */ + if (cast_func_finfo->fn_oid == InvalidOid) + return DatumGetFloat8(value); + + return DatumGetFloat8(FunctionCall1(cast_func_finfo, value)); + } + + Datum + median_finalfn_double(PG_FUNCTION_ARGS) + { + StatAggState *aggstate; + + Assert(AggCheckCallContext(fcinfo, NULL)); + + aggstate = PG_ARGISNULL(0) ? NULL : (StatAggState *) PG_GETARG_POINTER(0); + + if (aggstate != NULL) + { + int lidx; + int hidx; + Datum value; + bool isNull; + int i = 1; + double result = 0; + + hidx = aggstate->nelems / 2 + 1; + lidx = (aggstate->nelems + 1) / 2; + + tuplesort_performsort(aggstate->sortstate); + + while (tuplesort_getdatum(aggstate->sortstate, + true, + &value, &isNull)) + { + if (i++ == lidx) + { + result = to_double(value, &aggstate->cast_func_finfo); + + if (lidx != hidx) + { + tuplesort_getdatum(aggstate->sortstate, + true, + &value, &isNull); + result = (result + to_double(value, &aggstate->cast_func_finfo)) / 2.0; + } + break; + } + } + + tuplesort_end(aggstate->sortstate); + + PG_RETURN_FLOAT8(result); + } + else + PG_RETURN_NULL(); + } + + static Numeric + to_numeric(Datum value, FmgrInfo *cast_func_finfo) + { + /* when valtype is same as target type, returns directly */ + if (cast_func_finfo->fn_oid == InvalidOid) + return DatumGetNumeric(value); + + return DatumGetNumeric(FunctionCall1(cast_func_finfo, value)); + } + + Datum + median_finalfn_numeric(PG_FUNCTION_ARGS) + { + StatAggState *aggstate; + + Assert(AggCheckCallContext(fcinfo, NULL)); + + aggstate = PG_ARGISNULL(0) ? NULL : (StatAggState *) PG_GETARG_POINTER(0); + + if (aggstate != NULL) + { + int lidx; + int hidx; + Datum value; + bool isNull; + int i = 1; + Numeric result = NULL; /* be compiler quiet */ + + hidx = aggstate->nelems / 2 + 1; + lidx = (aggstate->nelems + 1) / 2; + + tuplesort_performsort(aggstate->sortstate); + + while (tuplesort_getdatum(aggstate->sortstate, + true, + &value, &isNull)) + { + if (i++ == lidx) + { + result = to_numeric(value, &aggstate->cast_func_finfo); + + if (lidx != hidx) + { + Numeric stack; + + tuplesort_getdatum(aggstate->sortstate, + true, + &value, &isNull); + stack = to_numeric(value, &aggstate->cast_func_finfo); + stack = DatumGetNumeric(DirectFunctionCall2(numeric_add, + NumericGetDatum(stack), + NumericGetDatum(result))); + result = DatumGetNumeric(DirectFunctionCall2(numeric_div, + NumericGetDatum(stack), + DirectFunctionCall1(float4_numeric, + Float4GetDatum(2.0)))); + } + break; + } + } + + tuplesort_end(aggstate->sortstate); + + PG_RETURN_NUMERIC(result); + } + else + PG_RETURN_NULL(); + } *** ./contrib/median/median.sql.in.orig 2010-08-19 12:39:06.192775857 +0200 --- ./contrib/median/median.sql.in 2010-09-21 21:52:18.730897577 +0200 *************** *** 0 **** --- 1,50 ---- + CREATE OR REPLACE FUNCTION median_transfn(internal, anyelement) + RETURNS internal + AS 'MODULE_PATHNAME' + LANGUAGE C IMMUTABLE; + + CREATE OR REPLACE FUNCTION median_finalfn_double(internal) + RETURNS double precision + AS 'MODULE_PATHNAME' + LANGUAGE C IMMUTABLE; + + CREATE OR REPLACE FUNCTION median_finalfn_numeric(internal) + RETURNS numeric + AS 'MODULE_PATHNAME' + LANGUAGE C IMMUTABLE; + + CREATE AGGREGATE median(bigint) ( + SFUNC=median_transfn, + STYPE=internal, + FINALFUNC=median_finalfn_numeric + ); + + CREATE AGGREGATE median(double precision) ( + SFUNC=median_transfn, + STYPE=internal, + FINALFUNC=median_finalfn_double + ); + + CREATE AGGREGATE median(integer) ( + SFUNC=median_transfn, + STYPE=internal, + FINALFUNC=median_finalfn_numeric + ); + + CREATE AGGREGATE median(numeric) ( + SFUNC=median_transfn, + STYPE=internal, + FINALFUNC=median_finalfn_numeric + ); + + CREATE AGGREGATE median(real) ( + SFUNC=median_transfn, + STYPE=internal, + FINALFUNC=median_finalfn_double + ); + + CREATE AGGREGATE median(smallint) ( + SFUNC=median_transfn, + STYPE=internal, + FINALFUNC=median_finalfn_numeric + ); *** ./contrib/median/sql/median.sql.orig 2010-09-21 21:59:24.909024776 +0200 --- ./contrib/median/sql/median.sql 2010-09-21 23:01:18.017899528 +0200 *************** *** 0 **** --- 1,31 ---- + -- import library + + SET client_min_messages = warning; + \set ECHO none + \i median.sql + RESET client_min_messages; + \set ECHO all + + -- check result for numeric datatypes + + create table median_test( + a int, + b int8, + c float, + d numeric, + e double precision + ); + + insert into median_test + select i,i,i,i,i + from generate_series(1,10) g(i); + + select median(a), median(b), median(c), median(d), median(e) from median_test; + + truncate table median_test; + + insert into median_test + select i,i,i,i,i + from generate_series(1,11) g(i); + + select median(a), median(b), median(c), median(d), median(e) from median_test; *** ./contrib/median/uninstall_median.sql.orig 2010-08-19 12:39:11.712777158 +0200 --- ./contrib/median/uninstall_median.sql 2010-09-21 21:52:08.794896392 +0200 *************** *** 0 **** --- 1,9 ---- + DROP FUNCTION median_transfn(internal, anyelement); + DROP FUNCTION median_finalfn_double(internal); + DROP FUNCTION median_finalfn_numeric(internal); + DROP AGGREGATE median(bigint); + DROP AGGREGATE median(double precison); + DROP AGGREGATE median(integer); + DROP AGGREGATE median(numeric); + DROP AGGREGATE median(real); + DROP AGGREGATE median(smallint);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers