summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y9
-rw-r--r--src/backend/parser/parse_expr.c34
-rw-r--r--src/backend/parser/parse_oper.c92
3 files changed, 132 insertions, 3 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d3d9b4a5e30..a8df7c65e9d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -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
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 6a90ab9197d..b985b190bac 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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;
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 983041eb45b..72327243310 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -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()