From 8ad86ff8811ffce2a5ebda1f1ed42196c14229fb Mon Sep 17 00:00:00 2001 From: Rob Verschoor <91290800+robverschoor@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:53:42 +0200 Subject: [PATCH] Support unary '+' operators for strings (#3013) The T-SQL grammar allows an arbitrary number of unary + operators to precede an expression, but PG only supports that for numeric expressions. For string expressions, the + will be parsed fine by the T-SQL ANTLR parser, but these will raise an error in PG. In SQL those unary + string operators may look like they are additional concatenation operators, like: SELECT 'a' ++ 'b'. Expressions such as +++(+++@v)) are also valid syntax according to the T-SQL grammar even though they look unusual. In this fix we remove such unary + operators, which are redundant anyway. However we do not touch numeric constants (e.g. +123) since the +, though still redundant, may have been included for code clarity (e.g. +123 as opposed to -123). Signed-off-by: Rob Verschoor rcv@amazon.com Issues Resolved BABEL-1924 Support unary '+' operator for string expressions --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 57 +- .../unary_plus_op_string-vu-cleanup.out | 11 + .../unary_plus_op_string-vu-prepare.out | 76 ++ .../unary_plus_op_string-vu-verify.out | 871 ++++++++++++++++++ .../input/unary_plus_op_string-vu-cleanup.sql | 11 + .../input/unary_plus_op_string-vu-prepare.sql | 76 ++ .../input/unary_plus_op_string-vu-verify.sql | 250 +++++ test/JDBC/upgrade/latest/schedule | 1 + .../expected_dependency.out | 1 - 9 files changed, 1347 insertions(+), 7 deletions(-) create mode 100644 test/JDBC/expected/unary_plus_op_string-vu-cleanup.out create mode 100644 test/JDBC/expected/unary_plus_op_string-vu-prepare.out create mode 100644 test/JDBC/expected/unary_plus_op_string-vu-verify.out create mode 100644 test/JDBC/input/unary_plus_op_string-vu-cleanup.sql create mode 100644 test/JDBC/input/unary_plus_op_string-vu-prepare.sql create mode 100644 test/JDBC/input/unary_plus_op_string-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index b37c7177d8..37e8de357b 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -2499,11 +2499,11 @@ class tsqlBuilder : public tsqlCommonMutator { // Check for comparison operators directly followed by an '@@' variable, like =@@ handleAtAtVarInPredicate(ctx); - } + } void exitUnary_op_expr(TSqlParser::Unary_op_exprContext *ctx) override { handleBitNotOperator(ctx); - } + } void exitPlus_minus_bit_expr(TSqlParser::Plus_minus_bit_exprContext *ctx) override { handleBitOperators(ctx); @@ -3217,10 +3217,7 @@ class tsqlMutator : public TSqlParserBaseListener // Check for comparison operators directly followed by an '@@' variable, like =@@ handleAtAtVarInPredicate(ctx); } - void exitUnary_op_expr(TSqlParser::Unary_op_exprContext *ctx) override - { - handleBitNotOperator(ctx); - } + void exitPlus_minus_bit_expr(TSqlParser::Plus_minus_bit_exprContext *ctx) override { handleBitOperators(ctx); @@ -3229,6 +3226,54 @@ class tsqlMutator : public TSqlParserBaseListener { handleModuloOperator(ctx); } + + void enterUnary_op_expr(TSqlParser::Unary_op_exprContext *ctx) override + { + /* + * The T-SQL grammar allows an arbitrary number of unary '+' operators to precede an expression, + * but PG only supports that for numeric expressions. For string expressions, such a '+' will raise an error in PG. + * In SQL this shows as redundant operators, for example for concatenation: SELECT 'a' ++ 'b'. Expressions + * such as +++(+++@v)) are also valid syntax according to the T-SQL grammar even though they look unusual. + * Here we remove such unary '+' operators, which are redundant anyway. + * However we do not touch numeric constants (e.g. +123) since the '+', although still redundant, may + * have been included for code clarity (e.g. +123 as opposed to -123). + */ + std::string op = getFullText(ctx->op); + if (op.front() == '+') { + auto rhsctx = ctx->expression(); + while (true) { + std::string rhs = getFullText(rhsctx); + if ( + (rhs.front() == '\'') || // single-quoted strings + (rhs.front() == '"') || // both double-quoted strings and double-quoted identifiers + (rhs.front() == '@') || // variables + (rhs.front() == '(') || // bracketed expressions + (rhs.front() == '[') || // bracket-delimited identifiers + (rhs.front() == '_') || // identifiers starting with an underscore + std::isalpha(rhs.front()) // identifiers as well as the N'...' string notation + ) { + stream.setText(ctx->op->getStartIndex(), " "); + break; + } + if (rhs.front() == '+') { + if (dynamic_cast(rhsctx)) { + TSqlParser::Unary_op_exprContext *uctx = static_cast(rhsctx); + op = getFullText(uctx->op); + if (op.front() == '+') { + rhsctx = uctx->expression(); + continue; + } + } + } + break; + } + } + return; + } + void exitUnary_op_expr(TSqlParser::Unary_op_exprContext *ctx) override + { + handleBitNotOperator(ctx); + } }; diff --git a/test/JDBC/expected/unary_plus_op_string-vu-cleanup.out b/test/JDBC/expected/unary_plus_op_string-vu-cleanup.out new file mode 100644 index 0000000000..7101758e59 --- /dev/null +++ b/test/JDBC/expected/unary_plus_op_string-vu-cleanup.out @@ -0,0 +1,11 @@ +drop procedure p1_unary_plus_op_string +go + +drop function f1_unary_plus_op_string +go + +drop view v1_unary_plus_op_string +go + +drop table t1_unary_plus_op_string +go diff --git a/test/JDBC/expected/unary_plus_op_string-vu-prepare.out b/test/JDBC/expected/unary_plus_op_string-vu-prepare.out new file mode 100644 index 0000000000..fa33ec42ae --- /dev/null +++ b/test/JDBC/expected/unary_plus_op_string-vu-prepare.out @@ -0,0 +1,76 @@ +create table t1_unary_plus_op_string(i int, vc varchar(30)) +go + +create view v1_unary_plus_op_string as +select 'view '+++(+N'value1') + ++ /*comment*/ +( ++ /*comment*/ ++ -- comment + +( ++ +'value2'))++(+(select 'value3')) as col1, +1 + -2 as col2, +1 ++ -2 as col3, +1 + ~2 as col4, +1 +++++ ~2 as col5, +1 ++++ (++++ -2) as col6, +1 ++++ (++++ ~2) as col7 +go + +create procedure p1_unary_plus_op_string +as +declare @v varchar(20) = ' test' +declare @i int = 1 +declare @d datetime='2024-Jan-01 01:02:03' +declare @dc decimal(10,4)=1 +select 'proc '+'line1' +select 'proc '++'line2' +select 'proc '++N'line3' +select 'proc '+++++'line4' +select 'proc '+++++"line5" +select 'proc '+ ++ /*comment*/ +( ++ /*comment*/ ++ -- comment + +( ++ +"line6"))+++@v +select 'proc ' ++(++(++(select N'line7')))++(+@v) +select 'proc ' ++ case when len('a'+++ 'b')=2 then 'true' else 'false' end +select 'proc line8' where 'x' in (+'x') +select 'proc line9' where 'x' like +'x' +set @v = 'x' +select 'proc line10' where 'x' like (+@v) +select 'proc line11' where 'x' like +(+(+@v)) +select 'proc line 12 ' ++ vc from t1_unary_plus_op_string order by 1 +select 'proc line 13 ' ++(+vc) from t1_unary_plus_op_string order by 1 +select 'proc line 14 ' ++ [vc] from t1_unary_plus_op_string order by 1 +select 1 + @i, 2 + (+@i), 3 ++++(++(+++@i)) +select +@d, + (+@d), ++++(++(+++@d)) +select 1 +@dc, 2 + (+@dc), 3 ++++(++(+++@dc)) +select 1 + -2 as expr1 +select 1 ++ -2 as expr2 +select 1 + ~2 as expr3 +select 1 +++++ ~2 as expr4 +select 1 ++++ (++++ -2) as expr5 +select 1 ++++ (++++ ~2) as expr6 +EXECUTE('select ''execimm ''++''line1''') +EXECUTE('select ''execimm ''++N''line2''') +EXECUTE('select ''execimm ''++(+(select N''line3''))') +go + +create function f1_unary_plus_op_string (@v varchar(10)) returns varchar(30) +as +begin +declare @s varchar(30) +set @s = 'func '+++(+N'value1') + ++ +( ++ /*comment*/ ++ -- comment + +(++(select "value2")))++(+@v) +return @s +end +go diff --git a/test/JDBC/expected/unary_plus_op_string-vu-verify.out b/test/JDBC/expected/unary_plus_op_string-vu-verify.out new file mode 100644 index 0000000000..8cc6573193 --- /dev/null +++ b/test/JDBC/expected/unary_plus_op_string-vu-verify.out @@ -0,0 +1,871 @@ +insert t1_unary_plus_op_string values (1, 'abc') +go +~~ROW COUNT: 1~~ + + +set quoted_identifier off +go +select 'x'+'y' +go +~~START~~ +varchar +xy +~~END~~ + +select 'x' + 'y' +go +~~START~~ +varchar +xy +~~END~~ + +select 'x' + +/* comment*/ +'y' +/*comment*/ + + 'z' +go +~~START~~ +varchar +xyz +~~END~~ + +select 'x'++'y' +go +~~START~~ +varchar +xy +~~END~~ + +select 'x'++++++++'y' +go +~~START~~ +varchar +xy +~~END~~ + +select 'x'++N'y' +go +~~START~~ +nvarchar +xy +~~END~~ + +select 'x'++++++++N'y' +go +~~START~~ +nvarchar +xy +~~END~~ + +select 'x' ++++++++ 'y' +go +~~START~~ +varchar +xy +~~END~~ + +select 'x' ++ ++ +/* comment*/ + + +'y' ++ -- comment + +/*comment*/ ++ + + ++ 'z' +go +~~START~~ +varchar +xyz +~~END~~ + +declare @v varchar(10)='y' select 'x'+ @v, 'x' +@v, 'x' ++++++@v +go +~~START~~ +varchar#!#varchar#!#varchar +xy#!#xy#!#xy +~~END~~ + +declare @v varchar(10)='y' select 'x'+ (@v), 'x' + (+@v), 'x' ++++(++(+++@v)) +go +~~START~~ +varchar#!#varchar#!#varchar +xy#!#xy#!#xy +~~END~~ + +declare @v tinyint=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +~~START~~ +int#!#int#!#int +2#!#3#!#4 +~~END~~ + +declare @v int=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +~~START~~ +int#!#int#!#int +2#!#3#!#4 +~~END~~ + +declare @v bigint=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +~~START~~ +bigint#!#bigint#!#bigint +2#!#3#!#4 +~~END~~ + +declare @v decimal(10,4)=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +~~START~~ +numeric#!#numeric#!#numeric +2.0000#!#3.0000#!#4.0000 +~~END~~ + +declare @v money=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +~~START~~ +money#!#money#!#money +2.0000#!#3.0000#!#4.0000 +~~END~~ + +declare @v datetime='2024-Jan-01 01:02:03' select +@v, + (+@v), ++++(++(+++@v)) +go +~~START~~ +datetime#!#datetime#!#datetime +2024-01-01 01:02:03.0#!#2024-01-01 01:02:03.0#!#2024-01-01 01:02:03.0 +~~END~~ + +declare @v datetime2='2024-Jan-01 01:02:03' select +@v, + (+@v), ++++(++(+++@v)) +go +~~START~~ +datetime2#!#datetime2#!#datetime2 +2024-01-01 01:02:03.0000000#!#2024-01-01 01:02:03.0000000#!#2024-01-01 01:02:03.0000000 +~~END~~ + +select +'y' +go +~~START~~ +varchar +y +~~END~~ + +select +N'y' +go +~~START~~ +nvarchar +y +~~END~~ + +select ((+'y')) +go +~~START~~ +varchar +y +~~END~~ + +select ((+N'y')) +go +~~START~~ +nvarchar +y +~~END~~ + +select ++++(++++++(+++++'y')) +go +~~START~~ +varchar +y +~~END~~ + +select 'x'+(+'y') +go +~~START~~ +varchar +xy +~~END~~ + +select 'x'+++((+++(+++'y'))) +go +~~START~~ +varchar +xy +~~END~~ + +select 'x'+++( +(+++ +(+++ +'y'))) +go +~~START~~ +varchar +xy +~~END~~ + +if 'x' <> + char(13) select 'true' else select 'false' +go +~~START~~ +varchar +true +~~END~~ + +if 'x' <> +++ char(13) select 'true' else select 'false' +go +~~START~~ +varchar +true +~~END~~ + +select len(+'x') +go +~~START~~ +int +1 +~~END~~ + +select len(+N'x') +go +~~START~~ +int +1 +~~END~~ + +select 'x' ++ substring('xyz', 2, 1) +go +~~START~~ +varchar +xy +~~END~~ + +select 'x' +++++ substring(+'xyz', 2, 1) +go +~~START~~ +varchar +xy +~~END~~ + +select 'x' ++ case when len('a'+++ 'b')=2 then 'true' else 'false' end +go +~~START~~ +varchar +xtrue +~~END~~ + +select 'x' ++ case when len(+'a'+++ 'b')=2 then +'true' else +++++'false' end +go +~~START~~ +varchar +xtrue +~~END~~ + +declare @v varchar(10) = 'true' +select 'x' ++ case when len(+'a'+++ 'b')=2 then +@v else 'false' end +go +~~START~~ +varchar +xtrue +~~END~~ + +select 1 where 'x' in (+'x') +go +~~START~~ +int +1 +~~END~~ + +select 1 where 'x' like +'x' +go +~~START~~ +int +1 +~~END~~ + +declare @v varchar(10) = 'x' +select 1 where 'x' like (+@v) +go +~~START~~ +int +1 +~~END~~ + +declare @v varchar(10) = 'x' +select 1 where 'x' like +(+(+@v)) +go +~~START~~ +int +1 +~~END~~ + +declare @v varchar(10) = 'x' +if 'y' <> + @v select 'true' else select 'false' +go +~~START~~ +varchar +true +~~END~~ + +declare @v varchar(10) = 'x' +if 'y' <> +++ @v select 'true' else select 'false' +set @v = 'x' ++ case when len('a'+++ 'b')=2 then 'true2' else 'false2' end +select @v +go +~~START~~ +varchar +true +~~END~~ + +~~START~~ +varchar +xtrue2 +~~END~~ + +select 'x' ++vc from t1_unary_plus_op_string order by 1 +go +~~START~~ +varchar +xabc +~~END~~ + +select 'x' ++(+vc) from t1_unary_plus_op_string order by 1 +go +~~START~~ +varchar +xabc +~~END~~ + +select +(select 'abc') +go +~~START~~ +varchar +abc +~~END~~ + +select ++++(select 'abc') +go +~~START~~ +varchar +abc +~~END~~ + +select +(+((select 'abc'))) +go +~~START~~ +varchar +abc +~~END~~ + + +/*double-quoted strings*/ +select "x"+"y" +go +~~START~~ +varchar +xy +~~END~~ + +select "x" + "y" +go +~~START~~ +varchar +xy +~~END~~ + +select "x" + +/* comment*/ +"y" +/*comment*/ + + "z" +go +~~START~~ +varchar +xyz +~~END~~ + +select "x"++"y" +go +~~START~~ +varchar +xy +~~END~~ + +select "x"++++++++"y" +go +~~START~~ +varchar +xy +~~END~~ + +select "x" ++++++++ "y" +go +~~START~~ +varchar +xy +~~END~~ + +select "x" ++ ++ +/* comment*/ + + +"y" ++ +/*comment*/ ++ + + ++ "z" +go +~~START~~ +varchar +xyz +~~END~~ + +declare @v varchar(10)="y" select "x"+ @v, "x" +@v, "x" ++++++@v +go +~~START~~ +varchar#!#varchar#!#varchar +xy#!#xy#!#xy +~~END~~ + +select +"y" +go +~~START~~ +varchar +y +~~END~~ + +select ((+"y")) +go +~~START~~ +varchar +y +~~END~~ + +select ++++(++++++(+++++"y")) +go +~~START~~ +varchar +y +~~END~~ + +select 'x'+(+"y") +go +~~START~~ +varchar +xy +~~END~~ + +select "x"+++((+++(+++"y"))) +go +~~START~~ +varchar +xy +~~END~~ + +select "x"+++( +(+++ +(+++ +"y"))) +go +~~START~~ +varchar +xy +~~END~~ + +if "x" <> + char(13) select "true" else select "false" +go +~~START~~ +varchar +true +~~END~~ + +if "x" <> +++ char(13) select "true" else select "false" +go +~~START~~ +varchar +true +~~END~~ + +select len(+"x") +go +~~START~~ +int +1 +~~END~~ + +select "x" ++ substring("xyz", 2, 1) +go +~~START~~ +varchar +xy +~~END~~ + +select "x" +++++ substring(+"xyz", 2, 1) +go +~~START~~ +varchar +xy +~~END~~ + +select "x" ++ case when len("a"+++ "b")=2 then "true" else "false" end +go +~~START~~ +varchar +xtrue +~~END~~ + +declare @v varchar(10) = "true" +select "x" ++ case when len(+"a"+++ 'b')=2 then +@v else +"false" end +go +~~START~~ +varchar +xtrue +~~END~~ + +select 1 where "x" in (+"x") +go +~~START~~ +int +1 +~~END~~ + +select 1 where "x" like +"x" +go +~~START~~ +int +1 +~~END~~ + +declare @v varchar(10) = "x" +if "y" <> +++ @v select "true" else select "false" +set @v = "x" ++ case when len(++"a"+++N'b')=2 then "true2" else "false2" end +select @v +go +~~START~~ +varchar +true +~~END~~ + +~~START~~ +varchar +xtrue2 +~~END~~ + +select +(+((select "abc"))) +go +~~START~~ +varchar +abc +~~END~~ + + +/* double-quoted identifiers */ +set quoted_identifier on +go +select 'x' ++ "vc" from t1_unary_plus_op_string order by 1 +go +~~START~~ +varchar +xabc +~~END~~ + +select 'x' ++((+(++"vc"))) from t1_unary_plus_op_string order by 1 +go +~~START~~ +varchar +xabc +~~END~~ + +set quoted_identifier off +go + +/* bracket-delimited identifiers */ +select 'x' ++ [vc] from t1_unary_plus_op_string order by 1 +go +~~START~~ +varchar +xabc +~~END~~ + +select 'x' ++ ((+(++[vc]))) from t1_unary_plus_op_string order by 1 +go +~~START~~ +varchar +xabc +~~END~~ + + +/*numeric expressions should not be affected*/ +select 1 +-2 +go +~~START~~ +int +-1 +~~END~~ + +select 1 + -2 +go +~~START~~ +int +-1 +~~END~~ + +select 1 ++-2 +go +~~START~~ +int +-1 +~~END~~ + +select 1 + + -2 +go +~~START~~ +int +-1 +~~END~~ + +select 1 + ~2 +go +~~START~~ +int +-2 +~~END~~ + +select 1 ++~2 +go +~~START~~ +int +-2 +~~END~~ + +select 1 ++ ~2 +go +~~START~~ +int +-2 +~~END~~ + +select 1 ++++ (++++ 2) +go +~~START~~ +int +3 +~~END~~ + +select 1 ++++ (++++ ~2) +go +~~START~~ +int +-2 +~~END~~ + +select 1 ++++ (++++ -2) +go +~~START~~ +int +-1 +~~END~~ + + +/* execute-immediate */ +execute('select ((+''y'')) ') +go +~~START~~ +varchar +y +~~END~~ + +execute('select ''x''+++((+++(+++''y'')))') +go +~~START~~ +varchar +xy +~~END~~ + +execute('select ''x'' ++vc from t1_unary_plus_op_string order by 1') +go +~~START~~ +varchar +xabc +~~END~~ + + +/* SQL objects */ +select * from v1_unary_plus_op_string +go +~~START~~ +nvarchar#!#int#!#int#!#int#!#int#!#int#!#int +view value1value2value3#!#-1#!#-1#!#-2#!#-2#!#-1#!#-2 +~~END~~ + +execute p1_unary_plus_op_string +go +~~START~~ +varchar +proc line1 +~~END~~ + +~~START~~ +varchar +proc line2 +~~END~~ + +~~START~~ +nvarchar +proc line3 +~~END~~ + +~~START~~ +varchar +proc line4 +~~END~~ + +~~START~~ +varchar +proc line5 +~~END~~ + +~~START~~ +varchar +proc line6 test +~~END~~ + +~~START~~ +nvarchar +proc line7 test +~~END~~ + +~~START~~ +varchar +proc true +~~END~~ + +~~START~~ +varchar +proc line8 +~~END~~ + +~~START~~ +varchar +proc line9 +~~END~~ + +~~START~~ +varchar +proc line10 +~~END~~ + +~~START~~ +varchar +proc line11 +~~END~~ + +~~START~~ +varchar +proc line 12 abc +~~END~~ + +~~START~~ +varchar +proc line 13 abc +~~END~~ + +~~START~~ +varchar +proc line 14 abc +~~END~~ + +~~START~~ +int#!#int#!#int +2#!#3#!#4 +~~END~~ + +~~START~~ +datetime#!#datetime#!#datetime +2024-01-01 01:02:03.0#!#2024-01-01 01:02:03.0#!#2024-01-01 01:02:03.0 +~~END~~ + +~~START~~ +numeric#!#numeric#!#numeric +2.0000#!#3.0000#!#4.0000 +~~END~~ + +~~START~~ +int +-1 +~~END~~ + +~~START~~ +int +-1 +~~END~~ + +~~START~~ +int +-2 +~~END~~ + +~~START~~ +int +-2 +~~END~~ + +~~START~~ +int +-1 +~~END~~ + +~~START~~ +int +-2 +~~END~~ + +~~START~~ +varchar +execimm line1 +~~END~~ + +~~START~~ +nvarchar +execimm line2 +~~END~~ + +~~START~~ +nvarchar +execimm line3 +~~END~~ + +select * from dbo.f1_unary_plus_op_string('test') +go +~~START~~ +varchar +func value1value2test +~~END~~ + + +/* the following should raise an error: unary operator other than '+' is invalid for a string in T-SQL */ +select ~'y' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: ~ unknown)~~ + +select 'x' + ~'y' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: ~ unknown)~~ + +select 'x' ++ ~'y' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: ~ unknown)~~ + +select -'y' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: - unknown)~~ + +select 'x' + -'y' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: - unknown)~~ + +select 'x' ++ -'y' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: - unknown)~~ + diff --git a/test/JDBC/input/unary_plus_op_string-vu-cleanup.sql b/test/JDBC/input/unary_plus_op_string-vu-cleanup.sql new file mode 100644 index 0000000000..20b05cbd91 --- /dev/null +++ b/test/JDBC/input/unary_plus_op_string-vu-cleanup.sql @@ -0,0 +1,11 @@ +drop procedure p1_unary_plus_op_string +go + +drop function f1_unary_plus_op_string +go + +drop view v1_unary_plus_op_string +go + +drop table t1_unary_plus_op_string +go \ No newline at end of file diff --git a/test/JDBC/input/unary_plus_op_string-vu-prepare.sql b/test/JDBC/input/unary_plus_op_string-vu-prepare.sql new file mode 100644 index 0000000000..fa33ec42ae --- /dev/null +++ b/test/JDBC/input/unary_plus_op_string-vu-prepare.sql @@ -0,0 +1,76 @@ +create table t1_unary_plus_op_string(i int, vc varchar(30)) +go + +create view v1_unary_plus_op_string as +select 'view '+++(+N'value1') + ++ /*comment*/ +( ++ /*comment*/ ++ -- comment + +( ++ +'value2'))++(+(select 'value3')) as col1, +1 + -2 as col2, +1 ++ -2 as col3, +1 + ~2 as col4, +1 +++++ ~2 as col5, +1 ++++ (++++ -2) as col6, +1 ++++ (++++ ~2) as col7 +go + +create procedure p1_unary_plus_op_string +as +declare @v varchar(20) = ' test' +declare @i int = 1 +declare @d datetime='2024-Jan-01 01:02:03' +declare @dc decimal(10,4)=1 +select 'proc '+'line1' +select 'proc '++'line2' +select 'proc '++N'line3' +select 'proc '+++++'line4' +select 'proc '+++++"line5" +select 'proc '+ ++ /*comment*/ +( ++ /*comment*/ ++ -- comment + +( ++ +"line6"))+++@v +select 'proc ' ++(++(++(select N'line7')))++(+@v) +select 'proc ' ++ case when len('a'+++ 'b')=2 then 'true' else 'false' end +select 'proc line8' where 'x' in (+'x') +select 'proc line9' where 'x' like +'x' +set @v = 'x' +select 'proc line10' where 'x' like (+@v) +select 'proc line11' where 'x' like +(+(+@v)) +select 'proc line 12 ' ++ vc from t1_unary_plus_op_string order by 1 +select 'proc line 13 ' ++(+vc) from t1_unary_plus_op_string order by 1 +select 'proc line 14 ' ++ [vc] from t1_unary_plus_op_string order by 1 +select 1 + @i, 2 + (+@i), 3 ++++(++(+++@i)) +select +@d, + (+@d), ++++(++(+++@d)) +select 1 +@dc, 2 + (+@dc), 3 ++++(++(+++@dc)) +select 1 + -2 as expr1 +select 1 ++ -2 as expr2 +select 1 + ~2 as expr3 +select 1 +++++ ~2 as expr4 +select 1 ++++ (++++ -2) as expr5 +select 1 ++++ (++++ ~2) as expr6 +EXECUTE('select ''execimm ''++''line1''') +EXECUTE('select ''execimm ''++N''line2''') +EXECUTE('select ''execimm ''++(+(select N''line3''))') +go + +create function f1_unary_plus_op_string (@v varchar(10)) returns varchar(30) +as +begin +declare @s varchar(30) +set @s = 'func '+++(+N'value1') + ++ +( ++ /*comment*/ ++ -- comment + +(++(select "value2")))++(+@v) +return @s +end +go diff --git a/test/JDBC/input/unary_plus_op_string-vu-verify.sql b/test/JDBC/input/unary_plus_op_string-vu-verify.sql new file mode 100644 index 0000000000..4e2dd49d89 --- /dev/null +++ b/test/JDBC/input/unary_plus_op_string-vu-verify.sql @@ -0,0 +1,250 @@ +insert t1_unary_plus_op_string values (1, 'abc') +go + +set quoted_identifier off +go +select 'x'+'y' +go +select 'x' + 'y' +go +select 'x' + +/* comment*/ +'y' +/*comment*/ + + 'z' +go +select 'x'++'y' +go +select 'x'++++++++'y' +go +select 'x'++N'y' +go +select 'x'++++++++N'y' +go +select 'x' ++++++++ 'y' +go +select 'x' ++ ++ +/* comment*/ + + +'y' ++ -- comment + +/*comment*/ ++ + + ++ 'z' +go +declare @v varchar(10)='y' select 'x'+ @v, 'x' +@v, 'x' ++++++@v +go +declare @v varchar(10)='y' select 'x'+ (@v), 'x' + (+@v), 'x' ++++(++(+++@v)) +go +declare @v tinyint=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +declare @v int=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +declare @v bigint=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +declare @v decimal(10,4)=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +declare @v money=1 select 1 +@v, 2 + (+@v), 3 ++++(++(+++@v)) +go +declare @v datetime='2024-Jan-01 01:02:03' select +@v, + (+@v), ++++(++(+++@v)) +go +declare @v datetime2='2024-Jan-01 01:02:03' select +@v, + (+@v), ++++(++(+++@v)) +go +select +'y' +go +select +N'y' +go +select ((+'y')) +go +select ((+N'y')) +go +select ++++(++++++(+++++'y')) +go +select 'x'+(+'y') +go +select 'x'+++((+++(+++'y'))) +go +select 'x'+++( +(+++ +(+++ +'y'))) +go +if 'x' <> + char(13) select 'true' else select 'false' +go +if 'x' <> +++ char(13) select 'true' else select 'false' +go +select len(+'x') +go +select len(+N'x') +go +select 'x' ++ substring('xyz', 2, 1) +go +select 'x' +++++ substring(+'xyz', 2, 1) +go +select 'x' ++ case when len('a'+++ 'b')=2 then 'true' else 'false' end +go +select 'x' ++ case when len(+'a'+++ 'b')=2 then +'true' else +++++'false' end +go +declare @v varchar(10) = 'true' +select 'x' ++ case when len(+'a'+++ 'b')=2 then +@v else 'false' end +go +select 1 where 'x' in (+'x') +go +select 1 where 'x' like +'x' +go +declare @v varchar(10) = 'x' +select 1 where 'x' like (+@v) +go +declare @v varchar(10) = 'x' +select 1 where 'x' like +(+(+@v)) +go +declare @v varchar(10) = 'x' +if 'y' <> + @v select 'true' else select 'false' +go +declare @v varchar(10) = 'x' +if 'y' <> +++ @v select 'true' else select 'false' +set @v = 'x' ++ case when len('a'+++ 'b')=2 then 'true2' else 'false2' end +select @v +go +select 'x' ++vc from t1_unary_plus_op_string order by 1 +go +select 'x' ++(+vc) from t1_unary_plus_op_string order by 1 +go +select +(select 'abc') +go +select ++++(select 'abc') +go +select +(+((select 'abc'))) +go + +/*double-quoted strings*/ +select "x"+"y" +go +select "x" + "y" +go +select "x" + +/* comment*/ +"y" +/*comment*/ + + "z" +go +select "x"++"y" +go +select "x"++++++++"y" +go +select "x" ++++++++ "y" +go +select "x" ++ ++ +/* comment*/ + + +"y" ++ +/*comment*/ ++ + + ++ "z" +go +declare @v varchar(10)="y" select "x"+ @v, "x" +@v, "x" ++++++@v +go +select +"y" +go +select ((+"y")) +go +select ++++(++++++(+++++"y")) +go +select 'x'+(+"y") +go +select "x"+++((+++(+++"y"))) +go +select "x"+++( +(+++ +(+++ +"y"))) +go +if "x" <> + char(13) select "true" else select "false" +go +if "x" <> +++ char(13) select "true" else select "false" +go +select len(+"x") +go +select "x" ++ substring("xyz", 2, 1) +go +select "x" +++++ substring(+"xyz", 2, 1) +go +select "x" ++ case when len("a"+++ "b")=2 then "true" else "false" end +go +declare @v varchar(10) = "true" +select "x" ++ case when len(+"a"+++ 'b')=2 then +@v else +"false" end +go +select 1 where "x" in (+"x") +go +select 1 where "x" like +"x" +go +declare @v varchar(10) = "x" +if "y" <> +++ @v select "true" else select "false" +set @v = "x" ++ case when len(++"a"+++N'b')=2 then "true2" else "false2" end +select @v +go +select +(+((select "abc"))) +go + +/* double-quoted identifiers */ +set quoted_identifier on +go +select 'x' ++ "vc" from t1_unary_plus_op_string order by 1 +go +select 'x' ++((+(++"vc"))) from t1_unary_plus_op_string order by 1 +go +set quoted_identifier off +go + +/* bracket-delimited identifiers */ +select 'x' ++ [vc] from t1_unary_plus_op_string order by 1 +go +select 'x' ++ ((+(++[vc]))) from t1_unary_plus_op_string order by 1 +go + +/*numeric expressions should not be affected*/ +select 1 +-2 +go +select 1 + -2 +go +select 1 ++-2 +go +select 1 + + -2 +go +select 1 + ~2 +go +select 1 ++~2 +go +select 1 ++ ~2 +go +select 1 ++++ (++++ 2) +go +select 1 ++++ (++++ ~2) +go +select 1 ++++ (++++ -2) +go + +/* execute-immediate */ +execute('select ((+''y'')) ') +go +execute('select ''x''+++((+++(+++''y'')))') +go +execute('select ''x'' ++vc from t1_unary_plus_op_string order by 1') +go + +/* SQL objects */ +select * from v1_unary_plus_op_string +go +execute p1_unary_plus_op_string +go +select * from dbo.f1_unary_plus_op_string('test') +go + +/* the following should raise an error: unary operator other than '+' is invalid for a string in T-SQL */ +select ~'y' +go +select 'x' + ~'y' +go +select 'x' ++ ~'y' +go +select -'y' +go +select 'x' + -'y' +go +select 'x' ++ -'y' +go \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 5a08e84bfa..aa3f9e6696 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -497,6 +497,7 @@ set_tran_isolvl with_recompile alter_proc_recompile catalogs_dbo_sys_schema-upgrade +unary_plus_op_string BABEL-4217 Test_ISNULL BABEL-4270 diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 89db9be947..876eca452f 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -796,7 +796,6 @@ Operator sys.+(sys.fixeddecimal,bigint) Operator sys.+(sys.fixeddecimal,integer) Operator sys.+(sys.fixeddecimal,smallint) Operator sys.+(sys.fixeddecimal,sys.fixeddecimal) -Operator sys.+(sys.nvarchar,sys."varchar") Operator sys.+(sys.smallmoney,bigint) Operator sys.+(sys.smallmoney,integer) Operator sys.+(sys.smallmoney,smallint)