aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_func.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-04-09 20:35:55 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-04-09 20:35:55 +0000
commitf2d70d32ebd6c38d4fe93c1a684f5f29e5e76938 (patch)
tree5d041018177cdf6e9ca3ef0cc2eafac580a5bb0b /src/backend/parser/parse_func.c
parentc419c224142eb4bbf6e9a47d2d3626f212fda0fc (diff)
downloadpostgresql-f2d70d32ebd6c38d4fe93c1a684f5f29e5e76938.tar.gz
postgresql-f2d70d32ebd6c38d4fe93c1a684f5f29e5e76938.zip
Functions live in namespaces. Qualified function names work, eg
SELECT schema1.func2(...). Aggregate names can be qualified at the syntactic level, but the qualification is ignored for the moment.
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r--src/backend/parser/parse_func.c146
1 files changed, 110 insertions, 36 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 578402fd255..a86195126ff 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.124 2002/04/06 06:59:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.125 2002/04/09 20:35:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -54,7 +54,7 @@ static int match_argtypes(int nargs,
static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid);
static FuncCandidateList func_select_candidate(int nargs, Oid *input_typeids,
FuncCandidateList candidates);
-static int agg_get_candidates(char *aggname, Oid typeId,
+static int agg_get_candidates(List *aggname, Oid typeId,
FuncCandidateList *candidates);
static Oid agg_select_candidate(Oid typeid, FuncCandidateList candidates);
@@ -64,22 +64,22 @@ static Oid agg_select_candidate(Oid typeid, FuncCandidateList candidates);
*
* For historical reasons, Postgres tries to treat the notations tab.col
* and col(tab) as equivalent: if a single-argument function call has an
- * argument of complex type and the function name matches any attribute
- * of the type, we take it as a column projection.
+ * argument of complex type and the (unqualified) function name matches
+ * any attribute of the type, we take it as a column projection.
*
* Hence, both cases come through here. The is_column parameter tells us
* which syntactic construct is actually being dealt with, but this is
* intended to be used only to deliver an appropriate error message,
* not to affect the semantics. When is_column is true, we should have
- * a single argument (the putative table), function name equal to the
- * column name, and no aggregate decoration.
+ * a single argument (the putative table), unqualified function name
+ * equal to the column name, and no aggregate decoration.
*
* In the function-call case, the argument expressions have been transformed
* already. In the column case, we may get either a transformed expression
* or a RangeVar node as argument.
*/
Node *
-ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
+ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool is_column)
{
Oid rettype;
@@ -113,23 +113,28 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
{
first_arg = lfirst(fargs);
if (first_arg == NULL) /* should not happen */
- elog(ERROR, "Function '%s' does not allow NULL input", funcname);
+ elog(ERROR, "Function '%s' does not allow NULL input",
+ NameListToString(funcname));
}
/*
* check for column projection: if function has one argument, and that
- * argument is of complex type, then the function could be a projection.
+ * argument is of complex type, and function name is not qualified,
+ * then the "function call" could be a projection. We also check
+ * that there wasn't any aggregate decoration.
*/
- /* We only have one parameter, and it's not got aggregate decoration */
- if (nargs == 1 && !must_be_agg)
+ if (nargs == 1 && !must_be_agg && length(funcname) == 1)
{
+ char *cname = strVal(lfirst(funcname));
+
/* Is it a not-yet-transformed RangeVar node? */
if (IsA(first_arg, RangeVar))
{
/* First arg is a relation. This could be a projection. */
refname = ((RangeVar *) first_arg)->relname;
- retval = qualifiedNameToVar(pstate, refname, funcname, true);
+ /* XXX WRONG: ignores possible qualification of argument */
+ retval = qualifiedNameToVar(pstate, refname, cname, true);
if (retval)
return retval;
}
@@ -140,9 +145,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
* ParseComplexProjection can't handle the projection, we have
* to keep going.
*/
- retval = ParseComplexProjection(pstate,
- funcname,
- first_arg);
+ retval = ParseComplexProjection(pstate, cname, first_arg);
if (retval)
return retval;
}
@@ -175,7 +178,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
/* try for exact match first... */
if (SearchSysCacheExists(AGGNAME,
- PointerGetDatum(funcname),
+ PointerGetDatum(strVal(llast(funcname))),
ObjectIdGetDatum(basetype),
0, 0))
return (Node *) ParseAgg(pstate, funcname, basetype,
@@ -183,7 +186,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
/* check for aggregate-that-accepts-any-type (eg, COUNT) */
if (SearchSysCacheExists(AGGNAME,
- PointerGetDatum(funcname),
+ PointerGetDatum(strVal(llast(funcname))),
ObjectIdGetDatum(0),
0, 0))
return (Node *) ParseAgg(pstate, funcname, 0,
@@ -211,7 +214,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
{
/* Multiple possible matches --- give up */
elog(ERROR, "Unable to select an aggregate function %s(%s)",
- funcname, format_type_be(basetype));
+ NameListToString(funcname), format_type_be(basetype));
}
}
@@ -222,7 +225,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
* function could not have been meant.
*/
elog(ERROR, "There is no aggregate function %s(%s)",
- funcname, format_type_be(basetype));
+ NameListToString(funcname), format_type_be(basetype));
}
}
@@ -275,7 +278,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
*/
if (is_column)
elog(ERROR, "No such attribute %s.%s",
- refname, funcname);
+ refname, strVal(lfirst(funcname)));
else
{
elog(ERROR, "Cannot pass result of sub-select or join %s to a function",
@@ -329,7 +332,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
* give an error message that is appropriate for that case.
*/
if (is_column)
- elog(ERROR, "Attribute \"%s\" not found", funcname);
+ elog(ERROR, "Attribute \"%s\" not found",
+ strVal(lfirst(funcname)));
/* Else generate a detailed complaint */
func_error(NULL, funcname, nargs, oid_array,
"Unable to identify a function that satisfies the "
@@ -373,7 +377,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
static int
-agg_get_candidates(char *aggname,
+agg_get_candidates(List *aggname,
Oid typeId,
FuncCandidateList *candidates)
{
@@ -388,7 +392,7 @@ agg_get_candidates(char *aggname,
ScanKeyEntryInitialize(&aggKey[0], 0,
Anum_pg_aggregate_aggname,
F_NAMEEQ,
- NameGetDatum(aggname));
+ NameGetDatum(strVal(llast(aggname))));
pg_aggregate_desc = heap_openr(AggregateRelationName, AccessShareLock);
pg_aggregate_scan = systable_beginscan(pg_aggregate_desc,
@@ -862,7 +866,7 @@ func_select_candidate(int nargs,
* d) if the answer is zero, try the next array from vector #1
*/
FuncDetailCode
-func_get_detail(char *funcname,
+func_get_detail(List *funcname,
List *fargs,
int nargs,
Oid *argtypes,
@@ -875,7 +879,7 @@ func_get_detail(char *funcname,
FuncCandidateList best_candidate;
/* Get list of possible candidates from namespace search */
- function_typeids = FuncnameGetCandidates(makeList1(makeString(funcname)), nargs);
+ function_typeids = FuncnameGetCandidates(funcname, nargs);
/*
* See if there is an exact match
@@ -917,15 +921,11 @@ func_get_detail(char *funcname,
if (nargs == 1)
{
Oid targetType;
+ TypeName *tn = makeNode(TypeName);
- /* XXX WRONG: need to search searchpath for name; but little
- * point in fixing before we revise this code for qualified
- * funcnames too.
- */
- targetType = GetSysCacheOid(TYPENAMENSP,
- PointerGetDatum(funcname),
- ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
- 0, 0);
+ tn->names = funcname;
+ tn->typmod = -1;
+ targetType = LookupTypeName(tn);
if (OidIsValid(targetType) &&
!ISCOMPLEX(targetType))
{
@@ -1409,7 +1409,7 @@ ParseComplexProjection(ParseState *pstate,
* argument types
*/
void
-func_error(const char *caller, const char *funcname,
+func_error(const char *caller, List *funcname,
int nargs, const Oid *argtypes,
const char *msg)
{
@@ -1439,13 +1439,87 @@ func_error(const char *caller, const char *funcname,
if (caller == NULL)
{
elog(ERROR, "Function '%s(%s)' does not exist%s%s",
- funcname, p,
+ NameListToString(funcname), p,
((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : ""));
}
else
{
elog(ERROR, "%s: function '%s(%s)' does not exist%s%s",
- caller, funcname, p,
+ caller, NameListToString(funcname), p,
((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : ""));
}
}
+
+/*
+ * LookupFuncName
+ * Given a possibly-qualified function name and a set of argument types,
+ * look up the function. Returns InvalidOid if no such function.
+ *
+ * If the function name is not schema-qualified, it is sought in the current
+ * namespace search path.
+ */
+Oid
+LookupFuncName(List *funcname, int nargs, const Oid *argtypes)
+{
+ FuncCandidateList clist;
+
+ clist = FuncnameGetCandidates(funcname, nargs);
+
+ while (clist)
+ {
+ if (memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0)
+ return clist->oid;
+ clist = clist->next;
+ }
+
+ return InvalidOid;
+}
+
+/*
+ * LookupFuncNameTypeNames
+ * Like LookupFuncName, but the argument types are specified by a
+ * list of TypeName nodes. Also, if we fail to find the function
+ * and caller is not NULL, then an error is reported via func_error.
+ *
+ * "opaque" is accepted as a typename only if opaqueOK is true.
+ */
+Oid
+LookupFuncNameTypeNames(List *funcname, List *argtypes, bool opaqueOK,
+ const char *caller)
+{
+ Oid funcoid;
+ Oid argoids[FUNC_MAX_ARGS];
+ int argcount;
+ int i;
+
+ MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid));
+ argcount = length(argtypes);
+ if (argcount > FUNC_MAX_ARGS)
+ elog(ERROR, "functions cannot have more than %d arguments",
+ FUNC_MAX_ARGS);
+
+ for (i = 0; i < argcount; i++)
+ {
+ TypeName *t = (TypeName *) lfirst(argtypes);
+
+ argoids[i] = LookupTypeName(t);
+ if (!OidIsValid(argoids[i]))
+ {
+ char *typnam = TypeNameToString(t);
+
+ if (opaqueOK && strcmp(typnam, "opaque") == 0)
+ argoids[i] = InvalidOid;
+ else
+ elog(ERROR, "Type \"%s\" does not exist", typnam);
+ }
+
+ argtypes = lnext(argtypes);
+ }
+
+ funcoid = LookupFuncName(funcname, argcount, argoids);
+
+ if (!OidIsValid(funcoid) && caller != NULL)
+ func_error(caller, funcname, argcount, argoids, NULL);
+
+ return funcoid;
+}