Skip to content

Commit

Permalink
Fix wrong operator for bit=varchar (#1806)
Browse files Browse the repository at this point in the history
* Fix case with bit=varchar

BBF has operators for BIT=INT and BIT=BIT. It must chose to cast the
varchar to BIT or to INT. Currently it picks INT as it has a higher
precedence, but the cast fails. We should prioritize same-typed
operators when picking which to use.

Signed-off-by: Walt Boettge <[email protected]>
Task: BABEL-4264
  • Loading branch information
wboettge authored Oct 2, 2023
1 parent 2e0cc34 commit e515c87
Show file tree
Hide file tree
Showing 5 changed files with 429 additions and 10 deletions.
21 changes: 19 additions & 2 deletions contrib/babelfishpg_tsql/src/pltsql_coerce.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,11 +724,13 @@ is_vectorized_binary_operator(FuncCandidateList candidate)
}

static bool
tsql_has_func_args_higher_precedence(int n, Oid *inputtypes, FuncCandidateList candidate1, FuncCandidateList candidate2)
tsql_has_func_args_higher_precedence(int n, Oid *inputtypes, FuncCandidateList candidate1, FuncCandidateList candidate2, bool candidates_are_opers)
{
int i;
Oid *argtypes1 = candidate1->args;
Oid *argtypes2 = candidate2->args;
bool can1_is_sametype = true;
bool can2_is_sametype = true;

/*
* There is no public documentation how T-SQL chooses the best candidate.
Expand All @@ -747,6 +749,19 @@ tsql_has_func_args_higher_precedence(int n, Oid *inputtypes, FuncCandidateList c
if (is_vectorized_binary_operator(candidate1) && !is_vectorized_binary_operator(candidate2))
return true;

/* Prioritize candidates with same-typed arguments for operators only*/
if (candidates_are_opers)
{
for (i = 1; i < n; ++i)
{
can1_is_sametype &= argtypes1[i-1] == argtypes1[i];
can2_is_sametype &= argtypes2[i-1] == argtypes2[i];
}

if (can2_is_sametype != can1_is_sametype)
return can1_is_sametype;
}

for (i = 0; i < n; ++i)
{
if (argtypes1[i] == argtypes2[i])
Expand Down Expand Up @@ -845,6 +860,7 @@ tsql_func_select_candidate(int nargs,
FuncCandidateList current_candidate;
FuncCandidateList another_candidate;
int i;
bool candidates_are_opers = false;

if (unknowns_resolved)
{
Expand Down Expand Up @@ -891,6 +907,7 @@ tsql_func_select_candidate(int nargs,
}

new_candidates = run_tsql_best_match_heuristics(nargs, input_typeids, candidates);
candidates_are_opers = SearchSysCacheExists1(OPEROID, new_candidates->oid);

for (current_candidate = new_candidates;
current_candidate != NULL;
Expand All @@ -902,7 +919,7 @@ tsql_func_select_candidate(int nargs,
another_candidate != NULL;
another_candidate = another_candidate->next)
{
if (!tsql_has_func_args_higher_precedence(nargs, input_typeids, current_candidate, another_candidate))
if (!tsql_has_func_args_higher_precedence(nargs, input_typeids, current_candidate, another_candidate, candidates_are_opers))
{
has_highest_precedence = false;
break;
Expand Down
281 changes: 281 additions & 0 deletions test/JDBC/expected/BABEL-4264.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
select set_config('babelfishpg_tsql.explain_costs', 'off', false)
go
~~START~~
text
off
~~END~~


create table babel4264(name1 varchar(42), flag1 bit)
go

insert into babel4264 values ('true', 1)
insert into babel4264 values ('false', 0)
go
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


select * from babel4264 where flag1 = CAST('true' as VARCHAR(20))
go
~~START~~
varchar#!#bit
true#!#1
~~END~~


select * from babel4264 where CAST('true' as VARCHAR(20)) = flag1
go
~~START~~
varchar#!#bit
true#!#1
~~END~~


select * from babel4264 where -flag1 = CAST('true' as VARCHAR(20))
go
~~START~~
varchar#!#bit
false#!#0
~~END~~


select * from babel4264 where CAST('true' as VARCHAR(20)) = ~flag1
go
~~START~~
varchar#!#bit
false#!#0
~~END~~


set babelfish_showplan_all on
go

select * from babel4264 where flag1 = CAST('true' as VARCHAR(20))
go
~~START~~
text
Query Text: select * from babel4264 where flag1 = CAST('true' as VARCHAR(20))
Seq Scan on babel4264
Filter: (flag1 = '1'::"bit")
~~END~~


set babelfish_showplan_all off
go

drop table babel4264
go

create table babel4264(date1 date)
go

set babelfish_showplan_all on
go

SELECT * from babel4264 where date1 = '1955-12-13 12:43:10'
go
~~START~~
text
Query Text: SELECT * from babel4264 where date1 = '1955-12-13 12:43:10'
Seq Scan on babel4264
Filter: (date1 = '1955-12-13'::date)
~~END~~


SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as datetime2)
go
~~START~~
text
Query Text: SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as datetime2)
Seq Scan on babel4264
Filter: ((date1)::datetime2 = '1955-12-13 12:43:10'::datetime2)
~~END~~


SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as smalldatetime)
go
~~START~~
text
Query Text: SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as smalldatetime)
Seq Scan on babel4264
Filter: (date1 = '1955-12-13 12:43:00'::smalldatetime(0) without time zone)
~~END~~


set babelfish_showplan_all off
go

drop table babel4264
go

create table babel4264(dollars money)
go

set babelfish_showplan_all on
go

SELECT * from babel4264 where dollars = 10
go
~~START~~
text
Query Text: SELECT * from babel4264 where dollars = 10
Seq Scan on babel4264
Filter: ((dollars)::fixeddecimal = 10)
~~END~~


SELECT * from babel4264 where dollars = 10.0
go
~~START~~
text
Query Text: SELECT * from babel4264 where dollars = 10.0
Seq Scan on babel4264
Filter: ((dollars)::fixeddecimal = 10.0)
~~END~~


SELECT * from babel4264 where dollars = 2147483650
go
~~START~~
text
Query Text: SELECT * from babel4264 where dollars = 2147483650
Seq Scan on babel4264
Filter: ((dollars)::fixeddecimal = '2147483650'::bigint)
~~END~~


SELECT * from babel4264 where dollars = '10.12'
go
~~START~~
text
Query Text: SELECT * from babel4264 where dollars = '10.12'
Seq Scan on babel4264
Filter: ((dollars)::fixeddecimal = '10.1200'::fixeddecimal)
~~END~~


SELECT * from babel4264 where dollars = '10.123512341234'
go
~~START~~
text
Query Text: SELECT * from babel4264 where dollars = '10.123512341234'
Seq Scan on babel4264
Filter: ((dollars)::fixeddecimal = '10.1235'::fixeddecimal)
~~END~~


SELECT * from babel4264 where dollars = cast('10' as varchar(30))
go
~~START~~
text
Query Text: SELECT * from babel4264 where dollars = cast('10' as varchar(30))
Seq Scan on babel4264
Filter: ((dollars)::fixeddecimal = '10.0000'::fixeddecimal)
~~END~~


set babelfish_showplan_all off
go

drop table babel4264
go

-- Not allowed
SELECT cast(cast('true' as varchar(20)) as INT)
go
~~ERROR (Code: 33557097)~~

~~ERROR (Message: invalid input syntax for type integer: "true")~~


-- Note, negative varbinary not allowed in T-SQL
SELECT (123 + (-0x42));
GO
~~START~~
bigint
57
~~END~~

SELECT ((-0x42) + 123);
GO
~~START~~
bigint
57
~~END~~


SELECT (123 - 0x42);
GO
~~START~~
int
57
~~END~~

SELECT (0x42 - 123);
GO
~~START~~
int
-57
~~END~~


-- Return type of int const and varbinary is now INT, not BIGINT. This can
-- result in overflows that didn't previously occur, but overflow matches T-SQL
SELECT (2147483640 + 0x10)
GO
~~ERROR (Code: 8115)~~

~~ERROR (Message: integer out of range)~~

SELECT (0x10 + 2147483640)
GO
~~ERROR (Code: 8115)~~

~~ERROR (Message: integer out of range)~~


SELECT (cast(2147483640 as bigint) + 0x10)
GO
~~START~~
bigint
2147483656
~~END~~

SELECT (0x10 + cast(2147483640 as bigint))
GO
~~START~~
bigint
2147483656
~~END~~


SELECT (-2147483640 - 0x10)
GO
~~ERROR (Code: 8115)~~

~~ERROR (Message: integer out of range)~~

SELECT (-0x10 - 2147483640)
GO
~~START~~
bigint
-2147483656
~~END~~


SELECT (cast(-2147483640 as bigint) - 0x10)
GO
~~START~~
bigint
-2147483656
~~END~~

SELECT (-0x10 - cast(2147483640 as bigint))
GO
~~START~~
bigint
-2147483656
~~END~~

12 changes: 6 additions & 6 deletions test/JDBC/expected/babel_operators.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ SELECT (123 + 0x42);
SELECT (0x42 + 123);
GO
~~START~~
bigint
int
189
~~END~~

~~START~~
bigint
int
189
~~END~~

Expand All @@ -18,12 +18,12 @@ SELECT (123 - 0x42);
SELECT (0x42 - 123);
GO
~~START~~
bigint
int
57
~~END~~

~~START~~
bigint
int
-57
~~END~~

Expand All @@ -33,12 +33,12 @@ SELECT (123 * CAST(123 AS varbinary(4)));
SELECT (CAST(123 AS varbinary(4)) * 123);
GO
~~START~~
bigint
int
15129
~~END~~

~~START~~
bigint
int
15129
~~END~~

Expand Down
Loading

0 comments on commit e515c87

Please sign in to comment.