Skip to content

Commit 7235435

Browse files
committed
Remove unnecessary restrictions about RowExprs in transformAExprIn().
When the existing code here was written, it made sense to special-case RowExprs because that was the only way that we could handle row comparisons at all. Now that we have record_eq() and arrays of composites, the generic logic for "scalar" types will in fact work on RowExprs too, so there's no reason to throw error for combinations of RowExprs and other ways of forming composite values, nor to ignore the possibility of using a ScalarArrayOpExpr. But keep using the old logic when comparing two RowExprs, for consistency with the main transformAExprOp() logic. (This allows some cases with not-quite-identical rowtypes to succeed, so we might get push-back if we removed it.) Per bug #8198 from Rafal Rzepecki. Back-patch to all supported branches, since this works fine as far back as 8.4. Rafal Rzepecki and Tom Lane
1 parent 160f2cb commit 7235435

File tree

3 files changed

+65
-24
lines changed

3 files changed

+65
-24
lines changed

src/backend/parser/parse_expr.c

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
762762
else if (lexpr && IsA(lexpr, RowExpr) &&
763763
rexpr && IsA(rexpr, RowExpr))
764764
{
765-
/* "row op row" */
765+
/* ROW() op ROW() is handled specially */
766766
lexpr = transformExpr(pstate, lexpr);
767767
rexpr = transformExpr(pstate, rexpr);
768768
Assert(IsA(lexpr, RowExpr));
@@ -867,7 +867,7 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a)
867867
if (lexpr && IsA(lexpr, RowExpr) &&
868868
rexpr && IsA(rexpr, RowExpr))
869869
{
870-
/* "row op row" */
870+
/* ROW() op ROW() is handled specially */
871871
return make_row_distinct_op(pstate, a->name,
872872
(RowExpr *) lexpr,
873873
(RowExpr *) rexpr,
@@ -957,7 +957,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
957957
List *rvars;
958958
List *rnonvars;
959959
bool useOr;
960-
bool haveRowExpr;
961960
ListCell *l;
962961

963962
/*
@@ -970,24 +969,21 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
970969

971970
/*
972971
* We try to generate a ScalarArrayOpExpr from IN/NOT IN, but this is only
973-
* possible if the inputs are all scalars (no RowExprs) and there is a
974-
* suitable array type available. If not, we fall back to a boolean
975-
* condition tree with multiple copies of the lefthand expression. Also,
976-
* any IN-list items that contain Vars are handled as separate boolean
977-
* conditions, because that gives the planner more scope for optimization
978-
* on such clauses.
972+
* possible if there is a suitable array type available. If not, we fall
973+
* back to a boolean condition tree with multiple copies of the lefthand
974+
* expression. Also, any IN-list items that contain Vars are handled as
975+
* separate boolean conditions, because that gives the planner more scope
976+
* for optimization on such clauses.
979977
*
980-
* First step: transform all the inputs, and detect whether any are
981-
* RowExprs or contain Vars.
978+
* First step: transform all the inputs, and detect whether any contain
979+
* Vars.
982980
*/
983981
lexpr = transformExpr(pstate, a->lexpr);
984-
haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
985982
rexprs = rvars = rnonvars = NIL;
986983
foreach(l, (List *) a->rexpr)
987984
{
988985
Node *rexpr = transformExpr(pstate, lfirst(l));
989986

990-
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
991987
rexprs = lappend(rexprs, rexpr);
992988
if (contain_vars_of_level(rexpr, 0))
993989
rvars = lappend(rvars, rexpr);
@@ -997,9 +993,9 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
997993

998994
/*
999995
* ScalarArrayOpExpr is only going to be useful if there's more than one
1000-
* non-Var righthand item. Also, it won't work for RowExprs.
996+
* non-Var righthand item.
1001997
*/
1002-
if (!haveRowExpr && list_length(rnonvars) > 1)
998+
if (list_length(rnonvars) > 1)
1003999
{
10041000
List *allexprs;
10051001
Oid scalar_type;
@@ -1015,8 +1011,13 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
10151011
allexprs = list_concat(list_make1(lexpr), rnonvars);
10161012
scalar_type = select_common_type(pstate, allexprs, NULL, NULL);
10171013

1018-
/* Do we have an array type to use? */
1019-
if (OidIsValid(scalar_type))
1014+
/*
1015+
* Do we have an array type to use? Aside from the case where there
1016+
* isn't one, we don't risk using ScalarArrayOpExpr when the common
1017+
* type is RECORD, because the RowExpr comparison logic below can cope
1018+
* with some cases of non-identical row types.
1019+
*/
1020+
if (OidIsValid(scalar_type) && scalar_type != RECORDOID)
10201021
array_type = get_array_type(scalar_type);
10211022
else
10221023
array_type = InvalidOid;
@@ -1066,26 +1067,25 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
10661067
Node *rexpr = (Node *) lfirst(l);
10671068
Node *cmp;
10681069

1069-
if (haveRowExpr)
1070+
if (IsA(lexpr, RowExpr) &&
1071+
IsA(rexpr, RowExpr))
10701072
{
1071-
if (!IsA(lexpr, RowExpr) ||
1072-
!IsA(rexpr, RowExpr))
1073-
ereport(ERROR,
1074-
(errcode(ERRCODE_SYNTAX_ERROR),
1075-
errmsg("arguments of row IN must all be row expressions"),
1076-
parser_errposition(pstate, a->location)));
1073+
/* ROW() op ROW() is handled specially */
10771074
cmp = make_row_comparison_op(pstate,
10781075
a->name,
10791076
(List *) copyObject(((RowExpr *) lexpr)->args),
10801077
((RowExpr *) rexpr)->args,
10811078
a->location);
10821079
}
10831080
else
1081+
{
1082+
/* Ordinary scalar operator */
10841083
cmp = (Node *) make_op(pstate,
10851084
a->name,
10861085
copyObject(lexpr),
10871086
rexpr,
10881087
a->location);
1088+
}
10891089

10901090
cmp = coerce_to_boolean(pstate, cmp, "IN");
10911091
if (result == NULL)

src/test/regress/expected/rowtypes.out

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,25 @@ ERROR: could not determine interpretation of row comparison operator ~~
208208
LINE 1: select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
209209
^
210210
HINT: Row comparison operators must be associated with btree operator families.
211+
-- Comparisons of ROW() expressions can cope with some type mismatches
212+
select ROW(1,2) = ROW(1,2::int8);
213+
?column?
214+
----------
215+
t
216+
(1 row)
217+
218+
select ROW(1,2) in (ROW(3,4), ROW(1,2));
219+
?column?
220+
----------
221+
t
222+
(1 row)
223+
224+
select ROW(1,2) in (ROW(3,4), ROW(1,2::int8));
225+
?column?
226+
----------
227+
t
228+
(1 row)
229+
211230
-- Check row comparison with a subselect
212231
select unique1, unique2 from tenk1
213232
where (unique1, unique2) < any (select ten, ten from tenk1 where hundred < 3)
@@ -252,6 +271,17 @@ order by thousand, tenthous;
252271
999 | 9999
253272
(25 rows)
254273

274+
-- Check row comparisons with IN
275+
select * from int8_tbl i8 where i8 in (row(123,456)); -- fail, type mismatch
276+
ERROR: cannot compare dissimilar column types bigint and integer at record column 1
277+
select * from int8_tbl i8
278+
where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)');
279+
q1 | q2
280+
------------------+-----
281+
123 | 456
282+
4567890123456789 | 123
283+
(2 rows)
284+
255285
-- Check some corner cases involving empty rowtypes
256286
select ROW();
257287
row

src/test/regress/sql/rowtypes.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ select ROW('ABC','DEF') ~<=~ ROW('DEF','ABC') as true;
9898
select ROW('ABC','DEF') ~>=~ ROW('DEF','ABC') as false;
9999
select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
100100

101+
-- Comparisons of ROW() expressions can cope with some type mismatches
102+
select ROW(1,2) = ROW(1,2::int8);
103+
select ROW(1,2) in (ROW(3,4), ROW(1,2));
104+
select ROW(1,2) in (ROW(3,4), ROW(1,2::int8));
105+
101106
-- Check row comparison with a subselect
102107
select unique1, unique2 from tenk1
103108
where (unique1, unique2) < any (select ten, ten from tenk1 where hundred < 3)
@@ -109,6 +114,12 @@ select thousand, tenthous from tenk1
109114
where (thousand, tenthous) >= (997, 5000)
110115
order by thousand, tenthous;
111116

117+
-- Check row comparisons with IN
118+
select * from int8_tbl i8 where i8 in (row(123,456)); -- fail, type mismatch
119+
120+
select * from int8_tbl i8
121+
where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)');
122+
112123
-- Check some corner cases involving empty rowtypes
113124
select ROW();
114125
select ROW() IS NULL;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy