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