Re: BUG #8198: ROW() literals not supported in an IN clause

From: Amit Kapila <amit(dot)kapila(at)huawei(dot)com>
To: <divided(dot)mind(at)gmail(dot)com>, <pgsql-bugs(at)postgresql(dot)org>
Subject: Re: BUG #8198: ROW() literals not supported in an IN clause
Date: 2013-06-04 10:35:05
Message-ID: 000301ce610f$2ee8de60$8cba9b20$@kapila@huawei.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

On Saturday, June 01, 2013 9:37 PM

> Row type literals constructed with ROW() cause an error when used in an
> IN
> clause (string literals casted appropriately are allowed). This is
> especially problematic since many client libraries use these literals
> to
> pass values of row-type arguments, hence making it impossible to use
> them in
> IN-clause queries.
>
> To wit:
> divide=# create type the_row as (mfg text, id text);
> CREATE TYPE
> divide=# create table the_table (widget the_row);
>
>
> CREATE TABLE
>
>
> divide=# insert into the_table values(row('foo', 'bar')::the_row);
>
>
> INSERT 0 1
>
>
> divide=# insert into the_table values('(bar,baz)'::the_row);
>
>
> INSERT 0 1
> divide=# select * from the_table;
> widget
> -----------
> (foo,bar)
> (bar,baz)
> (2 rows)
>
> divide=# select * from the_table where widget in
> ('(foo,bar)'::the_row);
> widget
> -----------
> (foo,bar)
> (1 row)
>
> divide=# select * from the_table where widget in
> (row('foo','bar')::the_row);
> ERROR: arguments of row IN must all be row expressions
> LINE 1: select * from the_table where widget in (row('foo','bar')::t...

The similar query for equal ('=') operator works fine.
select * from the_table where widget = (row('foo','bar')::the_row);

The reason for above is that in function transformAExprOp(..), it uses make_row_comparison_op() to operate on expressions only if both left and right are row expressions, else it will use make_op() to operate on expressions. Refer code below in function transformAExprOp()
else if (lexpr && IsA(lexpr, RowExpr) &&
rexpr && IsA(rexpr, RowExpr))
{
....
result = make_row_comparison_op(pstate,
a->name,
((RowExpr *) lexpr)->args,
((RowExpr *) rexpr)->args,
a->location);
}
else
{
....
result = (Node *) make_op(pstate,
a->name,
lexpr,
rexpr,
a->location);
}

However for IN clause, if any one expr (left or right) is RowExpr, then it will try to use make_row_comparison_op, which result in error.
Refer below code of function transformAExprIn():
if (haveRowExpr)
{
if (!IsA(lexpr, RowExpr) ||
!IsA(rexpr, RowExpr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("arguments of row IN must all be row expressions"),
parser_errposition(pstate, a->location)));
cmp = make_row_comparison_op(pstate,
a->name,
(List *) copyObject(((RowExpr *) lexpr)->args),
((RowExpr *) rexpr)->args,
a->location);
}
else
cmp = (Node *) make_op(pstate,
a->name,
copyObject(lexpr),
rexpr,
a->location);

Changing the functionality of transformAExprIn() similar to transformAExprOp() will fix this issue, but not sure if there is any other side effect of same.

With Regards,
Amit Kapila.

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Stephen Frost 2013-06-04 12:27:36 Re: Memory-leak in BackgroundWriter(and Checkpointer)
Previous Message Naoya Anzai 2013-06-04 07:45:01 Memory-leak in BackgroundWriter(and Checkpointer)