aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_func.c
diff options
context:
space:
mode:
authorThomas G. Lockhart <lockhart@fourpalms.org>1998-05-29 14:00:24 +0000
committerThomas G. Lockhart <lockhart@fourpalms.org>1998-05-29 14:00:24 +0000
commit8536c962614a55d33baa283a7901bb167a43978a (patch)
treed674201859f82cf92296a5fc079b5bfcaf1c4f8b /src/backend/parser/parse_func.c
parent329083a97e2b5de1191f50451a253c224c833605 (diff)
downloadpostgresql-8536c962614a55d33baa283a7901bb167a43978a.tar.gz
postgresql-8536c962614a55d33baa283a7901bb167a43978a.zip
Do type conversion to match columns in UNION clauses.
Currently force the type to match the _first_ select in the union. Move oper_select_candidate() from parse_func.c to parse_oper.c. Throw error inside of oper_inexact() if no match for binary operators. Check more carefully that types can be coerced even if there is only one candidate operator in oper_inexact(). Fix up error messages for more uniform look. Remove unused code. Fix up comments.
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r--src/backend/parser/parse_func.c472
1 files changed, 16 insertions, 456 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index a4e34d6791b..66453634aec 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.17 1998/05/09 23:29:53 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.18 1998/05/29 14:00:21 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -62,10 +62,6 @@ func_get_detail(char *funcname,
Oid *rettype, /* return value */
bool *retset, /* return value */
Oid **true_typeids);
-Oid *
-func_select_candidate(int nargs,
- Oid *input_typeids,
- CandidateList candidates);
static Oid funcid_get_rettype(Oid funcid);
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
static void
@@ -166,7 +162,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
{
first_arg = lfirst(fargs);
if (first_arg == NULL)
- elog(ERROR, "function '%s' does not allow NULL input", funcname);
+ elog(ERROR, "Function '%s' does not allow NULL input", funcname);
}
/*
@@ -234,8 +230,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
heap_close(rd);
}
else
- elog(ERROR,
- "Type '%s' is not a relation type",
+ elog(ERROR, "Type '%s' is not a relation type",
typeidTypeName(toid));
argrelid = typeidTypeRelid(toid);
@@ -342,8 +337,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
* cast them - jolly
*/
if (exprType(pair) == UNKNOWNOID && !IsA(pair, Const))
- elog(ERROR, "ParseFuncOrColumn: no function named '%s'"
- " that takes in an unknown type as argument #%d", funcname, nargs);
+ elog(ERROR, "There is no function '%s'"
+ " with argument #%d of type UNKNOWN",
+ funcname, nargs);
else
toid = exprType(pair);
}
@@ -385,7 +381,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
}
if (!exists)
- elog(ERROR, "no such attribute or function '%s'", funcname);
+ elog(ERROR, "No such attribute or function '%s'", funcname);
/* got it */
funcnode = makeNode(Func);
@@ -443,7 +439,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
Assert(length(fargs) == 1);
seq = (Const *) lfirst(fargs);
if (!IsA((Node *) seq, Const))
- elog(ERROR, "%s: only constant sequence names are acceptable", funcname);
+ elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname);
seqname = lower((text *) DatumGetPointer(seq->constvalue));
pfree(DatumGetPointer(seq->constvalue));
seq->constvalue = PointerGetDatum(seqname);
@@ -458,7 +454,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
pfree(seqrel);
if (funcid == F_NEXTVAL && pstate->p_in_where_clause)
- elog(ERROR, "nextval of a sequence in WHERE disallowed");
+ elog(ERROR, "Sequence function nextval is not allowed in WHERE clauses");
}
expr = makeNode(Expr);
@@ -497,7 +493,7 @@ funcid_get_rettype(Oid funcid)
0, 0, 0);
if (!HeapTupleIsValid(func_tuple))
- elog(ERROR, "function %d does not exist", funcid);
+ elog(ERROR, "Function OID %d does not exist", funcid);
funcrettype = (Oid)
((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
@@ -807,423 +803,6 @@ printf("func_select_candidate- column #%d input type is %s\n",
} /* func_select_candidate() */
-Oid *
-oper_select_candidate(int nargs,
- Oid *input_typeids,
- CandidateList candidates);
-
-#if FALSE
-/* oper_select_candidate()
- */
-Oid *
-oper_select_candidate(int nargs,
- Oid *input_typeids,
- CandidateList candidates)
-{
- CandidateList current_candidate;
- Oid *current_typeids;
- int unknownOids, textOids;
- int i;
-
- int ncandidates;
- int nbestMatch;
- Oid bestTypeId;
-
- unknownOids = TRUE;
- for (i = 0; i < nargs; i++)
- {
- unknownOids &= (input_typeids[i] == UNKNOWNOID);
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: argument #%d type is %s\n",
- i, typeidTypeName(input_typeids[i]));
-#endif
- }
-
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- if (unknownOids)
- {
- textOids = TRUE;
- for (i = 0; i < nargs; i++)
- {
- textOids &= (current_typeids[i] == TEXTOID);
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: candidate argument #%d type is %s\n",
- i, typeidTypeName(current_typeids[i]));
-#endif
- }
- if (textOids)
- return(current_candidate->args);
- }
- }
-
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: no all-text operators found\n");
-#endif
-
- /* OK, there are multiple types here; let's see if we can choose... */
- nbestMatch = 0;
- bestTypeId = InvalidOid;
-
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- if (IS_HIGHEST_TYPE(input_typeids[0])
- && (input_typeids[0] == current_typeids[0])
- && IS_HIGHEST_TYPE(current_typeids[1])
- && can_coerce_type(1, &input_typeids[1], &current_typeids[1]))
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: (1) choose (%s,%s) -> (%s,%s)...\n",
- typeidTypeName(input_typeids[0]), typeidTypeName(input_typeids[1]),
- typeidTypeName(current_typeids[0]), typeidTypeName(current_typeids[1]));
-#endif
- return (current_candidate->args);
- }
- else if (IS_HIGHEST_TYPE(input_typeids[1])
- && (input_typeids[1] == current_typeids[1])
- && IS_HIGHEST_TYPE(current_typeids[0])
- && can_coerce_type(1, &input_typeids[0], &current_typeids[0]))
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: (2) choose (%s,%s) -> (%s,%s)...\n",
- typeidTypeName(input_typeids[0]), typeidTypeName(input_typeids[1]),
- typeidTypeName(current_typeids[0]), typeidTypeName(current_typeids[1]));
-#endif
- return (current_candidate->args);
- }
- else
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: (3) skip (%s,%s) -> (%s,%s)...\n",
- typeidTypeName(input_typeids[0]), typeidTypeName(input_typeids[1]),
- typeidTypeName(current_typeids[0]), typeidTypeName(current_typeids[1]));
-#endif
- }
- }
-
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- if ((input_typeids[0] == current_typeids[0])
- && can_coerce_type(1, &input_typeids[1], &current_typeids[1]))
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: (4) choose (%s,%s) -> (%s,%s)...\n",
- typeidTypeName(input_typeids[0]), typeidTypeName(input_typeids[1]),
- typeidTypeName(current_typeids[0]), typeidTypeName(current_typeids[1]));
-#endif
- return (current_candidate->args);
- }
- else if ((input_typeids[1] == current_typeids[1])
- && can_coerce_type(1, &input_typeids[0], &current_typeids[0]))
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: (5) choose (%s,%s) -> (%s,%s)...\n",
- typeidTypeName(input_typeids[0]), typeidTypeName(input_typeids[1]),
- typeidTypeName(current_typeids[0]), typeidTypeName(current_typeids[1]));
-#endif
- return (current_candidate->args);
- }
- else
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate: (3) skip (%s,%s) -> (%s,%s)...\n",
- typeidTypeName(input_typeids[0]), typeidTypeName(input_typeids[1]),
- typeidTypeName(current_typeids[0]), typeidTypeName(current_typeids[1]));
-#endif
- }
- }
-
- return (NULL);
-#if FALSE
- return (candidates->args);
-#endif
-} /* oper_select_candidate() */
-#endif
-
-
-/* oper_select_candidate()
- * Given the input argtype array and more than one candidate
- * for the function argtype array, attempt to resolve the conflict.
- * returns the selected argtype array if the conflict can be resolved,
- * otherwise returns NULL.
- *
- * If all input Oids are UNKNOWNOID, then try matching with TEXTOID.
- * Otherwise, could return first function arguments on list of candidates.
- * But for now, return NULL and make the user give a better hint.
- * - thomas 1998-03-17
- */
-Oid *
-oper_select_candidate(int nargs,
- Oid *input_typeids,
- CandidateList candidates)
-{
- CandidateList current_candidate;
- CandidateList last_candidate;
- Oid *current_typeids;
- int unknownOids;
- int i;
-
- int ncandidates;
- int nbestMatch,
- nmatch;
-
- CATEGORY slot_category,
- current_category;
- Oid slot_type,
- current_type;
-
-/*
- * Run through all candidates and keep those with the most matches
- * on explicit types. Keep all candidates if none match.
- */
- ncandidates = 0;
- nbestMatch = 0;
- last_candidate = NULL;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- nmatch = 0;
- for (i = 0; i < nargs; i++)
- {
- if ((input_typeids[i] != UNKNOWNOID)
- && (current_typeids[i] == input_typeids[i]))
- {
- nmatch++;
- }
- }
-
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- candidate has %d matches\n", nmatch);
-#endif
- if ((nmatch > nbestMatch) || (last_candidate == NULL))
- {
- nbestMatch = nmatch;
- candidates = current_candidate;
- last_candidate = current_candidate;
- ncandidates = 1;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- choose candidate as best match\n");
-#endif
- }
- else if (nmatch == nbestMatch)
- {
- last_candidate->next = current_candidate;
- last_candidate = current_candidate;
- ncandidates++;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- choose candidate as possible match\n");
-#endif
- }
- else
- {
- last_candidate->next = NULL;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- reject candidate as possible match\n");
-#endif
- }
- }
-
- if (ncandidates <= 1)
- return ((ncandidates == 1)? candidates->args: NULL);
-
-/*
- * Now look for candidates which allow coersion and are preferred types.
- * Keep all candidates if none match.
- */
- ncandidates = 0;
- nbestMatch = 0;
- last_candidate = NULL;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- nmatch = 0;
- for (i = 0; i < nargs; i++)
- {
- current_category = TypeCategory(current_typeids[i]);
- if (input_typeids[i] != UNKNOWNOID)
- {
- if (current_typeids[i] == input_typeids[i])
- {
- nmatch++;
- }
- else if (IsPreferredType(current_category, current_typeids[i])
- && can_coerce_type(1, &input_typeids[i], &current_typeids[i]))
- {
- nmatch++;
- }
- }
- }
-
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- candidate has %d matches\n", nmatch);
-#endif
- if ((nmatch > nbestMatch) || (last_candidate == NULL))
- {
- nbestMatch = nmatch;
- candidates = current_candidate;
- last_candidate = current_candidate;
- ncandidates = 1;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- choose candidate as best match\n");
-#endif
- }
- else if (nmatch == nbestMatch)
- {
- last_candidate->next = current_candidate;
- last_candidate = current_candidate;
- ncandidates++;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- choose candidate as possible match\n");
-#endif
- }
- else
- {
- last_candidate->next = NULL;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- reject candidate as possible match\n");
-#endif
- }
- }
-
- if (ncandidates <= 1)
- return ((ncandidates == 1)? candidates->args: NULL);
-
-/*
- * Still too many candidates?
- * Try assigning types for the unknown columns.
- */
- if (ncandidates > 1)
- {
- unknownOids = FALSE;
- current_type = UNKNOWNOID;
- for (i = 0; i < nargs; i++)
- {
- if (input_typeids[i] != UNKNOWNOID)
- {
- current_type = input_typeids[i];
- }
- else
- {
- unknownOids = TRUE;
- }
- }
-
- if (unknownOids && (current_type != UNKNOWNOID))
- {
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- nmatch = 0;
- for (i = 0; i < nargs; i++)
- {
- current_typeids = current_candidate->args;
- if ((current_type == current_typeids[i])
- || IS_BINARY_COMPATIBLE(current_type, current_typeids[i]))
- nmatch++;
- }
- if (nmatch == nargs)
- return (candidates->args);
- }
- }
-
- for (i = 0; i < nargs; i++)
- {
- if (input_typeids[i] == UNKNOWNOID)
- {
- slot_category = INVALID_TYPE;
- slot_type = InvalidOid;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- current_type = current_typeids[i];
- current_category = TypeCategory(current_typeids[i]);
- if (slot_category == InvalidOid)
- {
- slot_category = current_category;
- slot_type = current_type;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- assign column #%d first candidate slot type %s\n",
- i, typeidTypeName(current_type));
-#endif
- }
- else if (current_category != slot_category)
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- multiple possible types for column #%d; unable to choose candidate\n", i);
-#endif
- return NULL;
- }
- else if (current_type != slot_type)
- {
- if (IsPreferredType(slot_category, current_type))
- {
- slot_type = current_type;
- candidates = current_candidate;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- column #%d found preferred candidate type %s\n",
- i, typeidTypeName(slot_type));
-#endif
- }
- else
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- column #%d found possible candidate type %s\n",
- i, typeidTypeName(current_type));
-#endif
- }
- }
- }
-
- if (slot_type != InvalidOid)
- {
- input_typeids[i] = slot_type;
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- assign column #%d slot type %s\n",
- i, typeidTypeName(input_typeids[i]));
-#endif
- }
- }
- else
- {
-#ifdef PARSEDEBUG
-printf("oper_select_candidate- column #%d input type is %s\n",
- i, typeidTypeName(input_typeids[i]));
-#endif
- }
- }
-
- ncandidates = 0;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- ncandidates++;
- }
- }
-
- if (ncandidates == 1)
- return (candidates->args);
-
- return (NULL);
-} /* oper_select_candidate() */
-
-
/* func_get_detail()
* Find the named function in the system catalogs.
*
@@ -1331,22 +910,6 @@ func_get_detail(char *funcname,
}
}
-#if FALSE
- /* Last-ditch attempt
- * See if this is a single argument function with the function name
- * also a type name and the input argument and type name binary compatible...
- */
- if (!HeapTupleIsValid(ftup) && (nargs == 1))
- {
- Type ttup;
-
- if ((HeapTupleIsValid(ttup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(funcname), 0, 0, 0)))
- && IS_BINARY_COMPATIBLE(typeTypeId(ttup), oid_array[0]))
- {
- }
- }
-#endif
-
if (!HeapTupleIsValid(ftup))
{
Type tp;
@@ -1355,11 +918,8 @@ func_get_detail(char *funcname,
{
tp = typeidType(oid_array[0]);
if (typeTypeFlag(tp) == 'c')
- elog(ERROR, "no such attribute or function '%s'", funcname);
+ elog(ERROR, "func_get_detail: No such attribute or function '%s'", funcname);
}
-#if FALSE
- func_error(NULL, funcname, nargs, oid_array, NULL);
-#endif
}
else
{
@@ -1519,7 +1079,7 @@ find_inheritors(Oid relid, Oid **supervec)
/* save the type id, rather than the relation id */
if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
- elog(ERROR, "relid %d does not exist", qentry->sqe_relid);
+ elog(ERROR, "Relid %d does not exist", qentry->sqe_relid);
qentry->sqe_relid = typeTypeId(typenameType(RelationGetRelationName(rd)->data));
heap_close(rd);
@@ -1676,7 +1236,7 @@ setup_tlist(char *attname, Oid relid)
attno = get_attnum(relid, attname);
if (attno < 0)
- elog(ERROR, "cannot reference attribute '%s'"
+ elog(ERROR, "Cannot reference attribute '%s'"
" of tuple params/return values for functions", attname);
typeid = get_atttype(relid, attno);
@@ -1780,7 +1340,7 @@ ParseComplexProjection(ParseState *pstate,
}
else
{
- elog(ERROR, "Function '%s' has bad returntype %d",
+ elog(ERROR, "Function '%s' has bad return type %d",
funcname, argtype);
}
}
@@ -1849,7 +1409,7 @@ ParseComplexProjection(ParseState *pstate,
}
- elog(ERROR, "Function '%s' has bad returntype %d",
+ elog(ERROR, "Function '%s' has bad return type %d",
funcname, argtype);
break;
}
@@ -1918,7 +1478,7 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes, char *msg)
if (caller == NULL)
{
- elog(ERROR, "function '%s(%s)' does not exist%s%s",
+ elog(ERROR, "Function '%s(%s)' does not exist%s%s",
funcname, p, ((msg != NULL)? "\n\t": ""), ((msg != NULL)? msg: ""));
}
else