diff --git a/contrib/babelfishpg_tsql/src/pltsql_coerce.c b/contrib/babelfishpg_tsql/src/pltsql_coerce.c index ad4bc796f3..83e19d72f9 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_coerce.c +++ b/contrib/babelfishpg_tsql/src/pltsql_coerce.c @@ -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. @@ -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]) @@ -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) { @@ -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; @@ -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; diff --git a/test/JDBC/expected/BABEL-4264.out b/test/JDBC/expected/BABEL-4264.out new file mode 100644 index 0000000000..fb4e557643 --- /dev/null +++ b/test/JDBC/expected/BABEL-4264.out @@ -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~~ + diff --git a/test/JDBC/expected/babel_operators.out b/test/JDBC/expected/babel_operators.out index 6dc6cba640..e515115a25 100644 --- a/test/JDBC/expected/babel_operators.out +++ b/test/JDBC/expected/babel_operators.out @@ -3,12 +3,12 @@ SELECT (123 + 0x42); SELECT (0x42 + 123); GO ~~START~~ -bigint +int 189 ~~END~~ ~~START~~ -bigint +int 189 ~~END~~ @@ -18,12 +18,12 @@ SELECT (123 - 0x42); SELECT (0x42 - 123); GO ~~START~~ -bigint +int 57 ~~END~~ ~~START~~ -bigint +int -57 ~~END~~ @@ -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~~ diff --git a/test/JDBC/expected/babel_varbinary.out b/test/JDBC/expected/babel_varbinary.out index 935538e9ff..70e770fb42 100644 --- a/test/JDBC/expected/babel_varbinary.out +++ b/test/JDBC/expected/babel_varbinary.out @@ -124,14 +124,14 @@ int select 0x1F * 10; go ~~START~~ -bigint +int 310 ~~END~~ select 10 * 0x1F; go ~~START~~ -bigint +int 310 ~~END~~ diff --git a/test/JDBC/input/BABEL-4264.sql b/test/JDBC/input/BABEL-4264.sql new file mode 100644 index 0000000000..93d6194981 --- /dev/null +++ b/test/JDBC/input/BABEL-4264.sql @@ -0,0 +1,121 @@ +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go + +create table babel4264(name1 varchar(42), flag1 bit) +go + +insert into babel4264 values ('true', 1) +insert into babel4264 values ('false', 0) +go + +select * from babel4264 where flag1 = CAST('true' as VARCHAR(20)) +go + +select * from babel4264 where CAST('true' as VARCHAR(20)) = flag1 +go + +select * from babel4264 where -flag1 = CAST('true' as VARCHAR(20)) +go + +select * from babel4264 where CAST('true' as VARCHAR(20)) = ~flag1 +go + +set babelfish_showplan_all on +go + +select * from babel4264 where flag1 = CAST('true' as VARCHAR(20)) +go + +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 + +SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as datetime2) +go + +SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as smalldatetime) +go + +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 + +SELECT * from babel4264 where dollars = 10.0 +go + +SELECT * from babel4264 where dollars = 2147483650 +go + +SELECT * from babel4264 where dollars = '10.12' +go + +SELECT * from babel4264 where dollars = '10.123512341234' +go + +SELECT * from babel4264 where dollars = cast('10' as varchar(30)) +go + +set babelfish_showplan_all off +go + +drop table babel4264 +go + +-- Not allowed +SELECT cast(cast('true' as varchar(20)) as INT) +go + +-- Note, negative varbinary not allowed in T-SQL +SELECT (123 + (-0x42)); +GO +SELECT ((-0x42) + 123); +GO + +SELECT (123 - 0x42); +GO +SELECT (0x42 - 123); +GO + +-- 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 +SELECT (0x10 + 2147483640) +GO + +SELECT (cast(2147483640 as bigint) + 0x10) +GO +SELECT (0x10 + cast(2147483640 as bigint)) +GO + +SELECT (-2147483640 - 0x10) +GO +SELECT (-0x10 - 2147483640) +GO + +SELECT (cast(-2147483640 as bigint) - 0x10) +GO +SELECT (-0x10 - cast(2147483640 as bigint)) +GO