-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathvec_trim_scale.c
94 lines (81 loc) · 2.48 KB
/
vec_trim_scale.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
Datum vec_trim_scale(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(vec_trim_scale);
// trim the output scale to drop trailing zeros; in PG13 the trim_scale function is available,
// otherwise manually find the appropriate scale to trim to
Datum
trimScaleNumeric(Datum num);
/**
* Trims trailing zeros from a numeric array.
*
* This function takes an array of n numeric elements and performs a
* "trim scale" operation on each to remove any trailing zeros by
* adjusting their decimal scale.
*/
Datum
vec_trim_scale(PG_FUNCTION_ARGS)
{
int16 elemTypeWidth;
bool elemTypeByValue;
char elemTypeAlignmentCode;
int valsLength;
ArrayType *valsArray, *retArray;
Datum *valsContent, *retContent;
bool *valsNulls, *retNulls;
int i;
int dims[1];
int lbs[1];
if (PG_ARGISNULL(0)) {
PG_RETURN_NULL();
}
valsArray = PG_GETARG_ARRAYTYPE_P(0);
if (ARR_NDIM(valsArray) == 0) {
PG_RETURN_NULL();
}
if (ARR_NDIM(valsArray) > 1) {
ereport(ERROR, (errmsg("vec_trim_scale: one-dimensional arrays are required, but got %d", ARR_NDIM(valsArray))));
}
get_typlenbyvalalign(NUMERICOID, &elemTypeWidth, &elemTypeByValue, &elemTypeAlignmentCode);
deconstruct_array(valsArray, NUMERICOID, elemTypeWidth, elemTypeByValue, elemTypeAlignmentCode,
&valsContent, &valsNulls, &valsLength);
retContent = palloc0(sizeof(Datum) * valsLength);
retNulls = palloc0(sizeof(bool) * valsLength);
for (i = 0; i < valsLength; i++) {
if (valsNulls[i]) {
retNulls[i] = true;
continue;
}
retNulls[i] = false;
retContent[i] = trimScaleNumeric(valsContent[i]);
}
dims[0] = valsLength;
lbs[0] = 1;
retArray = construct_md_array(retContent, retNulls, 1, dims, lbs,
NUMERICOID, elemTypeWidth, elemTypeByValue, elemTypeAlignmentCode);
PG_RETURN_ARRAYTYPE_P(retArray);
}
Datum
trimScaleNumeric(Datum num) {
#if PG_VERSION_NUM >= 130000
return DirectFunctionCall1(numeric_trim_scale, num);
#else
char *str;
int len;
int j;
int p;
// look for number of trailing zeros in string version, then set scale accordingly
str = DatumGetCString(DirectFunctionCall1(numeric_out, num));
len = strlen(str);
p = -1;
for (j = len - 1; j >= 0; j--) {
if (str[j] == '0') {
continue;
} else if (str[j] == '.') {
// we found the decimal point; handle all trailing zeros by setting scale to 0
return DirectFunctionCall2(numeric_trunc, num, Int32GetDatum(p > j ? p - j : 0));
} else if (p < 0) {
p = j;
}
}
return num;
#endif
}