|
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-2014, PostgreSQL Global Development Group
|
8 | 8 | *
|
@@ -1356,3 +1356,116 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases)
|
1356 | 1356 |
|
1357 | 1357 | return tupdesc;
|
1358 | 1358 | }
|
| 1359 | + |
| 1360 | +/* |
| 1361 | + * extract_variadic_args |
| 1362 | + * |
| 1363 | + * Extract a set of argument values, types and NULL markers for a given |
| 1364 | + * input function which makes use of a VARIADIC input whose argument list |
| 1365 | + * depends on the caller context. When doing a VARIADIC call, the caller |
| 1366 | + * has provided one argument made of an array of values, so deconstruct the |
| 1367 | + * array data before using it for the next processing. If no VARIADIC call |
| 1368 | + * is used, just fill in the status data based on all the arguments given |
| 1369 | + * by the caller. |
| 1370 | + * |
| 1371 | + * This function returns the number of arguments generated, or -1 in the |
| 1372 | + * case of "VARIADIC NULL". |
| 1373 | + */ |
| 1374 | +int |
| 1375 | +extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, |
| 1376 | + bool convert_unknown, Datum **args, Oid **types, |
| 1377 | + bool **nulls) |
| 1378 | +{ |
| 1379 | + bool variadic = get_fn_expr_variadic(fcinfo->flinfo); |
| 1380 | + Datum *args_res; |
| 1381 | + bool *nulls_res; |
| 1382 | + Oid *types_res; |
| 1383 | + int nargs, i; |
| 1384 | + |
| 1385 | + *args = NULL; |
| 1386 | + *types = NULL; |
| 1387 | + *nulls = NULL; |
| 1388 | + |
| 1389 | + if (variadic) |
| 1390 | + { |
| 1391 | + ArrayType *array_in; |
| 1392 | + Oid element_type; |
| 1393 | + bool typbyval; |
| 1394 | + char typalign; |
| 1395 | + int16 typlen; |
| 1396 | + |
| 1397 | + Assert(PG_NARGS() == variadic_start + 1); |
| 1398 | + |
| 1399 | + if (PG_ARGISNULL(variadic_start)) |
| 1400 | + return -1; |
| 1401 | + |
| 1402 | + array_in = PG_GETARG_ARRAYTYPE_P(variadic_start); |
| 1403 | + element_type = ARR_ELEMTYPE(array_in); |
| 1404 | + |
| 1405 | + get_typlenbyvalalign(element_type, |
| 1406 | + &typlen, &typbyval, &typalign); |
| 1407 | + deconstruct_array(array_in, element_type, typlen, typbyval, |
| 1408 | + typalign, &args_res, &nulls_res, |
| 1409 | + &nargs); |
| 1410 | + |
| 1411 | + /* All the elements of the array have the same type */ |
| 1412 | + types_res = (Oid *) palloc0(nargs * sizeof(Oid)); |
| 1413 | + for (i = 0; i < nargs; i++) |
| 1414 | + types_res[i] = element_type; |
| 1415 | + } |
| 1416 | + else |
| 1417 | + { |
| 1418 | + nargs = PG_NARGS() - variadic_start; |
| 1419 | + Assert (nargs > 0); |
| 1420 | + nulls_res = (bool *) palloc0(nargs * sizeof(bool)); |
| 1421 | + args_res = (Datum *) palloc0(nargs * sizeof(Datum)); |
| 1422 | + types_res = (Oid *) palloc0(nargs * sizeof(Oid)); |
| 1423 | + |
| 1424 | + for (i = 0; i < nargs; i++) |
| 1425 | + { |
| 1426 | + nulls_res[i] = PG_ARGISNULL(i + variadic_start); |
| 1427 | + types_res[i] = get_fn_expr_argtype(fcinfo->flinfo, |
| 1428 | + i + variadic_start); |
| 1429 | + |
| 1430 | + /* |
| 1431 | + * Turn a constant (more or less literal) value that's of unknown |
| 1432 | + * type into text if required . Unknowns come in as a cstring |
| 1433 | + * pointer. |
| 1434 | + * Note: for functions declared as taking type "any", the parser |
| 1435 | + * will not do any type conversion on unknown-type literals (that |
| 1436 | + * is, undecorated strings or NULLs). |
| 1437 | + */ |
| 1438 | + if (convert_unknown && |
| 1439 | + types_res[i] == UNKNOWNOID && |
| 1440 | + get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start)) |
| 1441 | + { |
| 1442 | + types_res[i] = TEXTOID; |
| 1443 | + |
| 1444 | + if (PG_ARGISNULL(i + variadic_start)) |
| 1445 | + args_res[i] = (Datum) 0; |
| 1446 | + else |
| 1447 | + args_res[i] = |
| 1448 | + CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start)); |
| 1449 | + } |
| 1450 | + else |
| 1451 | + { |
| 1452 | + /* no conversion needed, just take the datum as given */ |
| 1453 | + args_res[i] = PG_GETARG_DATUM(i + variadic_start); |
| 1454 | + } |
| 1455 | + |
| 1456 | + if (!OidIsValid(types_res[i]) || |
| 1457 | + (convert_unknown && types_res[i] == UNKNOWNOID)) |
| 1458 | + ereport(ERROR, |
| 1459 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 1460 | + errmsg("could not determine data type for argument %d", |
| 1461 | + i + 1))); |
| 1462 | + } |
| 1463 | + } |
| 1464 | + |
| 1465 | + /* Fill in results */ |
| 1466 | + *args = args_res; |
| 1467 | + *nulls = nulls_res; |
| 1468 | + *types = types_res; |
| 1469 | + |
| 1470 | + return nargs; |
| 1471 | +} |
0 commit comments