mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Support expressions of the form 'scalar op ANY (array)' and
'scalar op ALL (array)', where the operator is applied between the lefthand scalar and each element of the array. The operator must yield boolean; the result of the construct is the OR or AND of the per-element results, respectively. Original coding by Joe Conway, after an idea of Peter's. Rewritten by Tom to keep the implementation strictly separate from subqueries.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.422 2003/06/27 14:45:28 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.423 2003/06/29 00:33:43 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -6051,6 +6051,13 @@ a_expr: c_expr { $$ = $1; }
|
||||
n->subselect = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| a_expr qual_all_Op sub_type '(' a_expr ')' %prec Op
|
||||
{
|
||||
if ($3 == ANY_SUBLINK)
|
||||
$$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5);
|
||||
else
|
||||
$$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5);
|
||||
}
|
||||
| UNIQUE select_with_parens %prec Op
|
||||
{
|
||||
/* Not sure how to get rid of the parentheses
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.153 2003/06/27 17:04:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.154 2003/06/29 00:33:43 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -300,6 +300,34 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
makeList1(rexpr));
|
||||
}
|
||||
break;
|
||||
case AEXPR_OP_ANY:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
|
||||
result = (Node *) make_scalar_array_op(pstate,
|
||||
a->name,
|
||||
true,
|
||||
lexpr,
|
||||
rexpr);
|
||||
}
|
||||
break;
|
||||
case AEXPR_OP_ALL:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
|
||||
result = (Node *) make_scalar_array_op(pstate,
|
||||
a->name,
|
||||
false,
|
||||
lexpr,
|
||||
rexpr);
|
||||
}
|
||||
break;
|
||||
case AEXPR_DISTINCT:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
@@ -879,6 +907,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case T_FuncExpr:
|
||||
case T_OpExpr:
|
||||
case T_DistinctExpr:
|
||||
case T_ScalarArrayOpExpr:
|
||||
case T_NullIfExpr:
|
||||
case T_BoolExpr:
|
||||
case T_FieldSelect:
|
||||
@@ -1155,6 +1184,9 @@ exprType(Node *expr)
|
||||
case T_DistinctExpr:
|
||||
type = ((DistinctExpr *) expr)->opresulttype;
|
||||
break;
|
||||
case T_ScalarArrayOpExpr:
|
||||
type = BOOLOID;
|
||||
break;
|
||||
case T_BoolExpr:
|
||||
type = BOOLOID;
|
||||
break;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.67 2003/06/27 00:33:25 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.68 2003/06/29 00:33:43 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -737,6 +737,96 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* make_scalar_array_op()
|
||||
* Build expression tree for "scalar op ANY/ALL (array)" construct.
|
||||
*/
|
||||
Expr *
|
||||
make_scalar_array_op(ParseState *pstate, List *opname,
|
||||
bool useOr,
|
||||
Node *ltree, Node *rtree)
|
||||
{
|
||||
Oid ltypeId,
|
||||
rtypeId,
|
||||
atypeId,
|
||||
res_atypeId;
|
||||
Operator tup;
|
||||
Form_pg_operator opform;
|
||||
Oid actual_arg_types[2];
|
||||
Oid declared_arg_types[2];
|
||||
List *args;
|
||||
Oid rettype;
|
||||
ScalarArrayOpExpr *result;
|
||||
|
||||
ltypeId = exprType(ltree);
|
||||
atypeId = exprType(rtree);
|
||||
/*
|
||||
* The right-hand input of the operator will be the element type of
|
||||
* the array. However, if we currently have just an untyped literal
|
||||
* on the right, stay with that and hope we can resolve the operator.
|
||||
*/
|
||||
if (atypeId == UNKNOWNOID)
|
||||
rtypeId = UNKNOWNOID;
|
||||
else
|
||||
{
|
||||
rtypeId = get_element_type(atypeId);
|
||||
if (!OidIsValid(rtypeId))
|
||||
elog(ERROR, "op ANY/ALL (array) requires array on right side");
|
||||
}
|
||||
|
||||
/* Now resolve the operator */
|
||||
tup = oper(opname, ltypeId, rtypeId, false);
|
||||
opform = (Form_pg_operator) GETSTRUCT(tup);
|
||||
|
||||
args = makeList2(ltree, rtree);
|
||||
actual_arg_types[0] = ltypeId;
|
||||
actual_arg_types[1] = rtypeId;
|
||||
declared_arg_types[0] = opform->oprleft;
|
||||
declared_arg_types[1] = opform->oprright;
|
||||
|
||||
/*
|
||||
* enforce consistency with ANYARRAY and ANYELEMENT 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,
|
||||
2,
|
||||
opform->oprresult);
|
||||
|
||||
/*
|
||||
* Check that operator result is boolean
|
||||
*/
|
||||
if (rettype != BOOLOID)
|
||||
elog(ERROR, "op ANY/ALL (array) requires operator to yield boolean");
|
||||
if (get_func_retset(opform->oprcode))
|
||||
elog(ERROR, "op ANY/ALL (array) requires operator not to return a set");
|
||||
|
||||
/*
|
||||
* Now switch back to the array type on the right, arranging for
|
||||
* any needed cast to be applied.
|
||||
*/
|
||||
res_atypeId = get_array_type(declared_arg_types[1]);
|
||||
if (!OidIsValid(res_atypeId))
|
||||
elog(ERROR, "unable to find datatype for array of %s",
|
||||
format_type_be(declared_arg_types[1]));
|
||||
actual_arg_types[1] = atypeId;
|
||||
declared_arg_types[1] = res_atypeId;
|
||||
|
||||
/* perform the necessary typecasting of arguments */
|
||||
make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
|
||||
|
||||
/* and build the expression node */
|
||||
result = makeNode(ScalarArrayOpExpr);
|
||||
result->opno = oprid(tup);
|
||||
result->opfuncid = InvalidOid;
|
||||
result->useOr = useOr;
|
||||
result->args = args;
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
return (Expr *) result;
|
||||
}
|
||||
|
||||
/*
|
||||
* make_op_expr()
|
||||
|
||||
Reference in New Issue
Block a user