|
2 | 2 | *
|
3 | 3 | * funcapi.c
|
4 | 4 | * Utility and convenience functions for fmgr functions that return
|
5 |
| - * sets and/or composite types. |
| 5 | + * sets and/or composite types, or deal with VARIADIC inputs. |
6 | 6 | *
|
7 | 7 | * Copyright (c) 2002-2017, PostgreSQL Global Development Group
|
8 | 8 | *
|
@@ -1397,3 +1397,116 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases)
|
1397 | 1397 |
|
1398 | 1398 | return tupdesc;
|
1399 | 1399 | }
|
| 1400 | + |
| 1401 | +/* |
| 1402 | + * extract_variadic_args |
| 1403 | + * |
| 1404 | + * Extract a set of argument values, types and NULL markers for a given |
| 1405 | + * input function which makes use of a VARIADIC input whose argument list |
| 1406 | + * depends on the caller context. When doing a VARIADIC call, the caller |
| 1407 | + * has provided one argument made of an array of values, so deconstruct the |
| 1408 | + * array data before using it for the next processing. If no VARIADIC call |
| 1409 | + * is used, just fill in the status data based on all the arguments given |
| 1410 | + * by the caller. |
| 1411 | + * |
| 1412 | + * This function returns the number of arguments generated, or -1 in the |
| 1413 | + * case of "VARIADIC NULL". |
| 1414 | + */ |
| 1415 | +int |
| 1416 | +extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, |
| 1417 | + bool convert_unknown, Datum **args, Oid **types, |
| 1418 | + bool **nulls) |
| 1419 | +{ |
| 1420 | + bool variadic = get_fn_expr_variadic(fcinfo->flinfo); |
| 1421 | + Datum *args_res; |
| 1422 | + bool *nulls_res; |
| 1423 | + Oid *types_res; |
| 1424 | + int nargs, i; |
| 1425 | + |
| 1426 | + *args = NULL; |
| 1427 | + *types = NULL; |
| 1428 | + *nulls = NULL; |
| 1429 | + |
| 1430 | + if (variadic) |
| 1431 | + { |
| 1432 | + ArrayType *array_in; |
| 1433 | + Oid element_type; |
| 1434 | + bool typbyval; |
| 1435 | + char typalign; |
| 1436 | + int16 typlen; |
| 1437 | + |
| 1438 | + Assert(PG_NARGS() == variadic_start + 1); |
| 1439 | + |
| 1440 | + if (PG_ARGISNULL(variadic_start)) |
| 1441 | + return -1; |
| 1442 | + |
| 1443 | + array_in = PG_GETARG_ARRAYTYPE_P(variadic_start); |
| 1444 | + element_type = ARR_ELEMTYPE(array_in); |
| 1445 | + |
| 1446 | + get_typlenbyvalalign(element_type, |
| 1447 | + &typlen, &typbyval, &typalign); |
| 1448 | + deconstruct_array(array_in, element_type, typlen, typbyval, |
| 1449 | + typalign, &args_res, &nulls_res, |
| 1450 | + &nargs); |
| 1451 | + |
| 1452 | + /* All the elements of the array have the same type */ |
| 1453 | + types_res = (Oid *) palloc0(nargs * sizeof(Oid)); |
| 1454 | + for (i = 0; i < nargs; i++) |
| 1455 | + types_res[i] = element_type; |
| 1456 | + } |
| 1457 | + else |
| 1458 | + { |
| 1459 | + nargs = PG_NARGS() - variadic_start; |
| 1460 | + Assert (nargs > 0); |
| 1461 | + nulls_res = (bool *) palloc0(nargs * sizeof(bool)); |
| 1462 | + args_res = (Datum *) palloc0(nargs * sizeof(Datum)); |
| 1463 | + types_res = (Oid *) palloc0(nargs * sizeof(Oid)); |
| 1464 | + |
| 1465 | + for (i = 0; i < nargs; i++) |
| 1466 | + { |
| 1467 | + nulls_res[i] = PG_ARGISNULL(i + variadic_start); |
| 1468 | + types_res[i] = get_fn_expr_argtype(fcinfo->flinfo, |
| 1469 | + i + variadic_start); |
| 1470 | + |
| 1471 | + /* |
| 1472 | + * Turn a constant (more or less literal) value that's of unknown |
| 1473 | + * type into text if required . Unknowns come in as a cstring |
| 1474 | + * pointer. |
| 1475 | + * Note: for functions declared as taking type "any", the parser |
| 1476 | + * will not do any type conversion on unknown-type literals (that |
| 1477 | + * is, undecorated strings or NULLs). |
| 1478 | + */ |
| 1479 | + if (convert_unknown && |
| 1480 | + types_res[i] == UNKNOWNOID && |
| 1481 | + get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start)) |
| 1482 | + { |
| 1483 | + types_res[i] = TEXTOID; |
| 1484 | + |
| 1485 | + if (PG_ARGISNULL(i + variadic_start)) |
| 1486 | + args_res[i] = (Datum) 0; |
| 1487 | + else |
| 1488 | + args_res[i] = |
| 1489 | + CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start)); |
| 1490 | + } |
| 1491 | + else |
| 1492 | + { |
| 1493 | + /* no conversion needed, just take the datum as given */ |
| 1494 | + args_res[i] = PG_GETARG_DATUM(i + variadic_start); |
| 1495 | + } |
| 1496 | + |
| 1497 | + if (!OidIsValid(types_res[i]) || |
| 1498 | + (convert_unknown && types_res[i] == UNKNOWNOID)) |
| 1499 | + ereport(ERROR, |
| 1500 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 1501 | + errmsg("could not determine data type for argument %d", |
| 1502 | + i + 1))); |
| 1503 | + } |
| 1504 | + } |
| 1505 | + |
| 1506 | + /* Fill in results */ |
| 1507 | + *args = args_res; |
| 1508 | + *nulls = nulls_res; |
| 1509 | + *types = types_res; |
| 1510 | + |
| 1511 | + return nargs; |
| 1512 | +} |
0 commit comments