1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/* This file is included multiple times (from sql_cast.c).
10 * We expect the tokens TP1 & TP2 to be defined by the including file.
11 */
12
13/* ! ENSURE THAT THESE LOCAL MACROS ARE UNDEFINED AT THE END OF THIS FILE ! */
14
15/* stringify token */
16#define _STRNG_(s) #s
17#define STRNG(t) _STRNG_(t)
18
19/* concatenate two, three or four tokens */
20#define CONCAT_2(a,b) a##b
21#define CONCAT_3(a,b,c) a##b##c
22#define CONCAT_4(a,b,c,d) a##b##c##d
23
24#define NIL(t) CONCAT_2(t,_nil)
25#define ISNIL(t) CONCAT_3(is_,t,_nil)
26#define TPE(t) CONCAT_2(TYPE_,t)
27#define GDKmin(t) CONCAT_3(GDK_,t,_min)
28#define GDKmax(t) CONCAT_3(GDK_,t,_max)
29#define FUN(a,b,c,d) CONCAT_4(a,b,c,d)
30
31
32/* when casting a floating point to a decimal we like to preserve the
33 * precision. This means we first scale the float before converting.
34*/
35str
36FUN(,TP1,_num2dec_,TP2)(TP2 *res, const TP1 *v, const int *d2, const int *s2)
37{
38 TP1 val = *v;
39 int scale = *s2;
40 int precision = *d2;
41 int inlen;
42
43 if (ISNIL(TP1)(val)) {
44 *res = NIL(TP2);
45 return MAL_SUCCEED;
46 }
47
48 if (val <= -1) {
49 /* (-Inf, -1] */
50 inlen = (int) floor(log10(-val)) + 1;
51 } else if (val < 1) {
52 /* (-1, 1) */
53 inlen = 1;
54 } else {
55 /* [1, Inf) */
56 inlen = (int) floor(log10(val)) + 1;
57 }
58 if (inlen + scale > precision)
59 throw(SQL, "convert", SQLSTATE(22003) "too many digits (%d > %d)",
60 inlen + scale, precision);
61
62#ifndef TRUNCATE_NUMBERS
63 *res = (TP2) round_float(val * scales[scale]);
64#endif
65
66
67 return MAL_SUCCEED;
68}
69
70str
71FUN(bat,TP1,_num2dec_,TP2) (bat *res, const bat *bid, const int *d2, const int *s2)
72{
73 BAT *b, *dst;
74 BUN p, q;
75 char *msg = NULL;
76
77 if ((b = BATdescriptor(*bid)) == NULL) {
78 throw(SQL, "batcalc."STRNG(FUN(,TP1,_num2dec_,TP2)), SQLSTATE(HY005) "Cannot access column descriptor");
79 }
80 dst = COLnew(b->hseqbase, TPE(TP2), BATcount(b), TRANSIENT);
81 if (dst == NULL) {
82 BBPunfix(b->batCacheid);
83 throw(SQL, "sql."STRNG(FUN(,TP1,_num2dec_,TP2)), SQLSTATE(HY001) MAL_MALLOC_FAIL);
84 }
85 const TP1 *v = (const TP1 *) Tloc(b, 0);
86 BATloop(b, p, q) {
87 TP2 r;
88 msg = FUN(,TP1,_num2dec_,TP2) (&r, v, d2, s2);
89 if (msg) {
90 BBPunfix(dst->batCacheid);
91 BBPunfix(b->batCacheid);
92 return msg;
93 }
94 if (BUNappend(dst, &r, false) != GDK_SUCCEED) {
95 BBPunfix(dst->batCacheid);
96 BBPunfix(b->batCacheid);
97 throw(SQL, "sql."STRNG(FUN(,TP1,_num2dec_,TP2)), SQLSTATE(HY001) MAL_MALLOC_FAIL);
98 }
99 v++;
100 }
101 BBPkeepref(*res = dst->batCacheid);
102 BBPunfix(b->batCacheid);
103 return msg;
104}
105
106
107/* undo local defines */
108#undef FUN
109#undef NIL
110#undef ISNIL
111#undef TPE
112#undef GDKmin
113#undef GDKmax
114#undef CONCAT_2
115#undef CONCAT_3
116#undef CONCAT_4
117#undef STRNG
118#undef _STRNG_
119
120