From 1ad76112e7eeb5b4db04fd8a2397818cac6f895b Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 22 Apr 2008 01:34:34 +0000 Subject: [PATCH] Issue explicit error messages for attempts to use "shell" operators in ordinary expressions. This probably doesn't catch every single case where you might get "cache lookup failed for function 0" for use of a shell operator, but it will catch most. Per bug #4120 from Pedro Gimeno. This patch incidentally folds make_op_expr() into its sole remaining caller --- the alternative was to give it yet more arguments, which didn't seem an improvement. --- src/backend/parser/parse_oper.c | 160 ++++++++++++++++---------------- 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 6b23fbb9e9..54fb63f959 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.101 2008/01/11 18:39:41 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.102 2008/04/22 01:34:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -75,9 +75,6 @@ static const char *op_signature_string(List *op, char oprkind, static void op_error(ParseState *pstate, List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult, int location); -static Expr *make_op_expr(ParseState *pstate, Operator op, - Node *ltree, Node *rtree, - Oid ltypeId, Oid rtypeId); static bool make_oper_cache_key(OprCacheKey *key, List *opname, Oid ltypeId, Oid rtypeId); static Oid find_oper_cache_entry(OprCacheKey *key); @@ -913,7 +910,13 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, Oid ltypeId, rtypeId; Operator tup; - Expr *result; + Form_pg_operator opform; + Oid actual_arg_types[2]; + Oid declared_arg_types[2]; + int nargs; + List *args; + Oid rettype; + OpExpr *result; /* Select the operator */ if (rtree == NULL) @@ -938,12 +941,72 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, tup = oper(pstate, opname, ltypeId, rtypeId, false, location); } + opform = (Form_pg_operator) GETSTRUCT(tup); + + /* Check it's not a shell */ + if (!RegProcedureIsValid(opform->oprcode)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("operator is only a shell: %s", + op_signature_string(opname, + opform->oprkind, + opform->oprleft, + opform->oprright)), + parser_errposition(pstate, location))); + /* Do typecasting and build the expression tree */ - result = make_op_expr(pstate, tup, ltree, rtree, ltypeId, rtypeId); + if (rtree == NULL) + { + /* right operator */ + args = list_make1(ltree); + actual_arg_types[0] = ltypeId; + declared_arg_types[0] = opform->oprleft; + nargs = 1; + } + else if (ltree == NULL) + { + /* left operator */ + args = list_make1(rtree); + actual_arg_types[0] = rtypeId; + declared_arg_types[0] = opform->oprright; + nargs = 1; + } + else + { + /* otherwise, binary operator */ + args = list_make2(ltree, rtree); + actual_arg_types[0] = ltypeId; + actual_arg_types[1] = rtypeId; + declared_arg_types[0] = opform->oprleft; + declared_arg_types[1] = opform->oprright; + nargs = 2; + } + + /* + * enforce consistency with polymorphic argument and return types, + * possibly adjusting return type or declared_arg_types (which will be + * used as the cast destination by make_fn_arguments) + */ + rettype = enforce_generic_type_consistency(actual_arg_types, + declared_arg_types, + nargs, + opform->oprresult, + false); + + /* perform the necessary typecasting of arguments */ + make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); + + /* and build the expression node */ + result = makeNode(OpExpr); + result->opno = oprid(tup); + result->opfuncid = opform->oprcode; + result->opresulttype = rettype; + result->opretset = get_func_retset(opform->oprcode); + result->args = args; ReleaseSysCache(tup); - return result; + return (Expr *) result; } /* @@ -992,6 +1055,17 @@ make_scalar_array_op(ParseState *pstate, List *opname, tup = oper(pstate, opname, ltypeId, rtypeId, false, location); opform = (Form_pg_operator) GETSTRUCT(tup); + /* Check it's not a shell */ + if (!RegProcedureIsValid(opform->oprcode)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("operator is only a shell: %s", + op_signature_string(opname, + opform->oprkind, + opform->oprleft, + opform->oprright)), + parser_errposition(pstate, location))); + args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; @@ -1062,78 +1136,6 @@ make_scalar_array_op(ParseState *pstate, List *opname, return (Expr *) result; } -/* - * make_op_expr() - * Build operator expression using an already-looked-up operator. - * - * As with coerce_type, pstate may be NULL if no special unknown-Param - * processing is wanted. - */ -static Expr * -make_op_expr(ParseState *pstate, Operator op, - Node *ltree, Node *rtree, - Oid ltypeId, Oid rtypeId) -{ - Form_pg_operator opform = (Form_pg_operator) GETSTRUCT(op); - Oid actual_arg_types[2]; - Oid declared_arg_types[2]; - int nargs; - List *args; - Oid rettype; - OpExpr *result; - - if (rtree == NULL) - { - /* right operator */ - args = list_make1(ltree); - actual_arg_types[0] = ltypeId; - declared_arg_types[0] = opform->oprleft; - nargs = 1; - } - else if (ltree == NULL) - { - /* left operator */ - args = list_make1(rtree); - actual_arg_types[0] = rtypeId; - declared_arg_types[0] = opform->oprright; - nargs = 1; - } - else - { - /* otherwise, binary operator */ - args = list_make2(ltree, rtree); - actual_arg_types[0] = ltypeId; - actual_arg_types[1] = rtypeId; - declared_arg_types[0] = opform->oprleft; - declared_arg_types[1] = opform->oprright; - nargs = 2; - } - - /* - * enforce consistency with polymorphic argument and return types, - * possibly adjusting return type or declared_arg_types (which will be - * used as the cast destination by make_fn_arguments) - */ - rettype = enforce_generic_type_consistency(actual_arg_types, - declared_arg_types, - nargs, - opform->oprresult, - false); - - /* perform the necessary typecasting of arguments */ - make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); - - /* and build the expression node */ - result = makeNode(OpExpr); - result->opno = oprid(op); - result->opfuncid = opform->oprcode; - result->opresulttype = rettype; - result->opretset = get_func_retset(opform->oprcode); - result->args = args; - - return (Expr *) result; -} - /* * Lookaside cache to speed operator lookup. Possibly this should be in -- 2.40.0