From 71cf1a9148b20921aa60d7ae2062620c515557f8 Mon Sep 17 00:00:00 2001 From: "Andrey V. Lepikhov" Date: Sat, 28 May 2022 22:01:01 +0300 Subject: [PATCH] Try to search compatible operator if columns of compared rows is differ. --- src/backend/utils/adt/rowtypes.c | 36 +++++++++++++++++++++++--- src/test/regress/expected/rowtypes.out | 11 +++++--- src/test/regress/sql/rowtypes.sql | 2 +- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index db843a0fbf..432b44ec8c 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -18,14 +18,17 @@ #include "access/detoast.h" #include "access/htup_details.h" +#include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "common/hashfn.h" #include "funcapi.h" #include "libpq/pqformat.h" #include "miscadmin.h" +#include "parser/parse_oper.h" #include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" +#include "utils/syscache.h" #include "utils/typcache.h" @@ -1071,6 +1074,8 @@ record_eq(PG_FUNCTION_ARGS) int i1; int i2; int j; + Oid op_func = InvalidOid; + FmgrInfo op_func_finfo; check_stack_depth(); /* recurses for record-type columns */ @@ -1173,12 +1178,27 @@ record_eq(PG_FUNCTION_ARGS) * Have two matching columns, they must be same type */ if (att1->atttypid != att2->atttypid) - ereport(ERROR, + { + Operator op; + + op = compatible_oper(NULL, list_make1(makeString("=")), + att1->atttypid, att2->atttypid, false, -1); + + if (!op) + ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot compare dissimilar column types %s and %s at record column %d", format_type_be(att1->atttypid), format_type_be(att2->atttypid), j + 1))); + else + { + op_func = oprfuncid(op); + fmgr_info(op_func, &op_func_finfo); + ReleaseSysCache(op); + } + + } /* * If they're not same collation, we don't complain here, but the @@ -1217,8 +1237,18 @@ record_eq(PG_FUNCTION_ARGS) } /* Compare the pair of elements */ - InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2, - collation, NULL, NULL); + if (!OidIsValid(op_func)) + /* Compare the pair of elements */ + InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2, + collation, NULL, NULL); + else + { + /* XXX: Some collation matching logic needed. */ + collation = (collation != InvalidOid) ? collation : DEFAULT_COLLATION_OID; + InitFunctionCallInfoData(*locfcinfo, &op_func_finfo, 2, + collation, NULL, NULL); + } + locfcinfo->args[0].value = values1[i1]; locfcinfo->args[0].isnull = false; locfcinfo->args[1].value = values2[i2]; diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index a4cc2d8c12..8a3c4e9454 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -423,8 +423,12 @@ select a,b from test_table where (a,b) > ('a','a') order by a,b; reset enable_sort; -- Check row comparisons with IN -select * from int8_tbl i8 where i8 in (row(123,456)); -- fail, type mismatch -ERROR: cannot compare dissimilar column types bigint and integer at record column 1 +select * from int8_tbl i8 where i8 in (row(123,456)); -- compare rows with columns of slightly different types + q1 | q2 +-----+----- + 123 | 456 +(1 row) + explain (costs off) select * from int8_tbl i8 where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)'); @@ -618,7 +622,8 @@ create type testtype3 as (a int, b text); select row(1, 2)::testtype1 < row(1, 'abc')::testtype3; ERROR: cannot compare dissimilar column types integer and text at record column 2 select row(1, 2)::testtype1 <> row(1, 'abc')::testtype3; -ERROR: cannot compare dissimilar column types integer and text at record column 2 +ERROR: operator does not exist: integer = text +HINT: No operator matches the given name and argument types. You might need to add explicit type casts. create type testtype5 as (a int); select row(1, 2)::testtype1 < row(1)::testtype5; ERROR: cannot compare record types with different numbers of columns diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql index ad5b7e128f..5d17416117 100644 --- a/src/test/regress/sql/rowtypes.sql +++ b/src/test/regress/sql/rowtypes.sql @@ -166,7 +166,7 @@ select a,b from test_table where (a,b) > ('a','a') order by a,b; reset enable_sort; -- Check row comparisons with IN -select * from int8_tbl i8 where i8 in (row(123,456)); -- fail, type mismatch +select * from int8_tbl i8 where i8 in (row(123,456)); -- compare rows with columns of slightly different types explain (costs off) select * from int8_tbl i8 -- 2.36.1