| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2026 Tiger Data, Inc. | ||
| 3 | * Licensed under the PostgreSQL License. See LICENSE for details. | ||
| 4 | * | ||
| 5 | * vec32_pg.c - PostgreSQL functions for the vec32 type | ||
| 6 | * | ||
| 7 | * Type I/O, distance functions, comparison operators, casts. | ||
| 8 | * Distance functions bridge to SIMD-accelerated pg_vectorsearch core. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <postgres.h> | ||
| 12 | |||
| 13 | #include <catalog/pg_type.h> | ||
| 14 | #include <fmgr.h> | ||
| 15 | #include <lib/stringinfo.h> | ||
| 16 | #include <libpq/pqformat.h> | ||
| 17 | #include <utils/array.h> | ||
| 18 | #include <utils/float.h> | ||
| 19 | |||
| 20 | #include "algo/distance.h" | ||
| 21 | #include "support_pg.h" | ||
| 22 | |||
| 23 | /* ---------------------------------------------------------------- | ||
| 24 | * Type I/O | ||
| 25 | * ---------------------------------------------------------------- */ | ||
| 26 | |||
| 27 | 62 | PG_FUNCTION_INFO_V1(vs_vec32_in); | |
| 28 | |||
| 29 | Datum | ||
| 30 | 139329 | vs_vec32_in(PG_FUNCTION_ARGS) | |
| 31 | { | ||
| 32 | 139329 | char *str = PG_GETARG_CSTRING(0); | |
| 33 | 139329 | int32 typmod = PG_GETARG_INT32(2); | |
| 34 | 139329 | float values[VEC32_MAX_DIM]; | |
| 35 | 139329 | int dim = 0; | |
| 36 | 139329 | char *p = str; | |
| 37 | |||
| 38 | /* Expect leading '[' */ | ||
| 39 |
3/4✓ Branch 0 taken 139333 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 139329 times.
|
139333 | while (*p && (*p == ' ' || *p == '\t')) |
| 40 | 4 | p++; | |
| 41 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139328 times.
|
139329 | if (*p != '[') |
| 42 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ereport(ERROR, |
| 43 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | ||
| 44 | errmsg("vec32 must start with \"[\""))); | ||
| 45 | 139328 | p++; | |
| 46 | |||
| 47 | /* Parse comma-separated floats */ | ||
| 48 |
1/2✓ Branch 0 taken 14196911 times.
✗ Branch 1 not taken.
|
14196911 | while (*p) |
| 49 | { | ||
| 50 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 14196911 times.
|
14196920 | while (*p == ' ' || *p == '\t') |
| 51 | 9 | p++; | |
| 52 |
2/2✓ Branch 0 taken 14057587 times.
✓ Branch 1 taken 139324 times.
|
14196911 | if (*p == ']') |
| 53 | break; | ||
| 54 | |||
| 55 |
2/2✓ Branch 0 taken 13918260 times.
✓ Branch 1 taken 139327 times.
|
14057587 | if (dim > 0) |
| 56 | { | ||
| 57 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13918259 times.
|
13918260 | if (*p != ',') |
| 58 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ereport(ERROR, |
| 59 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | ||
| 60 | errmsg("expected \",\" or \"]\" in vec32"))); | ||
| 61 | 13918259 | p++; | |
| 62 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 13918259 times.
|
13918263 | while (*p == ' ' || *p == '\t') |
| 63 | 4 | p++; | |
| 64 | } | ||
| 65 | |||
| 66 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13918259 times.
|
13918259 | if (dim >= VEC32_MAX_DIM) |
| 67 | ✗ | ereport(ERROR, | |
| 68 | (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
| 69 | errmsg("vec32 cannot have more than %d dimensions", | ||
| 70 | VEC32_MAX_DIM))); | ||
| 71 | |||
| 72 | 14057586 | char *end; | |
| 73 | 14057586 | errno = 0; | |
| 74 | 14057586 | float val = strtof(p, &end); | |
| 75 |
3/4✓ Branch 0 taken 14057585 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14057585 times.
|
14057586 | if (end == p || errno == ERANGE) |
| 76 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ereport(ERROR, |
| 77 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | ||
| 78 | errmsg("invalid input syntax for type vec32: \"%s\"", | ||
| 79 | str))); | ||
| 80 | |||
| 81 | 14057585 | vs_pg_check_value_finite(val); | |
| 82 | 14057583 | values[dim++] = val; | |
| 83 | 14057583 | p = end; | |
| 84 | } | ||
| 85 | |||
| 86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 139324 times.
|
139324 | if (*p != ']') |
| 87 | ✗ | ereport(ERROR, | |
| 88 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | ||
| 89 | errmsg("vec32 must end with \"]\""))); | ||
| 90 | 139324 | p++; | |
| 91 | |||
| 92 | /* Check no trailing content */ | ||
| 93 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 139324 times.
|
139328 | while (*p == ' ' || *p == '\t') |
| 94 | 4 | p++; | |
| 95 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139323 times.
|
139324 | if (*p != '\0') |
| 96 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ereport(ERROR, |
| 97 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | ||
| 98 | errmsg("unexpected characters after \"]\" in vec32"))); | ||
| 99 | |||
| 100 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139322 times.
|
139323 | if (dim < 1) |
| 101 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ereport(ERROR, |
| 102 | (errcode(ERRCODE_DATA_EXCEPTION), | ||
| 103 | errmsg("vec32 must have at least 1 dimension"))); | ||
| 104 | |||
| 105 | 139322 | vs_pg_check_expected_dim(dim, typmod); | |
| 106 | |||
| 107 | 139322 | Vec32 *result = vs_pg_vec32_alloc(dim); | |
| 108 | 139322 | memcpy(result->x, values, dim * sizeof(float)); | |
| 109 | |||
| 110 | 139322 | PG_RETURN_VEC32_P(result); | |
| 111 | } | ||
| 112 | |||
| 113 | 24 | PG_FUNCTION_INFO_V1(vs_vec32_out); | |
| 114 | |||
| 115 | Datum | ||
| 116 | 83 | vs_vec32_out(PG_FUNCTION_ARGS) | |
| 117 | { | ||
| 118 | 83 | Vec32 *v = PG_GETARG_VEC32_P(0); | |
| 119 | 83 | StringInfoData buf; | |
| 120 | |||
| 121 | 83 | initStringInfo(&buf); | |
| 122 | 83 | appendStringInfoChar(&buf, '['); | |
| 123 | |||
| 124 |
2/2✓ Branch 1 taken 1142 times.
✓ Branch 2 taken 83 times.
|
1225 | for (int i = 0; i < v->dim; i++) |
| 125 | { | ||
| 126 |
2/2✓ Branch 0 taken 1059 times.
✓ Branch 1 taken 83 times.
|
1142 | if (i > 0) |
| 127 | 1059 | appendStringInfoChar(&buf, ','); | |
| 128 | 1142 | appendStringInfo(&buf, "%g", v->x[i]); | |
| 129 | } | ||
| 130 | |||
| 131 | 83 | appendStringInfoChar(&buf, ']'); | |
| 132 | |||
| 133 | 83 | PG_RETURN_CSTRING(buf.data); | |
| 134 | } | ||
| 135 | |||
| 136 | 44 | PG_FUNCTION_INFO_V1(vs_vec32_typmod_in); | |
| 137 | |||
| 138 | Datum | ||
| 139 | 300 | vs_vec32_typmod_in(PG_FUNCTION_ARGS) | |
| 140 | { | ||
| 141 | 300 | ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); | |
| 142 | 300 | int n; | |
| 143 | 300 | int32 *tl = ArrayGetIntegerTypmods(ta, &n); | |
| 144 | |||
| 145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
|
300 | if (n != 1) |
| 146 | ✗ | ereport(ERROR, | |
| 147 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||
| 148 | errmsg("invalid type modifier"))); | ||
| 149 | |||
| 150 | 300 | int dim = tl[0]; | |
| 151 | |||
| 152 | 300 | vs_pg_check_dim_valid(dim); | |
| 153 | |||
| 154 | 300 | PG_RETURN_INT32(dim); | |
| 155 | } | ||
| 156 | |||
| 157 | /* ---------------------------------------------------------------- | ||
| 158 | * Distance functions | ||
| 159 | * ---------------------------------------------------------------- */ | ||
| 160 | |||
| 161 | 58 | PG_FUNCTION_INFO_V1(vs_l2_distance); | |
| 162 | |||
| 163 | Datum | ||
| 164 | 69975 | vs_l2_distance(PG_FUNCTION_ARGS) | |
| 165 | { | ||
| 166 | 69975 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 167 | 69975 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 168 | |||
| 169 | 69975 | vs_pg_check_dims_match(a->dim, b->dim); | |
| 170 | |||
| 171 | 69974 | Vec32Ref ra = Vec32ToRef(a); | |
| 172 | 69974 | Vec32Ref rb = Vec32ToRef(b); | |
| 173 | 69974 | float d2 = vs_distance_l2(ra, rb); | |
| 174 | 69974 | double res = sqrt((double)d2); | |
| 175 | |||
| 176 | 69974 | PG_RETURN_FLOAT8(res); | |
| 177 | } | ||
| 178 | |||
| 179 | 9 | PG_FUNCTION_INFO_V1(vs_inner_product); | |
| 180 | |||
| 181 | Datum | ||
| 182 | 1 | vs_inner_product(PG_FUNCTION_ARGS) | |
| 183 | { | ||
| 184 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 185 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 186 | |||
| 187 | 1 | vs_pg_check_dims_match(a->dim, b->dim); | |
| 188 | |||
| 189 | 1 | Vec32Ref ra = Vec32ToRef(a); | |
| 190 | 1 | Vec32Ref rb = Vec32ToRef(b); | |
| 191 | 1 | float nip = vs_distance_ip(ra, rb); | |
| 192 | /* vs_distance_ip returns -dot, so negate to get actual dot */ | ||
| 193 | 1 | double res = (double)(-nip); | |
| 194 | |||
| 195 | 1 | PG_RETURN_FLOAT8(res); | |
| 196 | } | ||
| 197 | |||
| 198 | 14 | PG_FUNCTION_INFO_V1(vs_cosine_distance); | |
| 199 | |||
| 200 | Datum | ||
| 201 | 6558 | vs_cosine_distance(PG_FUNCTION_ARGS) | |
| 202 | { | ||
| 203 | 6558 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 204 | 6558 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 205 | |||
| 206 | 6558 | vs_pg_check_dims_match(a->dim, b->dim); | |
| 207 | |||
| 208 | 6558 | Vec32Ref ra = Vec32ToRef(a); | |
| 209 | 6558 | Vec32Ref rb = Vec32ToRef(b); | |
| 210 | 6558 | double res = (double)vs_distance_cosine(ra, rb); | |
| 211 | |||
| 212 | 6558 | PG_RETURN_FLOAT8(res); | |
| 213 | } | ||
| 214 | |||
| 215 | /* Private distance functions for operators (preserve metric semantics) */ | ||
| 216 | |||
| 217 | 8 | PG_FUNCTION_INFO_V1(vs_vec32_l2_squared_distance); | |
| 218 | |||
| 219 | Datum | ||
| 220 | ✗ | vs_vec32_l2_squared_distance(PG_FUNCTION_ARGS) | |
| 221 | { | ||
| 222 | ✗ | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 223 | ✗ | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 224 | |||
| 225 | ✗ | vs_pg_check_dims_match(a->dim, b->dim); | |
| 226 | |||
| 227 | ✗ | Vec32Ref ra = Vec32ToRef(a); | |
| 228 | ✗ | Vec32Ref rb = Vec32ToRef(b); | |
| 229 | ✗ | double res = (double)vs_distance_l2(ra, rb); | |
| 230 | |||
| 231 | ✗ | PG_RETURN_FLOAT8(res); | |
| 232 | } | ||
| 233 | |||
| 234 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_negative_inner_product); | |
| 235 | |||
| 236 | Datum | ||
| 237 | 1 | vs_vec32_negative_inner_product(PG_FUNCTION_ARGS) | |
| 238 | { | ||
| 239 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 240 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 241 | |||
| 242 | 1 | vs_pg_check_dims_match(a->dim, b->dim); | |
| 243 | |||
| 244 | 1 | Vec32Ref ra = Vec32ToRef(a); | |
| 245 | 1 | Vec32Ref rb = Vec32ToRef(b); | |
| 246 | 1 | double res = (double)vs_distance_ip(ra, rb); | |
| 247 | |||
| 248 | 1 | PG_RETURN_FLOAT8(res); | |
| 249 | } | ||
| 250 | |||
| 251 | /* ---------------------------------------------------------------- | ||
| 252 | * Comparison functions (for btree opclass) | ||
| 253 | * ---------------------------------------------------------------- */ | ||
| 254 | |||
| 255 | static int | ||
| 256 | 1216462 | vec32_cmp_internal(Vec32 *a, Vec32 *b) | |
| 257 | { | ||
| 258 | 1216462 | int min_dim = (a->dim < b->dim) ? a->dim : b->dim; | |
| 259 | |||
| 260 |
2/2✓ Branch 0 taken 1311084 times.
✓ Branch 1 taken 11 times.
|
1311095 | for (int i = 0; i < min_dim; i++) |
| 261 | { | ||
| 262 |
2/2✓ Branch 0 taken 720829 times.
✓ Branch 1 taken 590255 times.
|
1311084 | if (a->x[i] < b->x[i]) |
| 263 | return -1; | ||
| 264 |
2/2✓ Branch 0 taken 94633 times.
✓ Branch 1 taken 626196 times.
|
720829 | if (a->x[i] > b->x[i]) |
| 265 | return 1; | ||
| 266 | } | ||
| 267 | |||
| 268 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (a->dim < b->dim) |
| 269 | return -1; | ||
| 270 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (a->dim > b->dim) |
| 271 | ✗ | return 1; | |
| 272 | |||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 276 | 19 | PG_FUNCTION_INFO_V1(vs_vec32_cmp); | |
| 277 | |||
| 278 | Datum | ||
| 279 | 1216456 | vs_vec32_cmp(PG_FUNCTION_ARGS) | |
| 280 | { | ||
| 281 | 1216456 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 282 | 1216456 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 283 | 1216456 | PG_RETURN_INT32(vec32_cmp_internal(a, b)); | |
| 284 | } | ||
| 285 | |||
| 286 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_lt); | |
| 287 | |||
| 288 | Datum | ||
| 289 | 1 | vs_vec32_lt(PG_FUNCTION_ARGS) | |
| 290 | { | ||
| 291 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 292 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 293 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | PG_RETURN_BOOL(vec32_cmp_internal(a, b) < 0); |
| 294 | } | ||
| 295 | |||
| 296 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_le); | |
| 297 | |||
| 298 | Datum | ||
| 299 | 1 | vs_vec32_le(PG_FUNCTION_ARGS) | |
| 300 | { | ||
| 301 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 302 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | PG_RETURN_BOOL(vec32_cmp_internal(a, b) <= 0); |
| 304 | } | ||
| 305 | |||
| 306 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_eq); | |
| 307 | |||
| 308 | Datum | ||
| 309 | 1 | vs_vec32_eq(PG_FUNCTION_ARGS) | |
| 310 | { | ||
| 311 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 312 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | PG_RETURN_BOOL(vec32_cmp_internal(a, b) == 0); |
| 314 | } | ||
| 315 | |||
| 316 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_ne); | |
| 317 | |||
| 318 | Datum | ||
| 319 | 1 | vs_vec32_ne(PG_FUNCTION_ARGS) | |
| 320 | { | ||
| 321 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 322 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 323 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | PG_RETURN_BOOL(vec32_cmp_internal(a, b) != 0); |
| 324 | } | ||
| 325 | |||
| 326 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_ge); | |
| 327 | |||
| 328 | Datum | ||
| 329 | 1 | vs_vec32_ge(PG_FUNCTION_ARGS) | |
| 330 | { | ||
| 331 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 332 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | PG_RETURN_BOOL(vec32_cmp_internal(a, b) >= 0); |
| 334 | } | ||
| 335 | |||
| 336 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_gt); | |
| 337 | |||
| 338 | Datum | ||
| 339 | 1 | vs_vec32_gt(PG_FUNCTION_ARGS) | |
| 340 | { | ||
| 341 | 1 | Vec32 *a = PG_GETARG_VEC32_P(0); | |
| 342 | 1 | Vec32 *b = PG_GETARG_VEC32_P(1); | |
| 343 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | PG_RETURN_BOOL(vec32_cmp_internal(a, b) > 0); |
| 344 | } | ||
| 345 | |||
| 346 | /* ---------------------------------------------------------------- | ||
| 347 | * Utility functions | ||
| 348 | * ---------------------------------------------------------------- */ | ||
| 349 | |||
| 350 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_dims); | |
| 351 | |||
| 352 | Datum | ||
| 353 | 1 | vs_vec32_dims(PG_FUNCTION_ARGS) | |
| 354 | { | ||
| 355 | 1 | Vec32 *v = PG_GETARG_VEC32_P(0); | |
| 356 | 1 | PG_RETURN_INT32(v->dim); | |
| 357 | } | ||
| 358 | |||
| 359 | 9 | PG_FUNCTION_INFO_V1(vs_pg_vec32_norm); | |
| 360 | |||
| 361 | Datum | ||
| 362 | 1 | vs_pg_vec32_norm(PG_FUNCTION_ARGS) | |
| 363 | { | ||
| 364 | 1 | Vec32 *v = PG_GETARG_VEC32_P(0); | |
| 365 | 1 | double res = 0.0; | |
| 366 | |||
| 367 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
|
3 | for (int i = 0; i < v->dim; i++) |
| 368 | 2 | res += (double)v->x[i] * (double)v->x[i]; | |
| 369 | |||
| 370 | 1 | PG_RETURN_FLOAT8(sqrt(res)); | |
| 371 | } | ||
| 372 | |||
| 373 | /* ---------------------------------------------------------------- | ||
| 374 | * Cast functions | ||
| 375 | * ---------------------------------------------------------------- */ | ||
| 376 | |||
| 377 | 48 | PG_FUNCTION_INFO_V1(vs_vec32); | |
| 378 | |||
| 379 | Datum | ||
| 380 | 138776 | vs_vec32(PG_FUNCTION_ARGS) | |
| 381 | { | ||
| 382 | 138776 | Vec32 *v = PG_GETARG_VEC32_P(0); | |
| 383 | 138776 | int32 typmod = PG_GETARG_INT32(1); | |
| 384 | |||
| 385 | 138776 | vs_pg_check_expected_dim(v->dim, typmod); | |
| 386 | |||
| 387 | 138775 | PG_RETURN_VEC32_P(v); | |
| 388 | } | ||
| 389 | |||
| 390 | 31 | PG_FUNCTION_INFO_V1(vs_array_to_vec32); | |
| 391 | |||
| 392 | Datum | ||
| 393 | 46460 | vs_array_to_vec32(PG_FUNCTION_ARGS) | |
| 394 | { | ||
| 395 | 46460 | ArrayType *arr = PG_GETARG_ARRAYTYPE_P(0); | |
| 396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46460 times.
|
46460 | int32 typmod = PG_GETARG_INT32(1); |
| 397 | 46460 | Oid elemtype; | |
| 398 | 46460 | int ndims; | |
| 399 | 46460 | int *dims; | |
| 400 | 46460 | int dim; | |
| 401 | 46460 | Datum *elems; | |
| 402 | 46460 | bool *nulls; | |
| 403 | 46460 | int nelems; | |
| 404 | |||
| 405 | 46460 | elemtype = ARR_ELEMTYPE(arr); | |
| 406 | 46460 | ndims = ARR_NDIM(arr); | |
| 407 | |||
| 408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46460 times.
|
46460 | if (ndims > 1) |
| 409 | ✗ | ereport(ERROR, | |
| 410 | (errcode(ERRCODE_DATA_EXCEPTION), | ||
| 411 | errmsg("array must be 1-D"))); | ||
| 412 | |||
| 413 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 46459 times.
|
46460 | if (ndims == 0) |
| 414 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ereport(ERROR, |
| 415 | (errcode(ERRCODE_DATA_EXCEPTION), | ||
| 416 | errmsg("array must not be empty"))); | ||
| 417 | |||
| 418 | 46459 | dims = ARR_DIMS(arr); | |
| 419 | 46459 | dim = dims[0]; | |
| 420 | |||
| 421 | 46459 | vs_pg_check_dim_valid(dim); | |
| 422 | 46459 | vs_pg_check_expected_dim(dim, typmod); | |
| 423 | |||
| 424 | /* | ||
| 425 | * Only the two element types the SQL overloads declare. Deriving the | ||
| 426 | * element shape from "not float4" would hand deconstruct_array the | ||
| 427 | * wrong length for any other type. | ||
| 428 | */ | ||
| 429 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46459 times.
|
46459 | if (elemtype != FLOAT4OID && elemtype != FLOAT8OID) |
| 430 | ✗ | ereport(ERROR, | |
| 431 | (errcode(ERRCODE_DATATYPE_MISMATCH), | ||
| 432 | errmsg("unsupported array element type"))); | ||
| 433 | |||
| 434 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 46422 times.
|
46496 | deconstruct_array( |
| 435 | arr, | ||
| 436 | elemtype, | ||
| 437 | (elemtype == FLOAT4OID) ? sizeof(float4) : sizeof(float8), | ||
| 438 | (elemtype == FLOAT4OID) ? true : FLOAT8PASSBYVAL, | ||
| 439 | (elemtype == FLOAT4OID) ? TYPALIGN_INT : TYPALIGN_DOUBLE, | ||
| 440 | &elems, | ||
| 441 | &nulls, | ||
| 442 | &nelems); | ||
| 443 | |||
| 444 | 46459 | Vec32 *result = vs_pg_vec32_alloc(dim); | |
| 445 | |||
| 446 |
2/2✓ Branch 1 taken 3922072 times.
✓ Branch 2 taken 46458 times.
|
3968530 | for (int i = 0; i < dim; i++) |
| 447 | { | ||
| 448 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3922071 times.
|
3922072 | if (nulls[i]) |
| 449 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ereport(ERROR, |
| 450 | (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), | ||
| 451 | errmsg("array must not contain nulls"))); | ||
| 452 | |||
| 453 | 3922071 | float val; | |
| 454 |
2/2✓ Branch 0 taken 3921924 times.
✓ Branch 1 taken 147 times.
|
3922071 | if (elemtype == FLOAT4OID) |
| 455 | 3921924 | val = DatumGetFloat4(elems[i]); | |
| 456 | else | ||
| 457 | 147 | val = (float)DatumGetFloat8(elems[i]); | |
| 458 | |||
| 459 | 3922071 | vs_pg_check_value_finite(val); | |
| 460 | 3922071 | result->x[i] = val; | |
| 461 | } | ||
| 462 | |||
| 463 | 46458 | PG_RETURN_VEC32_P(result); | |
| 464 | } | ||
| 465 | |||
| 466 | 9 | PG_FUNCTION_INFO_V1(vs_vec32_to_float4); | |
| 467 | |||
| 468 | Datum | ||
| 469 | 1 | vs_vec32_to_float4(PG_FUNCTION_ARGS) | |
| 470 | { | ||
| 471 | 1 | Vec32 *v = PG_GETARG_VEC32_P(0); | |
| 472 | 1 | Datum *elems = (Datum *)palloc(v->dim * sizeof(Datum)); | |
| 473 | |||
| 474 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
|
4 | for (int i = 0; i < v->dim; i++) |
| 475 | 3 | elems[i] = Float4GetDatum(v->x[i]); | |
| 476 | |||
| 477 | 1 | ArrayType *result = construct_array( | |
| 478 | elems, v->dim, FLOAT4OID, sizeof(float4), true, TYPALIGN_INT); | ||
| 479 | |||
| 480 | 1 | pfree(elems); | |
| 481 | |||
| 482 | 1 | PG_RETURN_ARRAYTYPE_P(result); | |
| 483 | } | ||
| 484 |