From 7904baf248b2890933d0df297f97a14ca8f88216 Mon Sep 17 00:00:00 2001 From: robverschoor Date: Thu, 14 Nov 2024 16:26:12 +0000 Subject: [PATCH 1/2] Support empty double-quoted string in SQL object body --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 18 + .../empty_dq_string_in_object-vu-cleanup.out | 38 ++ .../empty_dq_string_in_object-vu-prepare.out | 23 ++ .../empty_dq_string_in_object-vu-verify.out | 345 ++++++++++++++++++ .../empty_dq_string_in_object-vu-cleanup.sql | 38 ++ .../empty_dq_string_in_object-vu-prepare.sql | 17 + .../empty_dq_string_in_object-vu-verify.sql | 189 ++++++++++ 7 files changed, 668 insertions(+) create mode 100644 test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out create mode 100644 test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out create mode 100644 test/JDBC/expected/empty_dq_string_in_object-vu-verify.out create mode 100644 test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql create mode 100644 test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql create mode 100644 test/JDBC/input/empty_dq_string_in_object-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 36a8ce4e22..e08fd95328 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -3347,6 +3347,24 @@ class tsqlMutator : public TSqlParserBaseListener } } + void enterChar_string(TSqlParser::Char_stringContext *ctx) override + { + std::string str = getFullText(ctx); + if ((str.front() == '"') && (str.back() == '"') && (str.length() == 2)) + { + // This means we have a double-quoted empty, zero-length string. The PG equivalent is a zero-length + // single-quoted string. + // Whenever we reference a double-quoted empty string inside the body of a T-SQL procedure, function or trigger, + // this is passed onto the PG backend where PG interprets double-quoted items as delimited identifiers. + // However those cannot be zero-length, so an error is then raised. + // By changing any double-quoted empty string to a single-quoted empty string we address this use case here. + // This also addresses any references outside those objects; those would otherwise have been rewritten as a + // single-quoted string by rewriteDoubleQuotedString() in the exitChar_string() functions, but doing it + // here preempts that and removes potential complexity from the rewriting in the mutator. + stream.setText(ctx->start->getStartIndex(), "''"); + } + } + // NB: similar code is in tsqlBuilder void exitChar_string(TSqlParser::Char_stringContext *ctx) override { diff --git a/test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out b/test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out new file mode 100644 index 0000000000..ead8034497 --- /dev/null +++ b/test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out @@ -0,0 +1,38 @@ +drop table t1_empty_dq_string +go +drop table t2_empty_dq_string +go +drop table t3_empty_dq_string +go +drop table t4_empty_dq_string +go +drop table t5_empty_dq_string +go +drop table t6_empty_dq_string +go +drop table t7_empty_dq_string +go +drop procedure p1_empty_dq_string +go +drop function f1_empty_dq_string +go +drop procedure p2_empty_dq_string +go +drop function f2_empty_dq_string +go +drop procedure p3_empty_dq_string +go +drop procedure p4_empty_dq_string +go +drop function f4_empty_dq_string +go +drop procedure p5_empty_dq_string +go +drop function f5_empty_dq_string +go +drop procedure p6_empty_dq_string +go +drop procedure p7_empty_dq_string +go +drop procedure p7a_empty_dq_string +go diff --git a/test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out b/test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out new file mode 100644 index 0000000000..7c2935616e --- /dev/null +++ b/test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out @@ -0,0 +1,23 @@ +create table t1_empty_dq_string(a int) +go +create table t2_empty_dq_string(a int) +go +create table t3_empty_dq_string(a int) +go +create table t4_empty_dq_string(a int) +go +create table t5_empty_dq_string(a int, b varchar(10)) +insert t5_empty_dq_string values(1, 'test 1') +go +~~ROW COUNT: 1~~ + +create table t6_empty_dq_string(a int, b varchar(10)) +insert t6_empty_dq_string values(1, 'test 1') +go +~~ROW COUNT: 1~~ + +create table t7_empty_dq_string(a int, b varchar(10)) +insert t7_empty_dq_string values(1, 'test 1') +go +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/empty_dq_string_in_object-vu-verify.out b/test/JDBC/expected/empty_dq_string_in_object-vu-verify.out new file mode 100644 index 0000000000..64e5a796ee --- /dev/null +++ b/test/JDBC/expected/empty_dq_string_in_object-vu-verify.out @@ -0,0 +1,345 @@ + +-- Purpose: a double-quoted empty string inside a SQL object body should be treated as an empty string +set quoted_identifier off +go + +-- SELECT "" +select "" as empty_str +go +~~START~~ +varchar + +~~END~~ + +create procedure p1_empty_dq_string +as +select "" as empty_str +go +exec p1_empty_dq_string +go +~~START~~ +varchar + +~~END~~ + +create function f1_empty_dq_string() returns varchar(10) +as +begin +return "" +end +go +select dbo.f1_empty_dq_string(), len(dbo.f1_empty_dq_string()) +go +~~START~~ +varchar#!#int +#!#0 +~~END~~ + +create trigger tr1_empty_dq_string on t1_empty_dq_string for insert as +begin +select "" as empty_str +end +go +insert t1_empty_dq_string values(1) +go +~~START~~ +varchar + +~~END~~ + +~~ROW COUNT: 1~~ + + +-- variable declaration and assignment +declare @v varchar(10) = "" +set @v = "" +select @v +go +~~START~~ +varchar + +~~END~~ + +create procedure p2_empty_dq_string +as +declare @v varchar(10) = "" +set @v = "" +select @v +go +exec p2_empty_dq_string +go +~~START~~ +varchar + +~~END~~ + +create function f2_empty_dq_string() returns varchar(10) +as +begin +declare @v varchar(10) = "" +set @v = "" +return @v +end +go +select dbo.f2_empty_dq_string(), len(dbo.f2_empty_dq_string()) +go +~~START~~ +varchar#!#int +#!#0 +~~END~~ + +create trigger tr2_empty_dq_string on t2_empty_dq_string for insert as +begin +declare @v varchar(10) = "" +set @v = "" +select @v +end +go +insert t2_empty_dq_string values(1) +go +~~START~~ +varchar + +~~END~~ + +~~ROW COUNT: 1~~ + + +-- print "" (not visible in JDBC test output) +print "" +go +create procedure p3_empty_dq_string +as +print "" +go +exec p3_empty_dq_string +go +create trigger tr3_empty_dq_string on t3_empty_dq_string for insert as +begin +select 'trigger' +print "" +end +go +insert t3_empty_dq_string values(1) +go +~~START~~ +varchar +trigger +~~END~~ + +~~ROW COUNT: 1~~ + + +-- usage in condition +if 'a' = "" select 'branch 1' else select 'branch 2' +go +~~START~~ +varchar +branch 2 +~~END~~ + +create procedure p4_empty_dq_string as +if 'a' = "" select 'branch 1' else select 'branch 2' +go +exec p4_empty_dq_string +go +~~START~~ +varchar +branch 2 +~~END~~ + +create function f4_empty_dq_string() returns int +as +begin +if 'a' = "" return 1 +return 2 +end +go +select dbo.f4_empty_dq_string() +go +~~START~~ +int +2 +~~END~~ + +create trigger tr4_empty_dq_string on t4_empty_dq_string for insert as +begin +if 'a' = "" select 'branch 1' else select 'branch 2' +end +go +insert t4_empty_dq_string values(1) +go +~~START~~ +varchar +branch 2 +~~END~~ + +~~ROW COUNT: 1~~ + + +-- usage in WHERE_clause +select * from t5_empty_dq_string where b = "" order by a +go +~~START~~ +int#!#varchar +~~END~~ + +create procedure p5_empty_dq_string as +select a, '['+b+']' as b from t5_empty_dq_string where b = "" order by a +go +exec p5_empty_dq_string +go +~~START~~ +int#!#varchar +~~END~~ + +create function f5_empty_dq_string() returns int +as +begin +declare @v int +select @v = count(*) from t5_empty_dq_string where b = "" +return @v +end +go +select dbo.f5_empty_dq_string() +go +~~START~~ +int +0 +~~END~~ + +create trigger tr5_empty_dq_string on t5_empty_dq_string for insert as +begin +select a, '['+b+']' as b from t5_empty_dq_string where b = "" order by a +end +go +insert t5_empty_dq_string values(1, 'test 1') +go +~~START~~ +int#!#varchar +~~END~~ + +~~ROW COUNT: 1~~ + + +-- usage in insert +insert t6_empty_dq_string values (2, "") +go +~~ROW COUNT: 1~~ + +create procedure p6_empty_dq_string as +insert t6_empty_dq_string values (3, "") +go +exec p6_empty_dq_string +go +~~ROW COUNT: 1~~ + +select a, '['+b+']' as b from t6_empty_dq_string order by a +go +~~START~~ +int#!#varchar +1#!#[test 1] +2#!#[] +3#!#[] +~~END~~ + +create trigger tr6_empty_dq_string on t6_empty_dq_string for insert as +begin +insert t6_empty_dq_string values (4, "") +end +go +insert t6_empty_dq_string values(1, 'test 1') +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select a, '['+b+']' as b from t6_empty_dq_string order by a +go +~~START~~ +int#!#varchar +1#!#[test 1] +1#!#[test 1] +2#!#[] +3#!#[] +4#!#[] +~~END~~ + + +-- usage in update +update t7_empty_dq_string set b = "" where a = 1 +go +~~ROW COUNT: 1~~ + +create procedure p7_empty_dq_string as +update t7_empty_dq_string set b = "" where a = 1 +go +exec p7_empty_dq_string +go +~~ROW COUNT: 1~~ + +select a, '['+b+']' as b from t7_empty_dq_string order by a +go +~~START~~ +int#!#varchar +1#!#[] +~~END~~ + +create trigger tr7_empty_dq_string on t7_empty_dq_string for insert as +begin +update t7_empty_dq_string set b = "" where a = 1 +end +go +insert t7_empty_dq_string values(2, 'test 2') +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select a, '['+b+']' as b from t7_empty_dq_string order by a +go +~~START~~ +int#!#varchar +1#!#[] +2#!#[test 2] +~~END~~ + + +-- single-space string in update +create procedure p7a_empty_dq_string as +update t7_empty_dq_string set b = " " where a = 1 +go +exec p7a_empty_dq_string +go +~~ROW COUNT: 1~~ + +select a, '['+b+']' as b from t7_empty_dq_string order by a +go +~~START~~ +int#!#varchar +1#!#[ ] +2#!#[test 2] +~~END~~ + +create trigger tr7a_empty_dq_string on t7_empty_dq_string for insert as +begin +update t7_empty_dq_string set b = " " where a = 1 +end +go +insert t7_empty_dq_string values(3, 'test 3') +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select a, '['+b+']' as b from t7_empty_dq_string order by a +go +~~START~~ +int#!#varchar +1#!#[ ] +2#!#[test 2] +3#!#[test 3] +~~END~~ + diff --git a/test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql b/test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql new file mode 100644 index 0000000000..32f97c26f0 --- /dev/null +++ b/test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql @@ -0,0 +1,38 @@ +drop table t1_empty_dq_string +go +drop table t2_empty_dq_string +go +drop table t3_empty_dq_string +go +drop table t4_empty_dq_string +go +drop table t5_empty_dq_string +go +drop table t6_empty_dq_string +go +drop table t7_empty_dq_string +go +drop procedure p1_empty_dq_string +go +drop function f1_empty_dq_string +go +drop procedure p2_empty_dq_string +go +drop function f2_empty_dq_string +go +drop procedure p3_empty_dq_string +go +drop procedure p4_empty_dq_string +go +drop function f4_empty_dq_string +go +drop procedure p5_empty_dq_string +go +drop function f5_empty_dq_string +go +drop procedure p6_empty_dq_string +go +drop procedure p7_empty_dq_string +go +drop procedure p7a_empty_dq_string +go \ No newline at end of file diff --git a/test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql b/test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql new file mode 100644 index 0000000000..665abf77d4 --- /dev/null +++ b/test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql @@ -0,0 +1,17 @@ +create table t1_empty_dq_string(a int) +go +create table t2_empty_dq_string(a int) +go +create table t3_empty_dq_string(a int) +go +create table t4_empty_dq_string(a int) +go +create table t5_empty_dq_string(a int, b varchar(10)) +insert t5_empty_dq_string values(1, 'test 1') +go +create table t6_empty_dq_string(a int, b varchar(10)) +insert t6_empty_dq_string values(1, 'test 1') +go +create table t7_empty_dq_string(a int, b varchar(10)) +insert t7_empty_dq_string values(1, 'test 1') +go diff --git a/test/JDBC/input/empty_dq_string_in_object-vu-verify.sql b/test/JDBC/input/empty_dq_string_in_object-vu-verify.sql new file mode 100644 index 0000000000..7dca054117 --- /dev/null +++ b/test/JDBC/input/empty_dq_string_in_object-vu-verify.sql @@ -0,0 +1,189 @@ +-- Purpose: a double-quoted empty string inside a SQL object body should be treated as an empty string + +set quoted_identifier off +go + +-- SELECT "" +select "" as empty_str +go +create procedure p1_empty_dq_string +as +select "" as empty_str +go +exec p1_empty_dq_string +go +create function f1_empty_dq_string() returns varchar(10) +as +begin +return "" +end +go +select dbo.f1_empty_dq_string(), len(dbo.f1_empty_dq_string()) +go +create trigger tr1_empty_dq_string on t1_empty_dq_string for insert as +begin +select "" as empty_str +end +go +insert t1_empty_dq_string values(1) +go + +-- variable declaration and assignment +declare @v varchar(10) = "" +set @v = "" +select @v +go +create procedure p2_empty_dq_string +as +declare @v varchar(10) = "" +set @v = "" +select @v +go +exec p2_empty_dq_string +go +create function f2_empty_dq_string() returns varchar(10) +as +begin +declare @v varchar(10) = "" +set @v = "" +return @v +end +go +select dbo.f2_empty_dq_string(), len(dbo.f2_empty_dq_string()) +go +create trigger tr2_empty_dq_string on t2_empty_dq_string for insert as +begin +declare @v varchar(10) = "" +set @v = "" +select @v +end +go +insert t2_empty_dq_string values(1) +go + +-- print "" (not visible in JDBC test output) +print "" +go +create procedure p3_empty_dq_string +as +print "" +go +exec p3_empty_dq_string +go +create trigger tr3_empty_dq_string on t3_empty_dq_string for insert as +begin +select 'trigger' +print "" +end +go +insert t3_empty_dq_string values(1) +go + +-- usage in condition +if 'a' = "" select 'branch 1' else select 'branch 2' +go +create procedure p4_empty_dq_string as +if 'a' = "" select 'branch 1' else select 'branch 2' +go +exec p4_empty_dq_string +go +create function f4_empty_dq_string() returns int +as +begin +if 'a' = "" return 1 +return 2 +end +go +select dbo.f4_empty_dq_string() +go +create trigger tr4_empty_dq_string on t4_empty_dq_string for insert as +begin +if 'a' = "" select 'branch 1' else select 'branch 2' +end +go +insert t4_empty_dq_string values(1) +go + +-- usage in WHERE_clause +select * from t5_empty_dq_string where b = "" order by a +go +create procedure p5_empty_dq_string as +select a, '['+b+']' as b from t5_empty_dq_string where b = "" order by a +go +exec p5_empty_dq_string +go +create function f5_empty_dq_string() returns int +as +begin +declare @v int +select @v = count(*) from t5_empty_dq_string where b = "" +return @v +end +go +select dbo.f5_empty_dq_string() +go +create trigger tr5_empty_dq_string on t5_empty_dq_string for insert as +begin +select a, '['+b+']' as b from t5_empty_dq_string where b = "" order by a +end +go +insert t5_empty_dq_string values(1, 'test 1') +go + +-- usage in insert +insert t6_empty_dq_string values (2, "") +go +create procedure p6_empty_dq_string as +insert t6_empty_dq_string values (3, "") +go +exec p6_empty_dq_string +go +select a, '['+b+']' as b from t6_empty_dq_string order by a +go +create trigger tr6_empty_dq_string on t6_empty_dq_string for insert as +begin +insert t6_empty_dq_string values (4, "") +end +go +insert t6_empty_dq_string values(1, 'test 1') +go +select a, '['+b+']' as b from t6_empty_dq_string order by a +go + +-- usage in update +update t7_empty_dq_string set b = "" where a = 1 +go +create procedure p7_empty_dq_string as +update t7_empty_dq_string set b = "" where a = 1 +go +exec p7_empty_dq_string +go +select a, '['+b+']' as b from t7_empty_dq_string order by a +go +create trigger tr7_empty_dq_string on t7_empty_dq_string for insert as +begin +update t7_empty_dq_string set b = "" where a = 1 +end +go +insert t7_empty_dq_string values(2, 'test 2') +go +select a, '['+b+']' as b from t7_empty_dq_string order by a +go + +-- single-space string in update +create procedure p7a_empty_dq_string as +update t7_empty_dq_string set b = " " where a = 1 +go +exec p7a_empty_dq_string +go +select a, '['+b+']' as b from t7_empty_dq_string order by a +go +create trigger tr7a_empty_dq_string on t7_empty_dq_string for insert as +begin +update t7_empty_dq_string set b = " " where a = 1 +end +go +insert t7_empty_dq_string values(3, 'test 3') +go +select a, '['+b+']' as b from t7_empty_dq_string order by a +go From d218a6771b8dcf714c0b52edc98d661038acd41e Mon Sep 17 00:00:00 2001 From: robverschoor Date: Thu, 14 Nov 2024 18:30:07 +0000 Subject: [PATCH 2/2] add more test cases --- .../empty_dq_string_in_object-vu-cleanup.out | 20 ++ .../empty_dq_string_in_object-vu-prepare.out | 8 + .../empty_dq_string_in_object-vu-verify.out | 216 +++++++++++++++++- .../empty_dq_string_in_object-vu-cleanup.sql | 20 ++ .../empty_dq_string_in_object-vu-prepare.sql | 6 + .../empty_dq_string_in_object-vu-verify.sql | 108 ++++++++- 6 files changed, 369 insertions(+), 9 deletions(-) diff --git a/test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out b/test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out index ead8034497..61bc654f33 100644 --- a/test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out +++ b/test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out @@ -20,6 +20,12 @@ drop procedure p2_empty_dq_string go drop function f2_empty_dq_string go +drop procedure p2a_empty_dq_string +go +drop function f2a_empty_dq_string +go +drop procedure p2b_empty_dq_string +go drop procedure p3_empty_dq_string go drop procedure p4_empty_dq_string @@ -36,3 +42,17 @@ drop procedure p7_empty_dq_string go drop procedure p7a_empty_dq_string go +drop procedure p7b_empty_dq_string +go +drop function f7b_empty_dq_string +go +drop procedure p7c_empty_dq_string +go +set quoted_identifier on +go +drop table "t8_empty_dq_string" +go +drop procedure "p8_empty_dq_string" +go +drop function "f8_empty_dq_string" +go diff --git a/test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out b/test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out index 7c2935616e..2afb2d9274 100644 --- a/test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out +++ b/test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out @@ -21,3 +21,11 @@ insert t7_empty_dq_string values(1, 'test 1') go ~~ROW COUNT: 1~~ + +set quoted_identifier on +go +create table "t8_empty_dq_string"("a" int, "b" varchar(10)) +insert "t8_empty_dq_string" values(1, 'test 1') +go +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/empty_dq_string_in_object-vu-verify.out b/test/JDBC/expected/empty_dq_string_in_object-vu-verify.out index 64e5a796ee..517c6bb4a5 100644 --- a/test/JDBC/expected/empty_dq_string_in_object-vu-verify.out +++ b/test/JDBC/expected/empty_dq_string_in_object-vu-verify.out @@ -78,14 +78,14 @@ as begin declare @v varchar(10) = "" set @v = "" -return @v +return '['+@v+']' end go select dbo.f2_empty_dq_string(), len(dbo.f2_empty_dq_string()) go ~~START~~ varchar#!#int -#!#0 +[]#!#2 ~~END~~ create trigger tr2_empty_dq_string on t2_empty_dq_string for insert as @@ -105,6 +105,67 @@ varchar ~~ROW COUNT: 1~~ +-- execute immediate +execute("") +go + +-- argument for procedure/function call +create procedure p2a_empty_dq_string @p varchar(10) +as +select '['+@p+']' as p, len(@p) as len +go +exec p2a_empty_dq_string "" +go +~~START~~ +varchar#!#int +[]#!#0 +~~END~~ + +exec p2a_empty_dq_string @p="" +go +~~START~~ +varchar#!#int +[]#!#0 +~~END~~ + +create function f2a_empty_dq_string(@p varchar(10)) returns varchar(10) +as +begin +return '['+@p+']' +end +go +select dbo.f2a_empty_dq_string(""), len(dbo.f2a_empty_dq_string("")) +go +~~START~~ +varchar#!#int +[]#!#2 +~~END~~ + + +create procedure p2b_empty_dq_string @p varchar(10) +as +exec p2a_empty_dq_string "" +exec p2a_empty_dq_string @p="" +select dbo.f2a_empty_dq_string(""), len(dbo.f2a_empty_dq_string("")) +go +exec p2b_empty_dq_string "" +go +~~START~~ +varchar#!#int +[]#!#0 +~~END~~ + +~~START~~ +varchar#!#int +[]#!#0 +~~END~~ + +~~START~~ +varchar#!#int +[]#!#2 +~~END~~ + + -- print "" (not visible in JDBC test output) print "" go @@ -198,15 +259,16 @@ as begin declare @v int select @v = count(*) from t5_empty_dq_string where b = "" -return @v +return '['+@v+']' end go select dbo.f5_empty_dq_string() go ~~START~~ int -0 -~~END~~ +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "[")~~ create trigger tr5_empty_dq_string on t5_empty_dq_string for insert as begin @@ -305,7 +367,7 @@ int#!#varchar ~~END~~ --- single-space string in update +-- single-space string in update: not affected create procedure p7a_empty_dq_string as update t7_empty_dq_string set b = " " where a = 1 go @@ -343,3 +405,145 @@ int#!#varchar 3#!#[test 3] ~~END~~ + + +-- single-space string: argument for procedure/function call +create procedure p7b_empty_dq_string @p varchar(10) +as +select '['+@p+']' as p, len(@p) as len +go +exec p7b_empty_dq_string " " +go +~~START~~ +varchar#!#int +[ ]#!#0 +~~END~~ + +exec p7b_empty_dq_string @p=" " +go +~~START~~ +varchar#!#int +[ ]#!#0 +~~END~~ + +create function f7b_empty_dq_string(@p varchar(10)) returns varchar(10) +as +begin +return '['+@p+']' +end +go +select dbo.f7b_empty_dq_string(" "), len(dbo.f7b_empty_dq_string(" ")) +go +~~START~~ +varchar#!#int +[ ]#!#3 +~~END~~ + + +create procedure p7c_empty_dq_string @p varchar(10) +as +exec p7b_empty_dq_string " " +exec p7b_empty_dq_string @p=" " +select dbo.f7b_empty_dq_string(" "), len(dbo.f7b_empty_dq_string(" ")) +go +exec p7c_empty_dq_string " " +go +~~START~~ +varchar#!#int +[ ]#!#0 +~~END~~ + +~~START~~ +varchar#!#int +[ ]#!#0 +~~END~~ + +~~START~~ +varchar#!#int +[ ]#!#3 +~~END~~ + + +-- double-quoted identifier: not affected +set quoted_identifier on +go + +-- SELECT "" +select * from "t8_empty_dq_string" order by "a" +go +~~START~~ +int#!#varchar +1#!#test 1 +~~END~~ + +create procedure "p8_empty_dq_string" +as +select * from "t8_empty_dq_string" order by "a" +go +exec "p8_empty_dq_string" +go +~~START~~ +int#!#varchar +1#!#test 1 +~~END~~ + +create function "f8_empty_dq_string"() returns varchar(10) +as +begin +return '' +end +go +select dbo."f8_empty_dq_string"(), len(dbo."f8_empty_dq_string"()) +go +~~START~~ +varchar#!#int +#!#0 +~~END~~ + +create trigger "tr8_empty_dq_string" on "t8_empty_dq_string" for insert as +begin +select * from "t8_empty_dq_string" order by "a" +end +go +insert "t8_empty_dq_string" values(2, 'test 2') +go +~~START~~ +int#!#varchar +1#!#test 1 +2#!#test 2 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from "t8_empty_dq_string" order by "a" +go +~~START~~ +int#!#varchar +1#!#test 1 +2#!#test 2 +~~END~~ + + +-- double-quoted identifier of length 0: invalid in T-SQL, should raise error +create table "" (a int) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero-length delimited identifier at or near """")~~ + +select * from "" +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero-length delimited identifier at or near """")~~ + +-- execute immediate +execute("") +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '""' at line 2 and character position 8)~~ + + +set quoted_identifier off +go diff --git a/test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql b/test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql index 32f97c26f0..c7531672ed 100644 --- a/test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql +++ b/test/JDBC/input/empty_dq_string_in_object-vu-cleanup.sql @@ -20,6 +20,12 @@ drop procedure p2_empty_dq_string go drop function f2_empty_dq_string go +drop procedure p2a_empty_dq_string +go +drop function f2a_empty_dq_string +go +drop procedure p2b_empty_dq_string +go drop procedure p3_empty_dq_string go drop procedure p4_empty_dq_string @@ -35,4 +41,18 @@ go drop procedure p7_empty_dq_string go drop procedure p7a_empty_dq_string +go +drop procedure p7b_empty_dq_string +go +drop function f7b_empty_dq_string +go +drop procedure p7c_empty_dq_string +go +set quoted_identifier on +go +drop table "t8_empty_dq_string" +go +drop procedure "p8_empty_dq_string" +go +drop function "f8_empty_dq_string" go \ No newline at end of file diff --git a/test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql b/test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql index 665abf77d4..84150a437a 100644 --- a/test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql +++ b/test/JDBC/input/empty_dq_string_in_object-vu-prepare.sql @@ -15,3 +15,9 @@ go create table t7_empty_dq_string(a int, b varchar(10)) insert t7_empty_dq_string values(1, 'test 1') go + +set quoted_identifier on +go +create table "t8_empty_dq_string"("a" int, "b" varchar(10)) +insert "t8_empty_dq_string" values(1, 'test 1') +go diff --git a/test/JDBC/input/empty_dq_string_in_object-vu-verify.sql b/test/JDBC/input/empty_dq_string_in_object-vu-verify.sql index 7dca054117..08eca2a87d 100644 --- a/test/JDBC/input/empty_dq_string_in_object-vu-verify.sql +++ b/test/JDBC/input/empty_dq_string_in_object-vu-verify.sql @@ -46,7 +46,7 @@ as begin declare @v varchar(10) = "" set @v = "" -return @v +return '['+@v+']' end go select dbo.f2_empty_dq_string(), len(dbo.f2_empty_dq_string()) @@ -61,6 +61,37 @@ go insert t2_empty_dq_string values(1) go +-- execute immediate +execute("") +go + +-- argument for procedure/function call +create procedure p2a_empty_dq_string @p varchar(10) +as +select '['+@p+']' as p, len(@p) as len +go +exec p2a_empty_dq_string "" +go +exec p2a_empty_dq_string @p="" +go +create function f2a_empty_dq_string(@p varchar(10)) returns varchar(10) +as +begin +return '['+@p+']' +end +go +select dbo.f2a_empty_dq_string(""), len(dbo.f2a_empty_dq_string("")) +go + +create procedure p2b_empty_dq_string @p varchar(10) +as +exec p2a_empty_dq_string "" +exec p2a_empty_dq_string @p="" +select dbo.f2a_empty_dq_string(""), len(dbo.f2a_empty_dq_string("")) +go +exec p2b_empty_dq_string "" +go + -- print "" (not visible in JDBC test output) print "" go @@ -117,7 +148,7 @@ as begin declare @v int select @v = count(*) from t5_empty_dq_string where b = "" -return @v +return '['+@v+']' end go select dbo.f5_empty_dq_string() @@ -170,7 +201,7 @@ go select a, '['+b+']' as b from t7_empty_dq_string order by a go --- single-space string in update +-- single-space string in update: not affected create procedure p7a_empty_dq_string as update t7_empty_dq_string set b = " " where a = 1 go @@ -187,3 +218,74 @@ insert t7_empty_dq_string values(3, 'test 3') go select a, '['+b+']' as b from t7_empty_dq_string order by a go + + +-- single-space string: argument for procedure/function call +create procedure p7b_empty_dq_string @p varchar(10) +as +select '['+@p+']' as p, len(@p) as len +go +exec p7b_empty_dq_string " " +go +exec p7b_empty_dq_string @p=" " +go +create function f7b_empty_dq_string(@p varchar(10)) returns varchar(10) +as +begin +return '['+@p+']' +end +go +select dbo.f7b_empty_dq_string(" "), len(dbo.f7b_empty_dq_string(" ")) +go + +create procedure p7c_empty_dq_string @p varchar(10) +as +exec p7b_empty_dq_string " " +exec p7b_empty_dq_string @p=" " +select dbo.f7b_empty_dq_string(" "), len(dbo.f7b_empty_dq_string(" ")) +go +exec p7c_empty_dq_string " " +go + +-- double-quoted identifier: not affected +set quoted_identifier on +go + +-- SELECT "" +select * from "t8_empty_dq_string" order by "a" +go +create procedure "p8_empty_dq_string" +as +select * from "t8_empty_dq_string" order by "a" +go +exec "p8_empty_dq_string" +go +create function "f8_empty_dq_string"() returns varchar(10) +as +begin +return '' +end +go +select dbo."f8_empty_dq_string"(), len(dbo."f8_empty_dq_string"()) +go +create trigger "tr8_empty_dq_string" on "t8_empty_dq_string" for insert as +begin +select * from "t8_empty_dq_string" order by "a" +end +go +insert "t8_empty_dq_string" values(2, 'test 2') +go +select * from "t8_empty_dq_string" order by "a" +go + +-- double-quoted identifier of length 0: invalid in T-SQL, should raise error +create table "" (a int) +go +select * from "" +go +-- execute immediate +execute("") +go + +set quoted_identifier off +go \ No newline at end of file