14
14
* Copyright (c) 1998-2003, PostgreSQL Global Development Group
15
15
*
16
16
* 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 $
18
18
*
19
19
*-------------------------------------------------------------------------
20
20
*/
@@ -252,6 +252,7 @@ static Numeric make_result(NumericVar *var);
252
252
253
253
static void apply_typmod (NumericVar * var , int32 typmod );
254
254
255
+ static int32 numericvar_to_int4 (NumericVar * var );
255
256
static bool numericvar_to_int8 (NumericVar * var , int64 * result );
256
257
static void int8_to_numericvar (int64 val , NumericVar * var );
257
258
static double numeric_to_double_no_overflow (Numeric num );
@@ -285,6 +286,8 @@ static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
285
286
static void round_var (NumericVar * var , int rscale );
286
287
static void trunc_var (NumericVar * var , int rscale );
287
288
static void strip_var (NumericVar * var );
289
+ static void compute_bucket (Numeric operand , Numeric bound1 , Numeric bound2 ,
290
+ NumericVar * count_var , NumericVar * result_var );
288
291
289
292
290
293
/* ----------------------------------------------------------------------
@@ -803,6 +806,125 @@ numeric_floor(PG_FUNCTION_ARGS)
803
806
PG_RETURN_NUMERIC (res );
804
807
}
805
808
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
+ }
806
928
807
929
/* ----------------------------------------------------------------------
808
930
*
@@ -1612,7 +1734,6 @@ numeric_int4(PG_FUNCTION_ARGS)
1612
1734
{
1613
1735
Numeric num = PG_GETARG_NUMERIC (0 );
1614
1736
NumericVar x ;
1615
- int64 val ;
1616
1737
int32 result ;
1617
1738
1618
1739
/* XXX would it be better to return NULL? */
@@ -1621,17 +1742,30 @@ numeric_int4(PG_FUNCTION_ARGS)
1621
1742
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1622
1743
errmsg ("cannot convert NaN to integer" )));
1623
1744
1624
- /* Convert to variable format and thence to int8 */
1745
+ /* Convert to variable format, then convert to int4 */
1625
1746
init_var (& x );
1626
1747
set_var_from_num (num , & x );
1748
+ result = numericvar_to_int4 (& x );
1749
+ free_var (& x );
1750
+ PG_RETURN_INT32 (result );
1751
+ }
1627
1752
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 ))
1629
1765
ereport (ERROR ,
1630
1766
(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1631
1767
errmsg ("integer out of range" )));
1632
1768
1633
- free_var (& x );
1634
-
1635
1769
/* Down-convert to int4 */
1636
1770
result = (int32 ) val ;
1637
1771
@@ -1641,10 +1775,9 @@ numeric_int4(PG_FUNCTION_ARGS)
1641
1775
(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1642
1776
errmsg ("integer out of range" )));
1643
1777
1644
- PG_RETURN_INT32 ( result ) ;
1778
+ return result ;
1645
1779
}
1646
1780
1647
-
1648
1781
Datum
1649
1782
int8_numeric (PG_FUNCTION_ARGS )
1650
1783
{
0 commit comments