Skip to content

Commit

Permalink
Fix the issue of preserving case of column names in SELECT corrname.c…
Browse files Browse the repository at this point in the history
…olname and Fix the issue of preserving case of column names in SELECT corrname.colname. (babelfish-for-postgresql#1941)

This commit fix preserving the original case spelling of column names while selecting named column with a correlation
name. It also fix the crash is pre_transform_target_entry for queries that involves DELETE ... OUTPUT with JOIN
statement.

Issue 1:
When selecting named column with a correlation name, the lowercase spelling is always returned. The case of column
name is not preserved. For instance, select ABC from table, here ABC is the column name. In this case column name
becomes down cased. To address this issue, We've made some code modifications to ensure that the column name is
handled correctly, whether it's truncated or its case needs to be preserved.

Issue 2:
For the delete queries with join statement, somehow the res->location is not processed correctly. This causes server to
crash as the value of last_dot pointer has never been computed. In this commit, we implemented a check which first
computed whether the res->location is correct or not and then further proceed with the code.

Task: BABEL-4279, BABEL-4484
Signed-off-by: Riya Jain <[email protected]>
  • Loading branch information
riyajain39 authored Oct 26, 2023
1 parent 6f64310 commit 3b93f27
Show file tree
Hide file tree
Showing 16 changed files with 825 additions and 5 deletions.
72 changes: 67 additions & 5 deletions contrib/babelfishpg_tsql/src/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1338,8 +1338,11 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate,
if (exprKind == EXPR_KIND_SELECT_TARGET)
{
int alias_len = 0;
const char *colname_start;
const char *colname_start = NULL;
const char *identifier_name = NULL;
int open_square_bracket = 0;
int double_quotes = 0;
const char *last_dot;

if (res->name == NULL && res->location != -1 &&
IsA(res->val, ColumnRef))
Expand All @@ -1349,15 +1352,74 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate,
/*
* If no alias is specified on a ColumnRef, then get the length of
* the name from the ColumnRef and copy the column name from the
* sourcetext.
* sourcetext. To prevent the server crash, res->location for queries
* with join statement should not be zero.
*/
if (list_length(cref->fields) == 1 &&
IsA(linitial(cref->fields), String))
if (res->location != 0 && (list_length(cref->fields) == 1 &&
IsA(linitial(cref->fields), String)))
{
identifier_name = strVal(linitial(cref->fields));
alias_len = strlen(identifier_name);
colname_start = pstate->p_sourcetext + res->location;
}
/*
* This condition will preserve the case of column name when there are more than
* one cref->fields. For instance, Queries like
* 1. select [database].[schema].[table].[column] from table.
* 2. select [schema].[table].[column] from table.
* 3. select [t].[column] from table as t
* Case 1: Handle the cases when column name is passed with no delimiters
* For example, select ABC from table
* Case 2: Handle the cases when column name is delimited with dq.
* In such cases, we are checking if no. of dq are even or not. When dq are odd,
* we are not tracing number of sqb and sq within dq.
* For instance, Queries like select "AF bjs'vs] " from table.
* Case 3: Handle the case when column name is delimited with sqb. When number of sqb
* are zero, it means we are out of sqb.
*/
else if(res->location != 0 && (list_length(cref->fields) > 1 &&
IsA(llast(cref->fields), String)))
{
identifier_name = strVal(llast(cref->fields));
alias_len = strlen(identifier_name);
colname_start = pstate->p_sourcetext + res->location;
last_dot = colname_start;
while(*colname_start != '\0')
{
if(open_square_bracket == 0 && *colname_start == '"')
{
double_quotes++;
}
/* To check how many open sqb are present in sourcetext. */
else if(double_quotes % 2 == 0 && *colname_start == '[')
{
open_square_bracket++;
}
else if(double_quotes % 2 == 0 && *colname_start == ']')
{
open_square_bracket--;
}
/*
* last_dot pointer is to trace the last dot in the sourcetext,
* as last dot indicates the starting of column name.
*/
else if(open_square_bracket == 0 && double_quotes % 2 == 0 && *colname_start == '.')
{
last_dot = colname_start;
}
/*
* If there is no open sqb, there are even no. of sq or dq and colname_start is at
* space or comma, it means colname_start is at the end of column name.
*/
else if(open_square_bracket == 0 && double_quotes % 2 == 0 && (*colname_start == ' ' || *colname_start == ','))
{
last_dot++;
colname_start = last_dot;
break;
}
colname_start++;
}
}
}
else if (res->name != NULL && res->name_location != -1)
{
Expand All @@ -1383,7 +1445,7 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate,
int actual_alias_len = 0;

/* To handle queries like SELECT ((<column_name>)) from <table_name> */
while(*colname_start == '(' || scanner_isspace(*colname_start))
while(*colname_start != '\0' && (*colname_start == '(' || scanner_isspace(*colname_start)))
{
colname_start++;
}
Expand Down
60 changes: 60 additions & 0 deletions test/JDBC/expected/BABEL-4279-vu-cleanup.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
-- tsql
DROP VIEW test_babel_4279_v1;
GO

DROP VIEW test_babel_4279_v2;
GO

DROP VIEW test_babel_4279_v3;
GO

DROP TABLE test_babel_4279_t1;
GO

USE [test_babel_4279_d.1];
GO

DROP VIEW test_babel_4279_sv1;
GO

DROP TABLE test_babel_4279_s1.test_babel_4279_st1;
GO

DROP SCHEMA test_babel_4279_s1;
GO

USE MASTER;
GO

DROP DATABASE [test_babel_4279_d.1];
GO

DROP VIEW test_babel_4279_v4;
GO

DROP VIEW test_babel_4279_v5;
GO

DROP TABLE test_babel_4279_t2;
GO

DROP VIEW test_babel_4279_v6;
GO

DROP TABLE "tngdf'".[sc,sdg"fdsngjds'];
GO

DROP SCHEMA "tngdf'";
GO

DROP VIEW test_babel_4279_v7;
GO

DROP TABLE test_babel_4279_t3;
GO

DROP VIEW test_babel_4279_v8;
GO

DROP TABLE test_babel_4279_t4;
GO
60 changes: 60 additions & 0 deletions test/JDBC/expected/BABEL-4279-vu-prepare.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
-- tsql
CREATE TABLE test_babel_4279_t1([ABC.nfds] INT, [DEf.j] INT);
GO

CREATE VIEW test_babel_4279_v1 AS SELECT test_babel_4279_t1.[ABC.nfds] from test_babel_4279_t1;
GO

CREATE VIEW test_babel_4279_v2 AS SELECT [test_babel_4279_t1].[ABC.nfds] ,test_babel_4279_t1.[DEf.j] from test_babel_4279_t1;
GO

CREATE DATABASE [test_babel_4279_d.1];
GO

USE [test_babel_4279_d.1];
GO

CREATE SCHEMA test_babel_4279_s1;
GO

CREATE TABLE test_babel_4279_s1.test_babel_4279_st1([ABC.nfds] INT, [DEf.j] INT);
GO

CREATE VIEW test_babel_4279_sv1 AS SELECT [test_babel_4279_s1].[test_babel_4279_st1].[ABC.nfds] from test_babel_4279_s1.test_babel_4279_st1;
GO

USE MASTER
GO

CREATE VIEW test_babel_4279_v3 AS SELECT [test_babel_4279_d.1].[test_babel_4279_s1].[test_babel_4279_st1].[ABC.nfds] from [test_babel_4279_d.1].[test_babel_4279_s1].[test_babel_4279_st1];
GO

CREATE TABLE test_babel_4279_t2(您您对您对您对您对您对您对您对您对您对您您您 INT, 对您对您对您对您对您对您对您 INT);
GO

CREATE VIEW test_babel_4279_v4 AS SELECT test_babel_4279_t2.[您您对您对您对您对您对您对您对您对您对您您您] from test_babel_4279_t2;
GO

CREATE VIEW test_babel_4279_v5 AS SELECT ぁあ.[您您对您对您对您对您对您对您对您对您对您您您] from test_babel_4279_t2 AS ぁあ;
GO

CREATE SCHEMA "tngdf'";
GO

CREATE TABLE "tngdf'".[sc,sdg"fdsngjds']("AB[C" INT);
GO

CREATE VIEW test_babel_4279_v6 AS SELECT "tngdf'".[sc,sdg"fdsngjds']."AB[C" from "tngdf'".[sc,sdg"fdsngjds'];
GO

CREATE TABLE test_babel_4279_t3(ABCD INT);
GO

CREATE VIEW test_babel_4279_v7 AS SELECT test_babel_4279_t3.ABCD FROM test_babel_4279_t3;
GO

CREATE TABLE test_babel_4279_t4([ぁあ'"] INT);
GO

CREATE VIEW test_babel_4279_v8 AS SELECT test_babel_4279_t4.[ぁあ'"] FROM test_babel_4279_t4;
GO
72 changes: 72 additions & 0 deletions test/JDBC/expected/BABEL-4279-vu-verify.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
-- psql
SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v1';
GO
~~START~~
text
SELECT test_babel_4279_t1."abc.nfds" AS "ABC.nfds"<newline> FROM master_dbo.test_babel_4279_t1;
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v2';
GO
~~START~~
text
SELECT test_babel_4279_t1."abc.nfds" AS "ABC.nfds",<newline> test_babel_4279_t1."def.j" AS "DEf.j"<newline> FROM master_dbo.test_babel_4279_t1;
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_sv1';
GO
~~START~~
text
SELECT test_babel_4279_st1."abc.nfds" AS "ABC.nfds"<newline> FROM "test_babel_4279_d.1_test_babel_4279_s1".test_babel_4279_st1;
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v3';
GO
~~START~~
text
SELECT test_babel_4279_st1."abc.nfds" AS "ABC.nfds"<newline> FROM "test_babel_4279_d.1_test_babel_4279_s1".test_babel_4279_st1;
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v4';
GO
~~START~~
text
SELECT test_babel_4279_t2."您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de"<newline> FROM master_dbo.test_babel_4279_t2;
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v5';
GO
~~START~~
text
SELECT "ぁあ"."您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de"<newline> FROM master_dbo.test_babel_4279_t2 "ぁあ";
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v6';
GO
~~START~~
text
SELECT "sc,sdg""fdsngjds'"."ab[c" AS "AB[C"<newline> FROM "master_tngdf'"."sc,sdg""fdsngjds'";
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v7';
GO
~~START~~
text
SELECT test_babel_4279_t3.abcd AS "ABCD"<newline> FROM master_dbo.test_babel_4279_t3;
~~END~~


SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v8';
GO
~~START~~
text
SELECT test_babel_4279_t4."ぁあ'"""<newline> FROM master_dbo.test_babel_4279_t4;
~~END~~

Loading

0 comments on commit 3b93f27

Please sign in to comment.