-
Notifications
You must be signed in to change notification settings - Fork 5
/
vec_coalesce.c
93 lines (77 loc) · 2.69 KB
/
vec_coalesce.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
Datum vec_coalesce(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(vec_coalesce);
/**
* Coalesce elements in an array to a non-null value.
*
* This function takes an array of n elements plus a non-null value of the same type
* as the array. It returns a new array with any NULL elements of the input array
* replaced by the given non-null value.
*/
Datum
vec_coalesce(PG_FUNCTION_ARGS)
{
Oid scalarTypeId = get_fn_expr_argtype(fcinfo->flinfo, 1);
Oid elemTypeId;
int16 elemTypeWidth;
bool elemTypeByValue;
char elemTypeAlignmentCode;
int inputLength;
ArrayType *inputArray, *retArray;
Datum *inputContent, scalarContent, *retContent = 0;
bool *inputNulls, *retNulls;
int i, j;
int dims[1];
int lbs[1];
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
PG_RETURN_NULL();
}
inputArray = PG_GETARG_ARRAYTYPE_P(0);
if (ARR_NDIM(inputArray) == 0) {
PG_RETURN_NULL();
}
if (ARR_NDIM(inputArray) > 1) {
ereport(ERROR, (errmsg("vec_coalesce: one-dimensional array is required")));
}
elemTypeId = ARR_ELEMTYPE(inputArray);
if (elemTypeId != INT2OID &&
elemTypeId != INT4OID &&
elemTypeId != INT8OID &&
elemTypeId != FLOAT4OID &&
elemTypeId != FLOAT8OID &&
elemTypeId != NUMERICOID) {
ereport(ERROR, (errmsg("vec_coalesce input must be array of SMALLINT, INTEGER, BIGINT, REAL, DOUBLE PRECISION, or NUMERIC")));
}
if (elemTypeId != scalarTypeId) {
ereport(ERROR, (errmsg("vec_coalesce input array and scalar must be the same type")));
}
get_typlenbyvalalign(scalarTypeId, &elemTypeWidth, &elemTypeByValue, &elemTypeAlignmentCode);
deconstruct_array(inputArray, scalarTypeId, elemTypeWidth, elemTypeByValue, elemTypeAlignmentCode,
&inputContent, &inputNulls, &inputLength);
scalarContent = PG_GETARG_DATUM(1);
for (i = 0; i < inputLength; i++) {
if (inputNulls[i]) {
if (!retContent) {
// lazy-init return structures now
retContent = palloc0(sizeof(Datum) * inputLength);
retNulls = palloc0(sizeof(bool) * inputLength);
// back-fill skipped values as needed
for (j = 0; j < i; j++) {
retNulls[j] = false;
retContent[j] = inputContent[j];
}
}
retNulls[i] = false;
retContent[i] = scalarContent;
} else if (retContent) {
retNulls[i] = false;
retContent[i] = inputContent[i];
}
}
// if we found no NULL elements; simply return the input to save a few cycles
if (!retContent) PG_RETURN_ARRAYTYPE_P(inputArray);
dims[0] = inputLength;
lbs[0] = 1;
retArray = construct_md_array(retContent, retNulls, 1, dims, lbs,
scalarTypeId, elemTypeWidth, elemTypeByValue, elemTypeAlignmentCode);
PG_RETURN_ARRAYTYPE_P(retArray);
}