#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_transform.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "executor/executor.h"
#include "executor/functions.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "pgstat.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
void
interpret_function_parameter_list(ParseState *pstate,
List *parameters,
Oid languageOid,
ObjectType objtype,
oidvector **parameterTypes,
List **parameterTypes_list,
ArrayType **allParameterTypes,
ArrayType **parameterModes,
ArrayType **parameterNames,
List **inParameterNames_list,
List **parameterDefaults,
Oid *variadicArgType,
Oid *requiredResultType)
{
int parameterCount = list_length(parameters);
Oid *inTypes;
int inCount = 0;
Datum *allTypes;
Datum *paramModes;
Datum *paramNames;
int outCount = 0;
int varCount = 0;
bool have_names = false;
bool have_defaults = false;
ListCell *x;
int i;
*variadicArgType = InvalidOid;
*requiredResultType = InvalidOid;
inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
*parameterDefaults = NIL;
i = 0;
foreach(x, parameters)
{
FunctionParameter *fp = (FunctionParameter *) lfirst(x);
TypeName *t = fp->argType;
FunctionParameterMode fpmode = fp->mode;
bool isinput = false;
Oid toid;
Type typtup;
if (fpmode == FUNC_PARAM_DEFAULT)
fpmode = FUNC_PARAM_IN;
typtup = LookupTypeName(pstate, t, NULL, false);
if (typtup)
{
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
{
if (languageOid == SQLlanguageId)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SQL function cannot accept shell type %s",
TypeNameToString(t)),
parser_errposition(pstate, t->location)));
else if (objtype == OBJECT_AGGREGATE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate cannot accept shell type %s",
TypeNameToString(t)),
parser_errposition(pstate, t->location)));
else
ereport(NOTICE,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("argument type %s is only a shell",
TypeNameToString(t)),
parser_errposition(pstate, t->location)));
}
toid = typeTypeId(typtup);
ReleaseSysCache(typtup);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type %s does not exist",
TypeNameToString(t)),
parser_errposition(pstate, t->location)));
toid = InvalidOid;
}
if (t->setof)
{
if (objtype == OBJECT_AGGREGATE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregates cannot accept set arguments"),
parser_errposition(pstate, fp->location)));
else if (objtype == OBJECT_PROCEDURE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("procedures cannot accept set arguments"),
parser_errposition(pstate, fp->location)));
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("functions cannot accept set arguments"),
parser_errposition(pstate, fp->location)));
}
if (fpmode != FUNC_PARAM_OUT && fpmode != FUNC_PARAM_TABLE)
{
if (varCount > 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("VARIADIC parameter must be the last input parameter"),
parser_errposition(pstate, fp->location)));
inTypes[inCount++] = toid;
isinput = true;
if (parameterTypes_list)
*parameterTypes_list = lappend_oid(*parameterTypes_list, toid);
}
if (fpmode != FUNC_PARAM_IN && fpmode != FUNC_PARAM_VARIADIC)
{
if (objtype == OBJECT_PROCEDURE)
{
if (varCount > 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("VARIADIC parameter must be the last parameter"),
parser_errposition(pstate, fp->location)));
*requiredResultType = RECORDOID;
}
else if (outCount == 0)
*requiredResultType = toid;
outCount++;
}
if (fpmode == FUNC_PARAM_VARIADIC)
{
*variadicArgType = toid;
varCount++;
switch (toid)
{
case ANYARRAYOID:
case ANYCOMPATIBLEARRAYOID:
case ANYOID:
break;
default:
if (!OidIsValid(get_element_type(toid)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("VARIADIC parameter must be an array"),
parser_errposition(pstate, fp->location)));
break;
}
}
allTypes[i] = ObjectIdGetDatum(toid);
paramModes[i] = CharGetDatum(fpmode);
if (fp->name && fp->name[0])
{
ListCell *px;
foreach(px, parameters)
{
FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
FunctionParameterMode prevfpmode;
if (prevfp == fp)
break;
prevfpmode = prevfp->mode;
if (prevfpmode == FUNC_PARAM_DEFAULT)
prevfpmode = FUNC_PARAM_IN;
if ((fpmode == FUNC_PARAM_IN ||
fpmode == FUNC_PARAM_VARIADIC) &&
(prevfpmode == FUNC_PARAM_OUT ||
prevfpmode == FUNC_PARAM_TABLE))
continue;
if ((prevfpmode == FUNC_PARAM_IN ||
prevfpmode == FUNC_PARAM_VARIADIC) &&
(fpmode == FUNC_PARAM_OUT ||
fpmode == FUNC_PARAM_TABLE))
continue;
if (prevfp->name && prevfp->name[0] &&
strcmp(prevfp->name, fp->name) == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("parameter name \"%s\" used more than once",
fp->name),
parser_errposition(pstate, fp->location)));
}
paramNames[i] = CStringGetTextDatum(fp->name);
have_names = true;
}
if (inParameterNames_list)
*inParameterNames_list = lappend(*inParameterNames_list, makeString(fp->name ? fp->name : pstrdup("")));
if (fp->defexpr)
{
Node *def;
if (!isinput)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only input parameters can have default values"),
parser_errposition(pstate, fp->location)));
def = transformExpr(pstate, fp->defexpr,
EXPR_KIND_FUNCTION_DEFAULT);
def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
assign_expr_collations(pstate, def);
if (pstate->p_rtable != NIL ||
contain_var_clause(def))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("cannot use table references in parameter default value"),
parser_errposition(pstate, fp->location)));
*parameterDefaults = lappend(*parameterDefaults, def);
have_defaults = true;
}
else
{
if (isinput && have_defaults)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("input parameters after one with a default value must also have defaults"),
parser_errposition(pstate, fp->location)));
if (objtype == OBJECT_PROCEDURE && have_defaults)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("procedure OUT parameters cannot appear after one with a default value"),
parser_errposition(pstate, fp->location)));
}
i++;
}
*parameterTypes = buildoidvector(inTypes, inCount);
if (outCount > 0 || varCount > 0)
{
*allParameterTypes = construct_array_builtin(allTypes, parameterCount, OIDOID);
*parameterModes = construct_array_builtin(paramModes, parameterCount, CHAROID);
if (outCount > 1)
*requiredResultType = RECORDOID;
}
else
{
*allParameterTypes = NULL;
*parameterModes = NULL;
}
if (have_names)
{
for (i = 0; i < parameterCount; i++)
{
if (paramNames[i] == PointerGetDatum(NULL))
paramNames[i] = CStringGetTextDatum("");
}
*parameterNames = construct_array_builtin(paramNames, parameterCount, TEXTOID);
}
else
*parameterNames = NULL;
}
#ifdef NOT_USED
#endif