diff options
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r-- | src/backend/parser/parse_oper.c | 935 |
1 files changed, 0 insertions, 935 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c deleted file mode 100644 index 663e83831b3..00000000000 --- a/src/backend/parser/parse_oper.c +++ /dev/null @@ -1,935 +0,0 @@ -/*------------------------------------------------------------------------- - * - * parse_oper.c - * handle operator things for parser - * - * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.57 2002/06/20 20:29:33 momjian Exp $ - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - -#include "access/genam.h" -#include "access/heapam.h" -#include "catalog/catname.h" -#include "catalog/indexing.h" -#include "catalog/namespace.h" -#include "catalog/pg_operator.h" -#include "parser/parse_coerce.h" -#include "parser/parse_func.h" -#include "parser/parse_oper.h" -#include "parser/parse_type.h" -#include "utils/builtins.h" -#include "utils/fmgroids.h" -#include "utils/syscache.h" - -static Oid binary_oper_exact(Oid arg1, Oid arg2, - FuncCandidateList candidates); -static Oid oper_select_candidate(int nargs, Oid *input_typeids, - FuncCandidateList candidates); -static void op_error(List *op, Oid arg1, Oid arg2); -static void unary_op_error(List *op, Oid arg, bool is_left_op); - - -/* - * LookupOperName - * Given a possibly-qualified operator name and exact input datatypes, - * look up the operator. Returns InvalidOid if no such operator. - * - * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for - * a postfix op. - * - * If the operator name is not schema-qualified, it is sought in the current - * namespace search path. - */ -Oid -LookupOperName(List *opername, Oid oprleft, Oid oprright) -{ - FuncCandidateList clist; - char oprkind; - - if (!OidIsValid(oprleft)) - oprkind = 'l'; - else if (!OidIsValid(oprright)) - oprkind = 'r'; - else - oprkind = 'b'; - - clist = OpernameGetCandidates(opername, oprkind); - - while (clist) - { - if (clist->args[0] == oprleft && clist->args[1] == oprright) - return clist->oid; - clist = clist->next; - } - - return InvalidOid; -} - -/* - * LookupOperNameTypeNames - * Like LookupOperName, but the argument types are specified by - * TypeName nodes. Also, if we fail to find the operator - * and caller is not NULL, then an error is reported. - * - * Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op. - */ -Oid -LookupOperNameTypeNames(List *opername, TypeName *oprleft, - TypeName *oprright, const char *caller) -{ - Oid operoid; - Oid leftoid, - rightoid; - - if (oprleft == NULL) - leftoid = InvalidOid; - else - { - leftoid = LookupTypeName(oprleft); - if (!OidIsValid(leftoid)) - elog(ERROR, "Type \"%s\" does not exist", - TypeNameToString(oprleft)); - } - if (oprright == NULL) - rightoid = InvalidOid; - else - { - rightoid = LookupTypeName(oprright); - if (!OidIsValid(rightoid)) - elog(ERROR, "Type \"%s\" does not exist", - TypeNameToString(oprright)); - } - - operoid = LookupOperName(opername, leftoid, rightoid); - - if (!OidIsValid(operoid) && caller != NULL) - { - if (oprleft == NULL) - elog(ERROR, "%s: Prefix operator '%s' for type '%s' does not exist", - caller, NameListToString(opername), - TypeNameToString(oprright)); - else if (oprright == NULL) - elog(ERROR, "%s: Postfix operator '%s' for type '%s' does not exist", - caller, NameListToString(opername), - TypeNameToString(oprleft)); - else - elog(ERROR, "%s: Operator '%s' for types '%s' and '%s' does not exist", - caller, NameListToString(opername), - TypeNameToString(oprleft), - TypeNameToString(oprright)); - } - - return operoid; -} - - -/* Select an ordering operator for the given datatype */ -Oid -any_ordering_op(Oid argtype) -{ - Oid order_opid; - - order_opid = compatible_oper_opid(makeList1(makeString("<")), - argtype, argtype, true); - if (!OidIsValid(order_opid)) - elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'" - "\n\tUse an explicit ordering operator or modify the query", - "<", format_type_be(argtype)); - return order_opid; -} - -/* given operator tuple, return the operator OID */ -Oid -oprid(Operator op) -{ - return op->t_data->t_oid; -} - -/* given operator tuple, return the underlying function's OID */ -Oid -oprfuncid(Operator op) -{ - Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op); - - return pgopform->oprcode; -} - - -/* binary_oper_exact() - * Check for an "exact" match to the specified operand types. - * - * If one operand is an unknown literal, assume it should be taken to be - * the same type as the other operand for this purpose. - */ -static Oid -binary_oper_exact(Oid arg1, Oid arg2, - FuncCandidateList candidates) -{ - /* Unspecified type for one of the arguments? then use the other */ - if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid)) - arg1 = arg2; - else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid)) - arg2 = arg1; - - while (candidates != NULL) - { - if (arg1 == candidates->args[0] && - arg2 == candidates->args[1]) - return candidates->oid; - candidates = candidates->next; - } - - return InvalidOid; -} - - -/* oper_select_candidate() - * Given the input argtype array and one or more candidates - * for the function argtype array, attempt to resolve the conflict. - * Returns the selected argtype array if the conflict can be resolved, - * otherwise returns NULL. - * - * By design, this is pretty similar to func_select_candidate in parse_func.c. - * However, we can do a couple of extra things here because we know we can - * have no more than two args to deal with. Also, the calling convention - * is a little different: we must prune away "candidates" that aren't actually - * coercion-compatible with the input types, whereas in parse_func.c that - * gets done by match_argtypes before func_select_candidate is called. - * - * This routine is new code, replacing binary_oper_select_candidate() - * which dates from v4.2/v1.0.x days. It tries very hard to match up - * operators with types, including allowing type coercions if necessary. - * The important thing is that the code do as much as possible, - * while _never_ doing the wrong thing, where "the wrong thing" would - * be returning an operator when other better choices are available, - * or returning an operator which is a non-intuitive possibility. - * - thomas 1998-05-21 - * - * The comments below came from binary_oper_select_candidate(), and - * illustrate the issues and choices which are possible: - * - thomas 1998-05-20 - * - * current wisdom holds that the default operator should be one in which - * both operands have the same type (there will only be one such - * operator) - * - * 7.27.93 - I have decided not to do this; it's too hard to justify, and - * it's easy enough to typecast explicitly - avi - * [the rest of this routine was commented out since then - ay] - * - * 6/23/95 - I don't complete agree with avi. In particular, casting - * floats is a pain for users. Whatever the rationale behind not doing - * this is, I need the following special case to work. - * - * In the WHERE clause of a query, if a float is specified without - * quotes, we treat it as float8. I added the float48* operators so - * that we can operate on float4 and float8. But now we have more than - * one matching operator if the right arg is unknown (eg. float - * specified with quotes). This break some stuff in the regression - * test where there are floats in quotes not properly casted. Below is - * the solution. In addition to requiring the operator operates on the - * same type for both operands [as in the code Avi originally - * commented out], we also require that the operators be equivalent in - * some sense. (see equivalentOpersAfterPromotion for details.) - * - ay 6/95 - */ -static Oid -oper_select_candidate(int nargs, - Oid *input_typeids, - FuncCandidateList candidates) -{ - FuncCandidateList current_candidate; - FuncCandidateList last_candidate; - Oid *current_typeids; - Oid current_type; - int unknownOids; - int i; - int ncandidates; - int nbestMatch, - nmatch; - CATEGORY slot_category[FUNC_MAX_ARGS], - current_category; - bool slot_has_preferred_type[FUNC_MAX_ARGS]; - bool resolved_unknowns; - - /* - * First, delete any candidates that cannot actually accept the given - * input types, whether directly or by coercion. (Note that - * can_coerce_type will assume that UNKNOWN inputs are coercible to - * anything, so candidates will not be eliminated on that basis.) - */ - ncandidates = 0; - last_candidate = NULL; - for (current_candidate = candidates; - current_candidate != NULL; - current_candidate = current_candidate->next) - { - if (can_coerce_type(nargs, input_typeids, current_candidate->args, - false)) - { - if (last_candidate == NULL) - { - candidates = current_candidate; - last_candidate = current_candidate; - ncandidates = 1; - } - else - { - last_candidate->next = current_candidate; - last_candidate = current_candidate; - ncandidates++; - } - } - /* otherwise, don't bother keeping this one... */ - } - - if (last_candidate) /* terminate rebuilt list */ - last_candidate->next = NULL; - - /* Done if no candidate or only one candidate survives */ - if (ncandidates == 0) - return InvalidOid; - if (ncandidates == 1) - return candidates->oid; - - /* - * Run through all candidates and keep those with the most matches on - * exact 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++; - } - - /* take this one as the best choice so far? */ - if ((nmatch > nbestMatch) || (last_candidate == NULL)) - { - nbestMatch = nmatch; - candidates = current_candidate; - last_candidate = current_candidate; - ncandidates = 1; - } - /* no worse than the last choice, so keep this one too? */ - else if (nmatch == nbestMatch) - { - last_candidate->next = current_candidate; - last_candidate = current_candidate; - ncandidates++; - } - /* otherwise, don't bother keeping this one... */ - } - - if (last_candidate) /* terminate rebuilt list */ - last_candidate->next = NULL; - - if (ncandidates == 1) - return candidates->oid; - - /* - * Still too many candidates? Run through all candidates and keep - * those with the most matches on exact types + binary-compatible - * 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) - { - if (IsBinaryCompatible(current_typeids[i], input_typeids[i])) - nmatch++; - } - } - - /* take this one as the best choice so far? */ - if ((nmatch > nbestMatch) || (last_candidate == NULL)) - { - nbestMatch = nmatch; - candidates = current_candidate; - last_candidate = current_candidate; - ncandidates = 1; - } - /* no worse than the last choice, so keep this one too? */ - else if (nmatch == nbestMatch) - { - last_candidate->next = current_candidate; - last_candidate = current_candidate; - ncandidates++; - } - /* otherwise, don't bother keeping this one... */ - } - - if (last_candidate) /* terminate rebuilt list */ - last_candidate->next = NULL; - - if (ncandidates == 1) - return candidates->oid; - - /* - * Still too many candidates? Now look for candidates which are - * preferred types at the args that will require coercion. 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_category = TypeCategory(current_typeids[i]); - if (current_typeids[i] == input_typeids[i] || - IsPreferredType(current_category, current_typeids[i])) - nmatch++; - } - } - - if ((nmatch > nbestMatch) || (last_candidate == NULL)) - { - nbestMatch = nmatch; - candidates = current_candidate; - last_candidate = current_candidate; - ncandidates = 1; - } - else if (nmatch == nbestMatch) - { - last_candidate->next = current_candidate; - last_candidate = current_candidate; - ncandidates++; - } - } - - if (last_candidate) /* terminate rebuilt list */ - last_candidate->next = NULL; - - if (ncandidates == 1) - return candidates->oid; - - /* - * Still too many candidates? Try assigning types for the unknown - * columns. - * - * First try: if we have an unknown and a non-unknown input, see whether - * there is a candidate all of whose input types are the same as the - * known input type (there can be at most one such candidate). If so, - * use that candidate. NOTE that this is cool only because operators - * can't have more than 2 args, so taking the last non-unknown as - * current_type can yield only one possibility if there is also an - * unknown. - */ - unknownOids = FALSE; - current_type = UNKNOWNOID; - for (i = 0; i < nargs; i++) - { - if ((input_typeids[i] != UNKNOWNOID) - && (input_typeids[i] != InvalidOid)) - 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) - { - current_typeids = current_candidate->args; - nmatch = 0; - for (i = 0; i < nargs; i++) - { - if (current_type == current_typeids[i]) - nmatch++; - } - if (nmatch == nargs) - return current_candidate->oid; - } - } - - /* - * Second try: same algorithm as for unknown resolution in - * parse_func.c. - * - * We do this by examining each unknown argument position to see if we - * can determine a "type category" for it. If any candidate has an - * input datatype of STRING category, use STRING category (this bias - * towards STRING is appropriate since unknown-type literals look like - * strings). Otherwise, if all the candidates agree on the type - * category of this argument position, use that category. Otherwise, - * fail because we cannot determine a category. - * - * If we are able to determine a type category, also notice whether any - * of the candidates takes a preferred datatype within the category. - * - * Having completed this examination, remove candidates that accept the - * wrong category at any unknown position. Also, if at least one - * candidate accepted a preferred type at a position, remove - * candidates that accept non-preferred types. - * - * If we are down to one candidate at the end, we win. - */ - resolved_unknowns = false; - for (i = 0; i < nargs; i++) - { - bool have_conflict; - - if (input_typeids[i] != UNKNOWNOID) - continue; - resolved_unknowns = true; /* assume we can do it */ - slot_category[i] = INVALID_TYPE; - slot_has_preferred_type[i] = false; - have_conflict = false; - 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_type); - if (slot_category[i] == INVALID_TYPE) - { - /* first candidate */ - slot_category[i] = current_category; - slot_has_preferred_type[i] = - IsPreferredType(current_category, current_type); - } - else if (current_category == slot_category[i]) - { - /* more candidates in same category */ - slot_has_preferred_type[i] |= - IsPreferredType(current_category, current_type); - } - else - { - /* category conflict! */ - if (current_category == STRING_TYPE) - { - /* STRING always wins if available */ - slot_category[i] = current_category; - slot_has_preferred_type[i] = - IsPreferredType(current_category, current_type); - } - else - { - /* - * Remember conflict, but keep going (might find - * STRING) - */ - have_conflict = true; - } - } - } - if (have_conflict && slot_category[i] != STRING_TYPE) - { - /* Failed to resolve category conflict at this position */ - resolved_unknowns = false; - break; - } - } - - if (resolved_unknowns) - { - /* Strip non-matching candidates */ - ncandidates = 0; - last_candidate = NULL; - for (current_candidate = candidates; - current_candidate != NULL; - current_candidate = current_candidate->next) - { - bool keepit = true; - - current_typeids = current_candidate->args; - for (i = 0; i < nargs; i++) - { - if (input_typeids[i] != UNKNOWNOID) - continue; - current_type = current_typeids[i]; - current_category = TypeCategory(current_type); - if (current_category != slot_category[i]) - { - keepit = false; - break; - } - if (slot_has_preferred_type[i] && - !IsPreferredType(current_category, current_type)) - { - keepit = false; - break; - } - } - if (keepit) - { - /* keep this candidate */ - last_candidate = current_candidate; - ncandidates++; - } - else - { - /* forget this candidate */ - if (last_candidate) - last_candidate->next = current_candidate->next; - else - candidates = current_candidate->next; - } - } - if (last_candidate) /* terminate rebuilt list */ - last_candidate->next = NULL; - } - - if (ncandidates == 1) - return candidates->oid; - - return InvalidOid; /* failed to determine a unique candidate */ -} /* oper_select_candidate() */ - - -/* oper() -- search for a binary operator - * Given operator name, types of arg1 and arg2, return oper struct. - * - * IMPORTANT: the returned operator (if any) is only promised to be - * coercion-compatible with the input datatypes. Do not use this if - * you need an exact- or binary-compatible match; see compatible_oper. - * - * If no matching operator found, return NULL if noError is true, - * raise an error if it is false. - * - * NOTE: on success, the returned object is a syscache entry. The caller - * must ReleaseSysCache() the entry when done with it. - */ -Operator -oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError) -{ - FuncCandidateList clist; - Oid operOid; - Oid inputOids[2]; - HeapTuple tup = NULL; - - /* Get binary operators of given name */ - clist = OpernameGetCandidates(opname, 'b'); - - /* No operators found? Then fail... */ - if (clist != NULL) - { - /* - * Check for an "exact" match. - */ - operOid = binary_oper_exact(ltypeId, rtypeId, clist); - if (!OidIsValid(operOid)) - { - /* - * Otherwise, search for the most suitable candidate. - */ - - /* Unspecified type for one of the arguments? then use the other */ - if (rtypeId == InvalidOid) - rtypeId = ltypeId; - else if (ltypeId == InvalidOid) - ltypeId = rtypeId; - inputOids[0] = ltypeId; - inputOids[1] = rtypeId; - operOid = oper_select_candidate(2, inputOids, clist); - } - if (OidIsValid(operOid)) - tup = SearchSysCache(OPEROID, - ObjectIdGetDatum(operOid), - 0, 0, 0); - } - - if (!HeapTupleIsValid(tup) && !noError) - op_error(opname, ltypeId, rtypeId); - - return (Operator) tup; -} - -/* compatible_oper() - * given an opname and input datatypes, find a compatible binary operator - * - * This is tighter than oper() because it will not return an operator that - * requires coercion of the input datatypes (but binary-compatible operators - * are accepted). Otherwise, the semantics are the same. - */ -Operator -compatible_oper(List *op, Oid arg1, Oid arg2, bool noError) -{ - Operator optup; - Form_pg_operator opform; - - /* oper() will find the best available match */ - optup = oper(op, arg1, arg2, noError); - if (optup == (Operator) NULL) - return (Operator) NULL; /* must be noError case */ - - /* but is it good enough? */ - opform = (Form_pg_operator) GETSTRUCT(optup); - if (IsBinaryCompatible(opform->oprleft, arg1) && - IsBinaryCompatible(opform->oprright, arg2)) - return optup; - - /* nope... */ - ReleaseSysCache(optup); - - if (!noError) - op_error(op, arg1, arg2); - - return (Operator) NULL; -} - -/* compatible_oper_opid() -- get OID of a binary operator - * - * This is a convenience routine that extracts only the operator OID - * from the result of compatible_oper(). InvalidOid is returned if the - * lookup fails and noError is true. - */ -Oid -compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError) -{ - Operator optup; - Oid result; - - optup = compatible_oper(op, arg1, arg2, noError); - if (optup != NULL) - { - result = oprid(optup); - ReleaseSysCache(optup); - return result; - } - return InvalidOid; -} - -/* compatible_oper_funcid() -- get OID of a binary operator's function - * - * This is a convenience routine that extracts only the function OID - * from the result of compatible_oper(). InvalidOid is returned if the - * lookup fails and noError is true. - */ -Oid -compatible_oper_funcid(List *op, Oid arg1, Oid arg2, bool noError) -{ - Operator optup; - Oid result; - - optup = compatible_oper(op, arg1, arg2, noError); - if (optup != NULL) - { - result = oprfuncid(optup); - ReleaseSysCache(optup); - return result; - } - return InvalidOid; -} - - -/* right_oper() -- search for a unary right operator (operator on right) - * Given operator name and type of arg, return oper struct. - * - * IMPORTANT: the returned operator (if any) is only promised to be - * coercion-compatible with the input datatype. Do not use this if - * you need an exact- or binary-compatible match. - * - * If no matching operator found, return NULL if noError is true, - * raise an error if it is false. - * - * NOTE: on success, the returned object is a syscache entry. The caller - * must ReleaseSysCache() the entry when done with it. - */ -Operator -right_oper(List *op, Oid arg, bool noError) -{ - FuncCandidateList clist; - Oid operOid = InvalidOid; - HeapTuple tup = NULL; - - /* Find candidates */ - clist = OpernameGetCandidates(op, 'r'); - - if (clist != NULL) - { - /* - * First, quickly check to see if there is an exactly matching - * operator (there can be only one such entry in the list). - */ - FuncCandidateList clisti; - - for (clisti = clist; clisti != NULL; clisti = clisti->next) - { - if (arg == clisti->args[0]) - { - operOid = clisti->oid; - break; - } - } - - if (!OidIsValid(operOid)) - { - /* - * We must run oper_select_candidate even if only one - * candidate, otherwise we may falsely return a - * non-type-compatible operator. - */ - operOid = oper_select_candidate(1, &arg, clist); - } - if (OidIsValid(operOid)) - tup = SearchSysCache(OPEROID, - ObjectIdGetDatum(operOid), - 0, 0, 0); - } - - if (!HeapTupleIsValid(tup) && !noError) - unary_op_error(op, arg, FALSE); - - return (Operator) tup; -} - - -/* left_oper() -- search for a unary left operator (operator on left) - * Given operator name and type of arg, return oper struct. - * - * IMPORTANT: the returned operator (if any) is only promised to be - * coercion-compatible with the input datatype. Do not use this if - * you need an exact- or binary-compatible match. - * - * If no matching operator found, return NULL if noError is true, - * raise an error if it is false. - * - * NOTE: on success, the returned object is a syscache entry. The caller - * must ReleaseSysCache() the entry when done with it. - */ -Operator -left_oper(List *op, Oid arg, bool noError) -{ - FuncCandidateList clist; - Oid operOid = InvalidOid; - HeapTuple tup = NULL; - - /* Find candidates */ - clist = OpernameGetCandidates(op, 'l'); - - if (clist != NULL) - { - /* - * First, quickly check to see if there is an exactly matching - * operator (there can be only one such entry in the list). - * - * The returned list has args in the form (0, oprright). Move the - * useful data into args[0] to keep oper_select_candidate simple. - * XXX we are assuming here that we may scribble on the list! - */ - FuncCandidateList clisti; - - for (clisti = clist; clisti != NULL; clisti = clisti->next) - { - clisti->args[0] = clisti->args[1]; - if (arg == clisti->args[0]) - { - operOid = clisti->oid; - break; - } - } - - if (!OidIsValid(operOid)) - { - /* - * We must run oper_select_candidate even if only one - * candidate, otherwise we may falsely return a - * non-type-compatible operator. - */ - operOid = oper_select_candidate(1, &arg, clist); - } - if (OidIsValid(operOid)) - tup = SearchSysCache(OPEROID, - ObjectIdGetDatum(operOid), - 0, 0, 0); - } - - if (!HeapTupleIsValid(tup) && !noError) - unary_op_error(op, arg, TRUE); - - return (Operator) tup; -} - - -/* op_error() - * Give a somewhat useful error message when the operator for two types - * is not found. - */ -static void -op_error(List *op, Oid arg1, Oid arg2) -{ - if (!typeidIsValid(arg1)) - elog(ERROR, "Left hand side of operator '%s' has an unknown type" - "\n\tProbably a bad attribute name", - NameListToString(op)); - - if (!typeidIsValid(arg2)) - elog(ERROR, "Right hand side of operator %s has an unknown type" - "\n\tProbably a bad attribute name", - NameListToString(op)); - - elog(ERROR, "Unable to identify an operator '%s' for types '%s' and '%s'" - "\n\tYou will have to retype this query using an explicit cast", - NameListToString(op), - format_type_be(arg1), format_type_be(arg2)); -} - -/* unary_op_error() - * Give a somewhat useful error message when the operator for one type - * is not found. - */ -static void -unary_op_error(List *op, Oid arg, bool is_left_op) -{ - if (!typeidIsValid(arg)) - { - if (is_left_op) - elog(ERROR, "operand of prefix operator '%s' has an unknown type" - "\n\t(probably an invalid column reference)", - NameListToString(op)); - else - elog(ERROR, "operand of postfix operator '%s' has an unknown type" - "\n\t(probably an invalid column reference)", - NameListToString(op)); - } - else - { - if (is_left_op) - elog(ERROR, "Unable to identify a prefix operator '%s' for type '%s'" - "\n\tYou may need to add parentheses or an explicit cast", - NameListToString(op), format_type_be(arg)); - else - elog(ERROR, "Unable to identify a postfix operator '%s' for type '%s'" - "\n\tYou may need to add parentheses or an explicit cast", - NameListToString(op), format_type_be(arg)); - } -} |