Index: doc/src/sgml/errcodes.sgml
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/doc/src/sgml/errcodes.sgml,v
retrieving revision 1.3
diff -c -r1.3 errcodes.sgml
*** doc/src/sgml/errcodes.sgml 4 Mar 2004 21:47:18 -0000 1.3
--- doc/src/sgml/errcodes.sgml 25 Apr 2004 02:31:27 -0000
***************
*** 306,311 ****
--- 306,316 ----
+ 2201G
+ INVALID ARGUMENT FOR WIDTH BUCKET FUNCTION
+
+
+
22018
INVALID CHARACTER VALUE FOR CAST
Index: src/backend/utils/adt/float.c
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/backend/utils/adt/float.c,v
retrieving revision 1.103
diff -c -r1.103 float.c
*** src/backend/utils/adt/float.c 1 Apr 2004 23:52:18 -0000 1.103
--- src/backend/utils/adt/float.c 24 Apr 2004 23:51:19 -0000
***************
*** 1825,1830 ****
--- 1825,1835 ----
PG_RETURN_INT32(iseed);
}
+ Datum
+ width_bucket_float8(PG_FUNCTION_ARGS)
+ {
+ ;
+ }
/*
Index: src/backend/utils/adt/numeric.c
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/backend/utils/adt/numeric.c,v
retrieving revision 1.72
diff -c -r1.72 numeric.c
*** src/backend/utils/adt/numeric.c 15 Mar 2004 03:29:22 -0000 1.72
--- src/backend/utils/adt/numeric.c 25 Apr 2004 03:49:04 -0000
***************
*** 252,257 ****
--- 252,258 ----
static void apply_typmod(NumericVar *var, int32 typmod);
+ static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int8_to_numericvar(int64 val, NumericVar *var);
static double numeric_to_double_no_overflow(Numeric num);
***************
*** 285,290 ****
--- 286,293 ----
static void round_var(NumericVar *var, int rscale);
static void trunc_var(NumericVar *var, int rscale);
static void strip_var(NumericVar *var);
+ static void compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
+ NumericVar *count_var, NumericVar *result_var);
/* ----------------------------------------------------------------------
***************
*** 803,808 ****
--- 806,930 ----
PG_RETURN_NUMERIC(res);
}
+ /*
+ * width_bucket_numeric() -
+ *
+ * 'bound1' and 'bound2' are the lower and upper bounds of the
+ * histogram's range, respectively. 'count' is the number of buckets
+ * in the histogram. width_bucket() returns an integer indicating the
+ * bucket number that 'operand' belongs in for an equiwidth histogram
+ * with the specified characteristics. An operand smaller than the
+ * lower bound is assigned to bucket 0. An operand greater than the
+ * upper bound is assigned to an additional bucket (with number
+ * count+1).
+ */
+ Datum
+ width_bucket_numeric(PG_FUNCTION_ARGS)
+ {
+ Numeric operand = PG_GETARG_NUMERIC(0);
+ Numeric bound1 = PG_GETARG_NUMERIC(1);
+ Numeric bound2 = PG_GETARG_NUMERIC(2);
+ int32 count = PG_GETARG_INT32(3);
+ NumericVar count_var;
+ NumericVar result_var;
+ int32 result;
+
+ if (count <= 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
+ errmsg("count must be greater than zero")));
+
+ init_var(&result_var);
+ init_var(&count_var);
+
+ /* Convert 'count' to a numeric, for ease of use later */
+ int8_to_numericvar((int64) count, &count_var);
+
+ switch (cmp_numerics(bound1, bound2))
+ {
+ case 0:
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
+ errmsg("lower bound cannot equal upper bound")));
+
+ /* bound1 < bound2 */
+ case -1:
+ if (cmp_numerics(operand, bound1) < 0)
+ set_var_from_var(&const_zero, &result_var);
+ else if (cmp_numerics(operand, bound2) >= 0)
+ add_var(&count_var, &const_one, &result_var);
+ else
+ compute_bucket(operand, bound1, bound2,
+ &count_var, &result_var);
+ break;
+
+ /* bound1 > bound2 */
+ case 1:
+ if (cmp_numerics(operand, bound1) > 0)
+ set_var_from_var(&const_zero, &result_var);
+ else if (cmp_numerics(operand, bound2) <= 0)
+ add_var(&count_var, &const_one, &result_var);
+ else
+ compute_bucket(operand, bound1, bound2,
+ &count_var, &result_var);
+ break;
+ }
+
+ result = numericvar_to_int4(&result_var);
+
+ free_var(&count_var);
+ free_var(&result_var);
+
+ PG_RETURN_INT32(result);
+ }
+
+ /*
+ * compute_bucket() -
+ *
+ * If 'operand' is not outside the bucket range, determine the correct
+ * bucket for it to go. The calculations performed by this function
+ * are derived directly from the SQL2003 spec.
+ */
+ static void
+ compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
+ NumericVar *count_var, NumericVar *result_var)
+ {
+ NumericVar bound1_var;
+ NumericVar bound2_var;
+ NumericVar operand_var;
+
+ init_var(&bound1_var);
+ init_var(&bound2_var);
+ init_var(&operand_var);
+
+ set_var_from_num(bound1, &bound1_var);
+ set_var_from_num(bound2, &bound2_var);
+ set_var_from_num(operand, &operand_var);
+
+ if (cmp_var(&bound1_var, &bound2_var) < 0)
+ {
+ sub_var(&operand_var, &bound1_var, &operand_var);
+ sub_var(&bound2_var, &bound1_var, &bound2_var);
+ div_var(&operand_var, &bound2_var, result_var,
+ select_div_scale(&operand_var, &bound2_var));
+ }
+ else
+ {
+ sub_var(&bound1_var, &operand_var, &operand_var);
+ sub_var(&bound1_var, &bound2_var, &bound1_var);
+ div_var(&operand_var, &bound1_var, result_var,
+ select_div_scale(&operand_var, &bound1_var));
+ }
+
+ mul_var(result_var, count_var, result_var,
+ result_var->dscale + count_var->dscale);
+ add_var(result_var, &const_one, result_var);
+ floor_var(result_var, result_var);
+
+ free_var(&bound1_var);
+ free_var(&bound2_var);
+ free_var(&operand_var);
+ }
/* ----------------------------------------------------------------------
*
***************
*** 1612,1618 ****
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar x;
- int64 val;
int32 result;
/* XXX would it be better to return NULL? */
--- 1734,1739 ----
***************
*** 1621,1637 ****
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to integer")));
! /* Convert to variable format and thence to int8 */
init_var(&x);
set_var_from_num(num, &x);
! if (!numericvar_to_int8(&x, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
- free_var(&x);
-
/* Down-convert to int4 */
result = (int32) val;
--- 1742,1771 ----
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to integer")));
! /* Convert to variable format, then convert to int4 */
init_var(&x);
set_var_from_num(num, &x);
+ result = numericvar_to_int4(&x);
+ free_var(&x);
+ PG_RETURN_INT32(result);
+ }
+
+ /*
+ * Given a NumericVar, convert it to an int32. If the NumericVar
+ * exceeds the range of an int32, raise the appropriate error via
+ * ereport(). The input NumericVar is *not* free'd.
+ */
+ static int32
+ numericvar_to_int4(NumericVar *var)
+ {
+ int32 result;
+ int64 val;
! if (!numericvar_to_int8(var, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
/* Down-convert to int4 */
result = (int32) val;
***************
*** 1641,1649 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
! PG_RETURN_INT32(result);
}
-
Datum
int8_numeric(PG_FUNCTION_ARGS)
--- 1775,1782 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
! return result;
}
Datum
int8_numeric(PG_FUNCTION_ARGS)
Index: src/include/catalog/catversion.h
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/include/catalog/catversion.h,v
retrieving revision 1.224
diff -c -r1.224 catversion.h
*** src/include/catalog/catversion.h 23 Apr 2004 20:32:19 -0000 1.224
--- src/include/catalog/catversion.h 24 Apr 2004 23:51:19 -0000
***************
*** 53,58 ****
*/
/* yyyymmddN */
! #define CATALOG_VERSION_NO 200404220
#endif
--- 53,58 ----
*/
/* yyyymmddN */
! #define CATALOG_VERSION_NO 200404230
#endif
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.325
diff -c -r1.325 pg_proc.h
*** src/include/catalog/pg_proc.h 23 Apr 2004 20:32:19 -0000 1.325
--- src/include/catalog/pg_proc.h 25 Apr 2004 03:30:52 -0000
***************
*** 2508,2513 ****
--- 2508,2517 ----
DESCR("(internal)");
DATA(insert OID = 1746 ( float8 PGNSP PGUID 12 f f t f i 1 701 "1700" _null_ numeric_float8 - _null_ ));
DESCR("(internal)");
+ DATA(insert OID = 2170 ( width_bucket PGNSP PGUID 12 f f t f i 4 23 "1700 1700 1700 23" _null_ width_bucket_numeric - _null_ ));
+ DESCR("XXX: todo");
+ DATA(insert OID = 2171 ( width_bucket PGNSP PGUID 12 f f t f i 4 23 "701 701 701 23" _null_ width_bucket_float8 - _null_ ));
+ DESCR("XXX: todo");
DATA(insert OID = 1747 ( time_pl_interval PGNSP PGUID 12 f f t f i 2 1083 "1083 1186" _null_ time_pl_interval - _null_ ));
DESCR("plus");
Index: src/include/utils/builtins.h
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/include/utils/builtins.h,v
retrieving revision 1.236
diff -c -r1.236 builtins.h
*** src/include/utils/builtins.h 1 Apr 2004 21:28:46 -0000 1.236
--- src/include/utils/builtins.h 24 Apr 2004 23:51:19 -0000
***************
*** 347,352 ****
--- 347,353 ----
extern Datum float84le(PG_FUNCTION_ARGS);
extern Datum float84gt(PG_FUNCTION_ARGS);
extern Datum float84ge(PG_FUNCTION_ARGS);
+ extern Datum width_bucket_float8(PG_FUNCTION_ARGS);
/* misc.c */
extern Datum nullvalue(PG_FUNCTION_ARGS);
***************
*** 756,761 ****
--- 757,763 ----
extern Datum int2_avg_accum(PG_FUNCTION_ARGS);
extern Datum int4_avg_accum(PG_FUNCTION_ARGS);
extern Datum int8_avg(PG_FUNCTION_ARGS);
+ extern Datum width_bucket_numeric(PG_FUNCTION_ARGS);
/* ri_triggers.c */
extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
Index: src/include/utils/errcodes.h
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/include/utils/errcodes.h,v
retrieving revision 1.8
diff -c -r1.8 errcodes.h
*** src/include/utils/errcodes.h 4 Mar 2004 21:47:18 -0000 1.8
--- src/include/utils/errcodes.h 25 Apr 2004 02:21:35 -0000
***************
*** 100,105 ****
--- 100,106 ----
#define ERRCODE_ESCAPE_CHARACTER_CONFLICT MAKE_SQLSTATE('2','2', '0','0','B')
#define ERRCODE_INDICATOR_OVERFLOW MAKE_SQLSTATE('2','2', '0','2','2')
#define ERRCODE_INTERVAL_FIELD_OVERFLOW MAKE_SQLSTATE('2','2', '0','1','5')
+ #define ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION MAKE_SQLSTATE('2','2', '0', '1', 'G')
#define ERRCODE_INVALID_CHARACTER_VALUE_FOR_CAST MAKE_SQLSTATE('2','2', '0','1','8')
#define ERRCODE_INVALID_DATETIME_FORMAT MAKE_SQLSTATE('2','2', '0','0','7')
#define ERRCODE_INVALID_ESCAPE_CHARACTER MAKE_SQLSTATE('2','2', '0','1','9')
Index: src/test/regress/expected/numeric.out
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/test/regress/expected/numeric.out,v
retrieving revision 1.14
diff -c -r1.14 numeric.out
*** src/test/regress/expected/numeric.out 23 Apr 2004 20:32:20 -0000 1.14
--- src/test/regress/expected/numeric.out 25 Apr 2004 03:58:35 -0000
***************
*** 730,735 ****
--- 730,786 ----
(7 rows)
DROP TABLE ceil_floor_round;
+ -- Testing for width_bucket()
+ -- NULL result
+ SELECT width_bucket(NULL, NULL, NULL, NULL);
+ width_bucket
+ --------------
+
+ (1 row)
+
+ -- errors
+ SELECT width_bucket(5.0, 3.0, 4.0, 0);
+ ERROR: count must be greater than zero
+ SELECT width_bucket(5.0, 3.0, 4.0, -5);
+ ERROR: count must be greater than zero
+ SELECT width_bucket(3.0, 3.0, 3.0, 888);
+ ERROR: lower bound cannot equal upper bound
+ -- normal operation
+ CREATE TABLE width_bucket_test (operand numeric);
+ COPY width_bucket_test FROM stdin;
+ SELECT
+ operand,
+ width_bucket(operand, 0, 10, 5) AS wb_1,
+ width_bucket(operand, 10, 0, 5) AS wb_2,
+ width_bucket(operand, 2, 8, 4) AS wb_3,
+ width_bucket(operand, 5.0, 5.5, 20) AS wb_4,
+ width_bucket(operand, -25, 25, 10) AS wb_5
+ FROM width_bucket_test;
+ operand | wb_1 | wb_2 | wb_3 | wb_4 | wb_5
+ ------------------+------+------+------+------+------
+ -5.2 | 0 | 6 | 0 | 0 | 4
+ -0.0000000000001 | 0 | 6 | 0 | 0 | 5
+ 0.0000000000001 | 1 | 5 | 0 | 0 | 6
+ 1 | 1 | 5 | 0 | 0 | 6
+ 1.99999999999999 | 1 | 5 | 0 | 0 | 6
+ 2 | 2 | 5 | 1 | 0 | 6
+ 2.00000000000001 | 2 | 4 | 1 | 0 | 6
+ 3 | 2 | 4 | 1 | 0 | 6
+ 4 | 3 | 4 | 2 | 0 | 6
+ 4.5 | 3 | 3 | 2 | 0 | 6
+ 5 | 3 | 3 | 3 | 1 | 7
+ 5.5 | 3 | 3 | 3 | 21 | 7
+ 6 | 4 | 3 | 3 | 21 | 7
+ 7 | 4 | 2 | 4 | 21 | 7
+ 8 | 5 | 2 | 5 | 21 | 7
+ 9 | 5 | 1 | 5 | 21 | 7
+ 9.99999999999999 | 5 | 1 | 5 | 21 | 7
+ 10 | 6 | 1 | 5 | 21 | 8
+ 10.0000000000001 | 6 | 0 | 5 | 21 | 8
+ NaN | 6 | 0 | 5 | 21 | 11
+ (20 rows)
+
+ DROP TABLE width_bucket_test;
-- TO_CHAR()
--
SELECT '' AS to_char_1, to_char(val, '9G999G999G999G999G999')
Index: src/test/regress/sql/numeric.sql
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql-server/src/test/regress/sql/numeric.sql,v
retrieving revision 1.9
diff -c -r1.9 numeric.sql
*** src/test/regress/sql/numeric.sql 23 Apr 2004 20:32:20 -0000 1.9
--- src/test/regress/sql/numeric.sql 25 Apr 2004 03:53:50 -0000
***************
*** 667,672 ****
--- 667,718 ----
SELECT a, ceil(a), ceiling(a), floor(a), round(a) FROM ceil_floor_round;
DROP TABLE ceil_floor_round;
+ -- Testing for width_bucket()
+ -- NULL result
+ SELECT width_bucket(NULL, NULL, NULL, NULL);
+
+ -- errors
+ SELECT width_bucket(5.0, 3.0, 4.0, 0);
+ SELECT width_bucket(5.0, 3.0, 4.0, -5);
+ SELECT width_bucket(3.0, 3.0, 3.0, 888);
+
+ -- normal operation
+ CREATE TABLE width_bucket_test (operand numeric);
+
+ COPY width_bucket_test FROM stdin;
+ -5.2
+ -0.0000000000001
+ 0.0000000000001
+ 1
+ 1.99999999999999
+ 2
+ 2.00000000000001
+ 3
+ 4
+ 4.5
+ 5
+ 5.5
+ 6
+ 7
+ 8
+ 9
+ 9.99999999999999
+ 10
+ 10.0000000000001
+ NaN
+ \.
+
+ SELECT
+ operand,
+ width_bucket(operand, 0, 10, 5) AS wb_1,
+ width_bucket(operand, 10, 0, 5) AS wb_2,
+ width_bucket(operand, 2, 8, 4) AS wb_3,
+ width_bucket(operand, 5.0, 5.5, 20) AS wb_4,
+ width_bucket(operand, -25, 25, 10) AS wb_5
+ FROM width_bucket_test;
+
+ DROP TABLE width_bucket_test;
+
-- TO_CHAR()
--
SELECT '' AS to_char_1, to_char(val, '9G999G999G999G999G999')