Skip to content

Commit 1ad7611

Browse files
committed
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.
1 parent ff673f5 commit 1ad7611

File tree

1 file changed

+81
-79
lines changed

1 file changed

+81
-79
lines changed

src/backend/parser/parse_oper.c

Lines changed: 81 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.101 2008/01/11 18:39:41 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.102 2008/04/22 01:34:34 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -75,9 +75,6 @@ static const char *op_signature_string(List *op, char oprkind,
7575
static void op_error(ParseState *pstate, List *op, char oprkind,
7676
Oid arg1, Oid arg2,
7777
FuncDetailCode fdresult, int location);
78-
static Expr *make_op_expr(ParseState *pstate, Operator op,
79-
Node *ltree, Node *rtree,
80-
Oid ltypeId, Oid rtypeId);
8178
static bool make_oper_cache_key(OprCacheKey *key, List *opname,
8279
Oid ltypeId, Oid rtypeId);
8380
static Oid find_oper_cache_entry(OprCacheKey *key);
@@ -913,7 +910,13 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
913910
Oid ltypeId,
914911
rtypeId;
915912
Operator tup;
916-
Expr *result;
913+
Form_pg_operator opform;
914+
Oid actual_arg_types[2];
915+
Oid declared_arg_types[2];
916+
int nargs;
917+
List *args;
918+
Oid rettype;
919+
OpExpr *result;
917920

918921
/* Select the operator */
919922
if (rtree == NULL)
@@ -938,12 +941,72 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
938941
tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
939942
}
940943

944+
opform = (Form_pg_operator) GETSTRUCT(tup);
945+
946+
/* Check it's not a shell */
947+
if (!RegProcedureIsValid(opform->oprcode))
948+
ereport(ERROR,
949+
(errcode(ERRCODE_UNDEFINED_FUNCTION),
950+
errmsg("operator is only a shell: %s",
951+
op_signature_string(opname,
952+
opform->oprkind,
953+
opform->oprleft,
954+
opform->oprright)),
955+
parser_errposition(pstate, location)));
956+
941957
/* Do typecasting and build the expression tree */
942-
result = make_op_expr(pstate, tup, ltree, rtree, ltypeId, rtypeId);
958+
if (rtree == NULL)
959+
{
960+
/* right operator */
961+
args = list_make1(ltree);
962+
actual_arg_types[0] = ltypeId;
963+
declared_arg_types[0] = opform->oprleft;
964+
nargs = 1;
965+
}
966+
else if (ltree == NULL)
967+
{
968+
/* left operator */
969+
args = list_make1(rtree);
970+
actual_arg_types[0] = rtypeId;
971+
declared_arg_types[0] = opform->oprright;
972+
nargs = 1;
973+
}
974+
else
975+
{
976+
/* otherwise, binary operator */
977+
args = list_make2(ltree, rtree);
978+
actual_arg_types[0] = ltypeId;
979+
actual_arg_types[1] = rtypeId;
980+
declared_arg_types[0] = opform->oprleft;
981+
declared_arg_types[1] = opform->oprright;
982+
nargs = 2;
983+
}
984+
985+
/*
986+
* enforce consistency with polymorphic argument and return types,
987+
* possibly adjusting return type or declared_arg_types (which will be
988+
* used as the cast destination by make_fn_arguments)
989+
*/
990+
rettype = enforce_generic_type_consistency(actual_arg_types,
991+
declared_arg_types,
992+
nargs,
993+
opform->oprresult,
994+
false);
995+
996+
/* perform the necessary typecasting of arguments */
997+
make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
998+
999+
/* and build the expression node */
1000+
result = makeNode(OpExpr);
1001+
result->opno = oprid(tup);
1002+
result->opfuncid = opform->oprcode;
1003+
result->opresulttype = rettype;
1004+
result->opretset = get_func_retset(opform->oprcode);
1005+
result->args = args;
9431006

9441007
ReleaseSysCache(tup);
9451008

946-
return result;
1009+
return (Expr *) result;
9471010
}
9481011

9491012
/*
@@ -992,6 +1055,17 @@ make_scalar_array_op(ParseState *pstate, List *opname,
9921055
tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
9931056
opform = (Form_pg_operator) GETSTRUCT(tup);
9941057

1058+
/* Check it's not a shell */
1059+
if (!RegProcedureIsValid(opform->oprcode))
1060+
ereport(ERROR,
1061+
(errcode(ERRCODE_UNDEFINED_FUNCTION),
1062+
errmsg("operator is only a shell: %s",
1063+
op_signature_string(opname,
1064+
opform->oprkind,
1065+
opform->oprleft,
1066+
opform->oprright)),
1067+
parser_errposition(pstate, location)));
1068+
9951069
args = list_make2(ltree, rtree);
9961070
actual_arg_types[0] = ltypeId;
9971071
actual_arg_types[1] = rtypeId;
@@ -1062,78 +1136,6 @@ make_scalar_array_op(ParseState *pstate, List *opname,
10621136
return (Expr *) result;
10631137
}
10641138

1065-
/*
1066-
* make_op_expr()
1067-
* Build operator expression using an already-looked-up operator.
1068-
*
1069-
* As with coerce_type, pstate may be NULL if no special unknown-Param
1070-
* processing is wanted.
1071-
*/
1072-
static Expr *
1073-
make_op_expr(ParseState *pstate, Operator op,
1074-
Node *ltree, Node *rtree,
1075-
Oid ltypeId, Oid rtypeId)
1076-
{
1077-
Form_pg_operator opform = (Form_pg_operator) GETSTRUCT(op);
1078-
Oid actual_arg_types[2];
1079-
Oid declared_arg_types[2];
1080-
int nargs;
1081-
List *args;
1082-
Oid rettype;
1083-
OpExpr *result;
1084-
1085-
if (rtree == NULL)
1086-
{
1087-
/* right operator */
1088-
args = list_make1(ltree);
1089-
actual_arg_types[0] = ltypeId;
1090-
declared_arg_types[0] = opform->oprleft;
1091-
nargs = 1;
1092-
}
1093-
else if (ltree == NULL)
1094-
{
1095-
/* left operator */
1096-
args = list_make1(rtree);
1097-
actual_arg_types[0] = rtypeId;
1098-
declared_arg_types[0] = opform->oprright;
1099-
nargs = 1;
1100-
}
1101-
else
1102-
{
1103-
/* otherwise, binary operator */
1104-
args = list_make2(ltree, rtree);
1105-
actual_arg_types[0] = ltypeId;
1106-
actual_arg_types[1] = rtypeId;
1107-
declared_arg_types[0] = opform->oprleft;
1108-
declared_arg_types[1] = opform->oprright;
1109-
nargs = 2;
1110-
}
1111-
1112-
/*
1113-
* enforce consistency with polymorphic argument and return types,
1114-
* possibly adjusting return type or declared_arg_types (which will be
1115-
* used as the cast destination by make_fn_arguments)
1116-
*/
1117-
rettype = enforce_generic_type_consistency(actual_arg_types,
1118-
declared_arg_types,
1119-
nargs,
1120-
opform->oprresult,
1121-
false);
1122-
1123-
/* perform the necessary typecasting of arguments */
1124-
make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
1125-
1126-
/* and build the expression node */
1127-
result = makeNode(OpExpr);
1128-
result->opno = oprid(op);
1129-
result->opfuncid = opform->oprcode;
1130-
result->opresulttype = rettype;
1131-
result->opretset = get_func_retset(opform->oprcode);
1132-
result->args = args;
1133-
1134-
return (Expr *) result;
1135-
}
1136-
11371139

11381140
/*
11391141
* Lookaside cache to speed operator lookup. Possibly this should be in

0 commit comments

Comments
 (0)