mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-12 18:34:36 +08:00
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.
This commit is contained in:
parent
ff673f558a
commit
1ad76112e7
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user