Skip to content

Commit 0079547

Browse files
author
Neil Conway
committed
Implement the width_bucket() function, per SQL2003. This commit only adds
a variant of the function for the 'numeric' datatype; it would be possible to add additional variants for other datatypes, but I haven't done so yet. This commit includes regression tests and minimal documentation; if we want developers to actually use this function in applications, we'll probably need to document what it does more fully.
1 parent 19a495c commit 0079547

File tree

10 files changed

+272
-23
lines changed

10 files changed

+272
-23
lines changed

doc/src/sgml/errcodes.sgml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.4 2004/05/14 18:04:02 neilc Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.5 2004/05/14 21:42:27 neilc Exp $ -->
22

33
<appendix id="errcodes-appendix">
44
<title><productname>PostgreSQL</productname> Error Codes</title>
@@ -310,6 +310,11 @@
310310
<entry>INTERVAL FIELD OVERFLOW</entry>
311311
</row>
312312

313+
<row>
314+
<entry><literal>2201G</literal></entry>
315+
<entry>INVALID ARGUMENT FOR WIDTH BUCKET FUNCTION</entry>
316+
</row>
317+
313318
<row>
314319
<entry><literal>22018</literal></entry>
315320
<entry>INVALID CHARACTER VALUE FOR CAST</entry>

doc/src/sgml/func.sgml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.201 2004/05/10 22:44:42 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.202 2004/05/14 21:42:27 neilc Exp $
33
PostgreSQL documentation
44
-->
55

@@ -751,6 +751,16 @@ PostgreSQL documentation
751751
<entry><literal>42.43</literal></entry>
752752
</row>
753753

754+
<row>
755+
<entry><literal><function>width_bucket</function>(<parameter>op</parameter> <type>numeric</type>, <parameter>b1</parameter> <type>numeric</type>, <parameter>b2</parameter> <type>numeric</type>, <parameter>count</parameter> <type>integer</type>)</literal></entry>
756+
<entry><type>integer</type></entry>
757+
<entry>return the bucket to which <parameter>operand</> would
758+
be assigned in an equidepth histogram with <parameter>count</>
759+
buckets, an upper bound of <parameter>b1</>, and a lower bound
760+
of <parameter>b2</></entry>
761+
<entry><literal>width_bucket(5.35, 0.024, 10.06, 5)</literal></entry>
762+
<entry><literal>3</literal></entry>
763+
</row>
754764
</tbody>
755765
</tgroup>
756766
</table>

doc/src/sgml/xfunc.sgml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.82 2004/05/10 22:44:43 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.83 2004/05/14 21:42:27 neilc Exp $
33
-->
44

55
<sect1 id="xfunc">
@@ -56,20 +56,20 @@ $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.82 2004/05/10 22:44:43 tgl Exp $
5656
</para>
5757

5858
<para>
59-
It's easiest to define <acronym>SQL</acronym>
59+
It's easiest to define <acronym>SQL</acronym>
6060
functions, so we'll start by discussing those.
6161
Most of the concepts presented for <acronym>SQL</acronym> functions
6262
will carry over to the other types of functions.
6363
</para>
6464

6565
<para>
6666
Throughout this chapter, it can be useful to look at the reference
67-
page of the <command>CREATE FUNCTION</command> command to
68-
understand the examples better.
69-
Some examples from this chapter
70-
can be found in <filename>funcs.sql</filename>
71-
and <filename>funcs.c</filename> in the <filename>src/tutorial</>
72-
directory in the <productname>PostgreSQL</productname> source distribution.
67+
page of the <xref linkend="sql-createfunction"> command to
68+
understand the examples better. Some examples from this chapter
69+
can be found in <filename>funcs.sql</filename> and
70+
<filename>funcs.c</filename> in the <filename>src/tutorial</>
71+
directory in the <productname>PostgreSQL</productname> source
72+
distribution.
7373
</para>
7474
</sect1>
7575

src/backend/utils/adt/numeric.c

Lines changed: 141 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* Copyright (c) 1998-2003, PostgreSQL Global Development Group
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.73 2004/05/07 00:24:58 tgl Exp $
17+
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.74 2004/05/14 21:42:28 neilc Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -252,6 +252,7 @@ static Numeric make_result(NumericVar *var);
252252

253253
static void apply_typmod(NumericVar *var, int32 typmod);
254254

255+
static int32 numericvar_to_int4(NumericVar *var);
255256
static bool numericvar_to_int8(NumericVar *var, int64 *result);
256257
static void int8_to_numericvar(int64 val, NumericVar *var);
257258
static double numeric_to_double_no_overflow(Numeric num);
@@ -285,6 +286,8 @@ static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
285286
static void round_var(NumericVar *var, int rscale);
286287
static void trunc_var(NumericVar *var, int rscale);
287288
static void strip_var(NumericVar *var);
289+
static void compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
290+
NumericVar *count_var, NumericVar *result_var);
288291

289292

290293
/* ----------------------------------------------------------------------
@@ -803,6 +806,125 @@ numeric_floor(PG_FUNCTION_ARGS)
803806
PG_RETURN_NUMERIC(res);
804807
}
805808

809+
/*
810+
* width_bucket_numeric() -
811+
*
812+
* 'bound1' and 'bound2' are the lower and upper bounds of the
813+
* histogram's range, respectively. 'count' is the number of buckets
814+
* in the histogram. width_bucket() returns an integer indicating the
815+
* bucket number that 'operand' belongs in for an equiwidth histogram
816+
* with the specified characteristics. An operand smaller than the
817+
* lower bound is assigned to bucket 0. An operand greater than the
818+
* upper bound is assigned to an additional bucket (with number
819+
* count+1).
820+
*/
821+
Datum
822+
width_bucket_numeric(PG_FUNCTION_ARGS)
823+
{
824+
Numeric operand = PG_GETARG_NUMERIC(0);
825+
Numeric bound1 = PG_GETARG_NUMERIC(1);
826+
Numeric bound2 = PG_GETARG_NUMERIC(2);
827+
int32 count = PG_GETARG_INT32(3);
828+
NumericVar count_var;
829+
NumericVar result_var;
830+
int32 result;
831+
832+
if (count <= 0)
833+
ereport(ERROR,
834+
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
835+
errmsg("count must be greater than zero")));
836+
837+
init_var(&result_var);
838+
init_var(&count_var);
839+
840+
/* Convert 'count' to a numeric, for ease of use later */
841+
int8_to_numericvar((int64) count, &count_var);
842+
843+
switch (cmp_numerics(bound1, bound2))
844+
{
845+
case 0:
846+
ereport(ERROR,
847+
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
848+
errmsg("lower bound cannot equal upper bound")));
849+
850+
/* bound1 < bound2 */
851+
case -1:
852+
if (cmp_numerics(operand, bound1) < 0)
853+
set_var_from_var(&const_zero, &result_var);
854+
else if (cmp_numerics(operand, bound2) >= 0)
855+
add_var(&count_var, &const_one, &result_var);
856+
else
857+
compute_bucket(operand, bound1, bound2,
858+
&count_var, &result_var);
859+
break;
860+
861+
/* bound1 > bound2 */
862+
case 1:
863+
if (cmp_numerics(operand, bound1) > 0)
864+
set_var_from_var(&const_zero, &result_var);
865+
else if (cmp_numerics(operand, bound2) <= 0)
866+
add_var(&count_var, &const_one, &result_var);
867+
else
868+
compute_bucket(operand, bound1, bound2,
869+
&count_var, &result_var);
870+
break;
871+
}
872+
873+
result = numericvar_to_int4(&result_var);
874+
875+
free_var(&count_var);
876+
free_var(&result_var);
877+
878+
PG_RETURN_INT32(result);
879+
}
880+
881+
/*
882+
* compute_bucket() -
883+
*
884+
* If 'operand' is not outside the bucket range, determine the correct
885+
* bucket for it to go. The calculations performed by this function
886+
* are derived directly from the SQL2003 spec.
887+
*/
888+
static void
889+
compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
890+
NumericVar *count_var, NumericVar *result_var)
891+
{
892+
NumericVar bound1_var;
893+
NumericVar bound2_var;
894+
NumericVar operand_var;
895+
896+
init_var(&bound1_var);
897+
init_var(&bound2_var);
898+
init_var(&operand_var);
899+
900+
set_var_from_num(bound1, &bound1_var);
901+
set_var_from_num(bound2, &bound2_var);
902+
set_var_from_num(operand, &operand_var);
903+
904+
if (cmp_var(&bound1_var, &bound2_var) < 0)
905+
{
906+
sub_var(&operand_var, &bound1_var, &operand_var);
907+
sub_var(&bound2_var, &bound1_var, &bound2_var);
908+
div_var(&operand_var, &bound2_var, result_var,
909+
select_div_scale(&operand_var, &bound2_var));
910+
}
911+
else
912+
{
913+
sub_var(&bound1_var, &operand_var, &operand_var);
914+
sub_var(&bound1_var, &bound2_var, &bound1_var);
915+
div_var(&operand_var, &bound1_var, result_var,
916+
select_div_scale(&operand_var, &bound1_var));
917+
}
918+
919+
mul_var(result_var, count_var, result_var,
920+
result_var->dscale + count_var->dscale);
921+
add_var(result_var, &const_one, result_var);
922+
floor_var(result_var, result_var);
923+
924+
free_var(&bound1_var);
925+
free_var(&bound2_var);
926+
free_var(&operand_var);
927+
}
806928

807929
/* ----------------------------------------------------------------------
808930
*
@@ -1612,7 +1734,6 @@ numeric_int4(PG_FUNCTION_ARGS)
16121734
{
16131735
Numeric num = PG_GETARG_NUMERIC(0);
16141736
NumericVar x;
1615-
int64 val;
16161737
int32 result;
16171738

16181739
/* XXX would it be better to return NULL? */
@@ -1621,17 +1742,30 @@ numeric_int4(PG_FUNCTION_ARGS)
16211742
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16221743
errmsg("cannot convert NaN to integer")));
16231744

1624-
/* Convert to variable format and thence to int8 */
1745+
/* Convert to variable format, then convert to int4 */
16251746
init_var(&x);
16261747
set_var_from_num(num, &x);
1748+
result = numericvar_to_int4(&x);
1749+
free_var(&x);
1750+
PG_RETURN_INT32(result);
1751+
}
16271752

1628-
if (!numericvar_to_int8(&x, &val))
1753+
/*
1754+
* Given a NumericVar, convert it to an int32. If the NumericVar
1755+
* exceeds the range of an int32, raise the appropriate error via
1756+
* ereport(). The input NumericVar is *not* free'd.
1757+
*/
1758+
static int32
1759+
numericvar_to_int4(NumericVar *var)
1760+
{
1761+
int32 result;
1762+
int64 val;
1763+
1764+
if (!numericvar_to_int8(var, &val))
16291765
ereport(ERROR,
16301766
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
16311767
errmsg("integer out of range")));
16321768

1633-
free_var(&x);
1634-
16351769
/* Down-convert to int4 */
16361770
result = (int32) val;
16371771

@@ -1641,10 +1775,9 @@ numeric_int4(PG_FUNCTION_ARGS)
16411775
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
16421776
errmsg("integer out of range")));
16431777

1644-
PG_RETURN_INT32(result);
1778+
return result;
16451779
}
16461780

1647-
16481781
Datum
16491782
int8_numeric(PG_FUNCTION_ARGS)
16501783
{

src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.229 2004/05/10 22:44:49 tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.230 2004/05/14 21:42:28 neilc Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 200405101
56+
#define CATALOG_VERSION_NO 200405141
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.328 2004/05/07 16:57:16 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.329 2004/05/14 21:42:28 neilc Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -2508,6 +2508,8 @@ DATA(insert OID = 1745 ( float4 PGNSP PGUID 12 f f t f i 1 700 "1700" _null_
25082508
DESCR("(internal)");
25092509
DATA(insert OID = 1746 ( float8 PGNSP PGUID 12 f f t f i 1 701 "1700" _null_ numeric_float8 - _null_ ));
25102510
DESCR("(internal)");
2511+
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_ ));
2512+
DESCR("bucket number of operand in equidepth histogram");
25112513

25122514
DATA(insert OID = 1747 ( time_pl_interval PGNSP PGUID 12 f f t f i 2 1083 "1083 1186" _null_ time_pl_interval - _null_ ));
25132515
DESCR("plus");

src/include/utils/builtins.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.237 2004/05/05 04:48:47 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.238 2004/05/14 21:42:30 neilc Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -758,6 +758,7 @@ extern Datum int8_sum(PG_FUNCTION_ARGS);
758758
extern Datum int2_avg_accum(PG_FUNCTION_ARGS);
759759
extern Datum int4_avg_accum(PG_FUNCTION_ARGS);
760760
extern Datum int8_avg(PG_FUNCTION_ARGS);
761+
extern Datum width_bucket_numeric(PG_FUNCTION_ARGS);
761762

762763
/* ri_triggers.c */
763764
extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);

src/include/utils/errcodes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
* Copyright (c) 2003, PostgreSQL Global Development Group
1313
*
14-
* $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.9 2004/05/14 18:04:02 neilc Exp $
14+
* $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.10 2004/05/14 21:42:30 neilc Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -116,6 +116,7 @@
116116
#define ERRCODE_ESCAPE_CHARACTER_CONFLICT MAKE_SQLSTATE('2','2', '0','0','B')
117117
#define ERRCODE_INDICATOR_OVERFLOW MAKE_SQLSTATE('2','2', '0','2','2')
118118
#define ERRCODE_INTERVAL_FIELD_OVERFLOW MAKE_SQLSTATE('2','2', '0','1','5')
119+
#define ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION MAKE_SQLSTATE('2','2', '0', '1', 'G')
119120
#define ERRCODE_INVALID_CHARACTER_VALUE_FOR_CAST MAKE_SQLSTATE('2','2', '0','1','8')
120121
#define ERRCODE_INVALID_DATETIME_FORMAT MAKE_SQLSTATE('2','2', '0','0','7')
121122
#define ERRCODE_INVALID_ESCAPE_CHARACTER MAKE_SQLSTATE('2','2', '0','1','9')

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy