]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Issue explicit error messages for attempts to use "shell" operators in
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 22 Apr 2008 01:34:34 +0000 (01:34 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 22 Apr 2008 01:34:34 +0000 (01:34 +0000)
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

index 6b23fbb9e9a05af761d1b5262d40a1034be4ea3d..54fb63f959d014a7d03269f267d9b6ce8f2e7a0a 100644 (file)
@@ -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