Skip to content

Commit

Permalink
Support empty double-quoted string in SQL object body (babelfish-for-…
Browse files Browse the repository at this point in the history
…postgresql#3121)

This fixes the long-standing bug that a reference to a double-quoted empty string, when located in the body of a procedure, function or trigger, raises an error even though QUOTED_IDENTIFIER is OFF. This is due to the PG backend interpreting any double-quoted string as an identifier, whose length cannot be zero. It is fixed by replacing "" by '' at the ANTLR stage.

Signed-off-by: Rob Verschoor <[email protected]>
  • Loading branch information
robverschoor authored and roshan0708 committed Nov 20, 2024
1 parent 51a326e commit 4278428
Show file tree
Hide file tree
Showing 7 changed files with 1,028 additions and 0 deletions.
18 changes: 18 additions & 0 deletions contrib/babelfishpg_tsql/src/tsqlIface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3349,6 +3349,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
{
Expand Down
58 changes: 58 additions & 0 deletions test/JDBC/expected/empty_dq_string_in_object-vu-cleanup.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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 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
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
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
31 changes: 31 additions & 0 deletions test/JDBC/expected/empty_dq_string_in_object-vu-prepare.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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~~


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~~

Loading

0 comments on commit 4278428

Please sign in to comment.