From 5f38213a1ffaf5fe55d9a0e31f386b1ef743d81e Mon Sep 17 00:00:00 2001 From: wangfeihuo Date: Mon, 10 Feb 2025 16:19:25 +0800 Subject: [PATCH] add some sql-server programmer --- .../shark/expected/sql-server-test-part2.out | 730 ++++++++++++++++++ contrib/shark/parallel_schedule | 2 + contrib/shark/shark.cpp | 19 + contrib/shark/shark.h | 7 + contrib/shark/sql/sql-server-test-part2.sql | 296 +++++++ .../shark/src/backend_parser/gram-tsql-decl.y | 5 +- .../backend_parser/gram-tsql-epilogue.y.cpp | 1 + .../shark/src/backend_parser/gram-tsql-rule.y | 49 +- contrib/shark/src/backend_parser/kwlist.h | 3 - .../backend_parser/scan-tsql-epilogue.l.cpp | 2 + .../backend_parser/scan-tsql-prologue-top.l.h | 3 +- .../src/backend_parser/scan-tsql-prologue.l.h | 3 +- contrib/shark/src/pltsql/gram.y | 8 +- contrib/shark/src/pltsql/pl_scanner.cpp | 2 +- src/common/backend/parser/gram.y | 59 +- src/common/backend/parser/parse_clause.cpp | 7 +- src/common/backend/parser/parse_expr.cpp | 23 +- src/common/backend/utils/misc/guc.cpp | 1 + src/common/backend/utils/misc/guc/guc_sql.cpp | 41 +- src/common/pl/plpgsql/src/gram.y | 2 +- src/include/executor/spi.h | 2 +- .../knl/knl_guc/knl_session_attr_sql.h | 1 + src/include/nodes/parsenodes_common.h | 2 + src/include/postgres_fe.h | 4 +- 24 files changed, 1249 insertions(+), 23 deletions(-) create mode 100644 contrib/shark/expected/sql-server-test-part2.out create mode 100644 contrib/shark/sql/sql-server-test-part2.sql diff --git a/contrib/shark/expected/sql-server-test-part2.out b/contrib/shark/expected/sql-server-test-part2.out new file mode 100644 index 0000000000..f44e8cc496 --- /dev/null +++ b/contrib/shark/expected/sql-server-test-part2.out @@ -0,0 +1,730 @@ +create database sql_server_test_part2 dbcompatibility 'D'; +\c sql_server_test_part2 +create extension shark; +\c contrib_regression +create schema sql_server_test_part2; +set search_path = 'sql_server_test_part2'; +-- part1: pivot +CREATE TABLE sales (year INT, product VARCHAR(50), amount DECIMAL(10, 2)); +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot; + year | a | b +------+---+--- + 2021 | 0 | 0 + 2020 | 0 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ); + year | a | b +------+---+--- + 2021 | 0 | 0 + 2020 | 0 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ) pivot_table; + year | a | b +------+---+--- + 2021 | 0 | 0 + 2020 | 0 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, 'A', 'SSS', 1, 2, 2.3, 1011) +) as pivot_table; + year | a | b | A | SSS | 1 | 2 | 2.3 | 1011 +------+---+---+---+-----+---+---+-----+------ + 2021 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 + 2020 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot; + year | amount | a | b +------+--------+---+--- + 2021 | 250.00 | 0 | 0 + 2021 | 150.00 | 0 | 0 + 2020 | 200.00 | 0 | 0 + 2020 | 100.00 | 0 | 0 +(4 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot order by year; + year | a | b +------+---+--- + 2020 | 0 | 0 + 2021 | 0 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + year | amount | a | b +------+--------+---+--- + 2021 | 250.00 | 0 | 0 + 2021 | 150.00 | 0 | 0 + 2020 | 200.00 | 0 | 0 + 2020 | 100.00 | 0 | 0 +(4 rows) + +-- expect error +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where source_table.year > 1; +ERROR: missing FROM-clause entry for table "source_table" +LINE 4: ) as pivot_table where source_table.year > 1; + ^ +CREATE PROCEDURE proc1(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN ('A', 'B')) ; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ +--CALL proc1(param1:='123'); +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'A'; + con2 = 'B'; + sql1 = 'SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN (''' || con1 || ''',''' || con2 || '''))'; + EXECUTE IMMEDIATE sql1; +end; +/ + create table CategoryTable2 ( + MergeDocID bigint, + CategoryFieldName nvarchar(100), + CategoryFieldValue nvarchar(255) + ); + + select * + from CategoryTable2 rotate (max(CategoryFieldValue ) + for CategoryFieldName + in (ItemAssetCategory_Code, ItemCostCategory_Code, ItemCreditCategory_Code, ItemMRPCategory_Code, ItemPriceCategory_Code, ItemProductionCategory_Code, ItemPurchaseCategory_Code, ItemSaleCategory_Code, ItemStockCategory_Code, ItemAssetCategory_Name, ItemCostCategory_Name, ItemCreditCategory_Name, ItemMRPCategory_Name, ItemPriceCategory_Name, ItemProductionCategory_Name, ItemPurchaseCategory_Name, ItemSaleCategory_Name, ItemStockCategory_Name)); + mergedocid | itemassetcategory_code | itemcostcategory_code | itemcreditcategory_code | itemmrpcategory_code | itempricecategory_code | itemproductioncategory_code | itempurchasecategory_code | itemsalecategory_code | itemstockcategory_code | itemassetcategory_name | itemcostcategory_name | itemcreditcategory_name | itemmrpcategory_name | itempricecategory_name | itemproductioncategory_name | itempurchasecategory_name | itemsalecategory_name | itemstockcategory_name +------------+------------------------+-----------------------+-------------------------+----------------------+------------------------+-----------------------------+---------------------------+-----------------------+------------------------+------------------------+-----------------------+-------------------------+----------------------+------------------------+-----------------------------+---------------------------+-----------------------+------------------------ +(0 rows) + +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; +select * from v1; + year | amount | a | b +------+--------+---+--- + 2021 | 250.00 | 0 | 0 + 2021 | 150.00 | 0 | 0 + 2020 | 200.00 | 0 | 0 + 2020 | 100.00 | 0 | 0 +(4 rows) + +-- part2: unpivot +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50), + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +); +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) as unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +); + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES (2021, 'A', 150, NULL, NULL, NULL, NULL, NULL), (2021, 'B', 250, NULL, NULL, NULL, NULL, NULL), (2022, 'C', 250, NULL, NULL, NULL, NULL, NULL); +SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) as unpvt; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +create table aaa as SELECT * +FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; +CREATE PROCEDURE proc2(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ +--CALL proc2(param1:='123'); +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'sale1'; + con2 = 'sale2'; + sql1 = 'SELECT * FROM sales2 not rotate(sale_all For sale IN (' || con1 || ',' || con2 || ')) unpvt'; + EXECUTE IMMEDIATE sql1; +end; +/ +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) order by 1,2,3; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2022 | C | 250.00 | 5 | sale1 | 5 +(20 rows) + +create view v2 as SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) order by 1,2,3; +select * from v2; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2022 | C | 250.00 | 5 | sale1 | 5 +(20 rows) + +set enable_ignore_case_in_dquotes on; +WARNING: Please avoid turn on this param when already created +uppercase named objects or using double quotes in PL. +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; + year | sale5 | a | b | sale | sale_all +------+-------+--------+--------+-------+---------- + 2020 | 1 | 100.00 | | sale4 | 1 + 2020 | 1 | 100.00 | | sale1 | 1 + 2020 | 1 | 100.00 | | sale2 | 1 + 2020 | 1 | 100.00 | | sale3 | 1 + 2020 | 2 | | 200.00 | sale3 | 2 + 2020 | 2 | | 200.00 | sale4 | 2 + 2020 | 2 | | 200.00 | sale1 | 2 + 2020 | 2 | | 200.00 | sale2 | 2 + 2021 | 3 | 150.00 | | sale1 | 3 + 2021 | 3 | 150.00 | | sale2 | 3 + 2021 | 3 | 150.00 | | sale3 | 3 + 2021 | 3 | 150.00 | | sale4 | 3 + 2021 | 4 | | 250.00 | sale2 | 4 + 2021 | 4 | | 250.00 | sale3 | 4 + 2021 | 4 | | 250.00 | sale4 | 4 + 2021 | 4 | | 250.00 | sale1 | 4 + 2022 | 5 | | | sale3 | 5 + 2022 | 5 | | | sale2 | 5 + 2022 | 5 | | | sale4 | 5 + 2022 | 5 | | | sale1 | 5 +(20 rows) + +set enable_ignore_case_in_dquotes off; +-- part3: ANSI_NULLS +set ANSI_NULLS on; +select NULL = NULL; + ?column? +---------- + +(1 row) + +select 1 = NULL; + ?column? +---------- + +(1 row) + +select NULL <> NULL; + ?column? +---------- + +(1 row) + +select 1 <> NULL; + ?column? +---------- + +(1 row) + +select NULL > NULL; + ?column? +---------- + +(1 row) + +select 1 > NULL; + ?column? +---------- + +(1 row) + +select NULL IS NULL; + ?column? +---------- + t +(1 row) + +select 1 IS NULL; + ?column? +---------- + f +(1 row) + +select NULL IS NOT NULL; + ?column? +---------- + f +(1 row) + +select 1 IS NOT NULL; + ?column? +---------- + t +(1 row) + +select 1 != NULL; + ?column? +---------- + +(1 row) + +select NULL != NULL; + ?column? +---------- + +(1 row) + +set ANSI_NULLS off; +select NULL = NULL; + ?column? +---------- + t +(1 row) + +select 1 = NULL; + ?column? +---------- + f +(1 row) + +select NULL <> NULL; + ?column? +---------- + f +(1 row) + +select 1 <> NULL; + ?column? +---------- + t +(1 row) + +select NULL > NULL; + ?column? +---------- + +(1 row) + +select 1 > NULL; + ?column? +---------- + +(1 row) + +select NULL IS NULL; + ?column? +---------- + t +(1 row) + +select 1 IS NULL; + ?column? +---------- + f +(1 row) + +select NULL IS NOT NULL; + ?column? +---------- + f +(1 row) + +select 1 IS NOT NULL; + ?column? +---------- + t +(1 row) + +select 1 != NULL; + ?column? +---------- + t +(1 row) + +select NULL != NULL; + ?column? +---------- + f +(1 row) + +CREATE TABLE test1 (a INT NULL); +INSERT INTO test1 values (NULL),(0),(1); +set ANSI_NULLS on; +select * from test1 where NULL = NULL; + a +--- +(0 rows) + +select * from test1 where 1 = NULL; + a +--- +(0 rows) + +select * from test1 where NULL <> NULL; + a +--- +(0 rows) + +select * from test1 where 1 <> NULL; + a +--- +(0 rows) + +select * from test1 where NULL > NULL; + a +--- +(0 rows) + +select * from test1 where 1 > NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 IS NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NOT NULL; + a +--- +(0 rows) + +select * from test1 where 1 IS NOT NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 != NULL; + a +--- +(0 rows) + +select * from test1 where NULL != NULL; + a +--- +(0 rows) + +set ANSI_NULLS off; +select * from test1 where NULL = NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 = NULL; + a +--- +(0 rows) + +select * from test1 where NULL <> NULL; + a +--- +(0 rows) + +select * from test1 where 1 <> NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where NULL > NULL; + a +--- +(0 rows) + +select * from test1 where 1 > NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 IS NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NOT NULL; + a +--- +(0 rows) + +select * from test1 where 1 IS NOT NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 != NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where NULL != NULL; + a +--- +(0 rows) + +-- part3 : body and rownum +create table body(body varchar); +insert into body values ('body'); +select body from body; + body +------ + body +(1 row) + +create table rownum(rownum varchar); +insert into rownum values ('rownum'); +select rownum from rownum; + rownum +-------- + rownum +(1 row) + +create table pivot(pivot varchar); +insert into pivot values ('pivot'); +select pivot from pivot; + pivot +------- + pivot +(1 row) + +create table unpivot(unpivot varchar); +insert into unpivot values ('unpivot'); +select unpivot from unpivot; + unpivot +--------- + unpivot +(1 row) + +drop table sales; +drop table categorytable2; +drop view v1; +drop table sales2; +drop table aaa; +drop view v2; +drop table test1; +drop table body; +drop table rownum; +drop table pivot; +drop table unpivot; +drop schema sql_server_test_part2 cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to function proc1(character) +drop cascades to function proc2(character) diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index e172544464..8be7faadcb 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -1,3 +1,5 @@ # init must be first test: init test: basetest +test: sql-server-test-part2 + diff --git a/contrib/shark/shark.cpp b/contrib/shark/shark.cpp index f327ade7f0..b041be21a3 100644 --- a/contrib/shark/shark.cpp +++ b/contrib/shark/shark.cpp @@ -7,6 +7,7 @@ PG_MODULE_MAGIC; static bool global_hook_inited = false; +static uint32 shark_index; extern List* tsql_raw_parser(const char* str, List** query_string_locationlist); @@ -24,6 +25,24 @@ void init_session_vars(void) } u_sess->hook_cxt.coreYYlexHook = (void*)pgtsql_core_yylex; u_sess->hook_cxt.plsqlCompileHook = (void*)pltsql_compile; + + RepallocSessionVarsArrayIfNecessary(); + SharkContext *cxt = (SharkContext*) MemoryContextAlloc(u_sess->self_mem_cxt, sizeof(sharkContext)); + u_sess->attr.attr_common.extension_session_vars_array[shark_index] = cxt; + cxt->dialect_sql = false; +} + +SharkContext* GetSessionContext() +{ + if (u_sess->attr.attr_common.extension_session_vars_array[shark_index] == NULL) { + init_session_vars(); + } + return (SharkContext*) u_sess->attr.attr_common.extension_session_vars_array[shark_index]; +} + +void set_extension_index(uint32 index) +{ + shark_index = index; } void _PG_fini(void) diff --git a/contrib/shark/shark.h b/contrib/shark/shark.h index 14b6b2849c..18ec337928 100644 --- a/contrib/shark/shark.h +++ b/contrib/shark/shark.h @@ -4,3 +4,10 @@ extern "C" void _PG_init(void); extern "C" void _PG_fini(void); extern "C" void init_session_vars(void); +extern "C" void set_extension_index(uint32 index); + +typedef struct SharkContext { + bool dialect_sql; +} sharkContext; + +SharkContext* GetSessionContext(); diff --git a/contrib/shark/sql/sql-server-test-part2.sql b/contrib/shark/sql/sql-server-test-part2.sql new file mode 100644 index 0000000000..d30bdc05b4 --- /dev/null +++ b/contrib/shark/sql/sql-server-test-part2.sql @@ -0,0 +1,296 @@ +create database sql_server_test_part2 dbcompatibility 'D'; +\c sql_server_test_part2 +create extension shark; + +\c contrib_regression +create schema sql_server_test_part2; +set search_path = 'sql_server_test_part2'; + + +-- part1: pivot +CREATE TABLE sales (year INT, product VARCHAR(50), amount DECIMAL(10, 2)); + +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot; + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ); + + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ) pivot_table; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, 'A', 'SSS', 1, 2, 2.3, 1011) +) as pivot_table; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot; + + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot order by year; + + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + + +-- expect error +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where source_table.year > 1; + + +CREATE PROCEDURE proc1(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN ('A', 'B')) ; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ + +--CALL proc1(param1:='123'); + + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'A'; + con2 = 'B'; + sql1 = 'SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN (''' || con1 || ''',''' || con2 || '''))'; + EXECUTE IMMEDIATE sql1; +end; +/ + + create table CategoryTable2 ( + MergeDocID bigint, + CategoryFieldName nvarchar(100), + CategoryFieldValue nvarchar(255) + ); + + select * + from CategoryTable2 rotate (max(CategoryFieldValue ) + for CategoryFieldName + in (ItemAssetCategory_Code, ItemCostCategory_Code, ItemCreditCategory_Code, ItemMRPCategory_Code, ItemPriceCategory_Code, ItemProductionCategory_Code, ItemPurchaseCategory_Code, ItemSaleCategory_Code, ItemStockCategory_Code, ItemAssetCategory_Name, ItemCostCategory_Name, ItemCreditCategory_Name, ItemMRPCategory_Name, ItemPriceCategory_Name, ItemProductionCategory_Name, ItemPurchaseCategory_Name, ItemSaleCategory_Name, ItemStockCategory_Name)); + +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + +select * from v1; + +-- part2: unpivot + +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50), + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +); + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) as unpivot; + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +); + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) unpivot; + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES (2021, 'A', 150, NULL, NULL, NULL, NULL, NULL), (2021, 'B', 250, NULL, NULL, NULL, NULL, NULL), (2022, 'C', 250, NULL, NULL, NULL, NULL, NULL); + +SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) as unpvt; + +create table aaa as SELECT * +FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + + +CREATE PROCEDURE proc2(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ + +--CALL proc2(param1:='123'); + + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'sale1'; + con2 = 'sale2'; + sql1 = 'SELECT * FROM sales2 not rotate(sale_all For sale IN (' || con1 || ',' || con2 || ')) unpvt'; + EXECUTE IMMEDIATE sql1; +end; +/ + + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) order by 1,2,3; + + +create view v2 as SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) order by 1,2,3; + +select * from v2; + +set enable_ignore_case_in_dquotes on; +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; + +set enable_ignore_case_in_dquotes off; + +-- part3: ANSI_NULLS +set ANSI_NULLS on; +select NULL = NULL; +select 1 = NULL; +select NULL <> NULL; +select 1 <> NULL; +select NULL > NULL; +select 1 > NULL; +select NULL IS NULL; +select 1 IS NULL; +select NULL IS NOT NULL; +select 1 IS NOT NULL; +select 1 != NULL; +select NULL != NULL; + +set ANSI_NULLS off; +select NULL = NULL; +select 1 = NULL; +select NULL <> NULL; +select 1 <> NULL; +select NULL > NULL; +select 1 > NULL; +select NULL IS NULL; +select 1 IS NULL; +select NULL IS NOT NULL; +select 1 IS NOT NULL; +select 1 != NULL; +select NULL != NULL; + + +CREATE TABLE test1 (a INT NULL); +INSERT INTO test1 values (NULL),(0),(1); +set ANSI_NULLS on; +select * from test1 where NULL = NULL; +select * from test1 where 1 = NULL; +select * from test1 where NULL <> NULL; +select * from test1 where 1 <> NULL; +select * from test1 where NULL > NULL; +select * from test1 where 1 > NULL; +select * from test1 where NULL IS NULL; +select * from test1 where 1 IS NULL; +select * from test1 where NULL IS NOT NULL; +select * from test1 where 1 IS NOT NULL; +select * from test1 where 1 != NULL; +select * from test1 where NULL != NULL; + + +set ANSI_NULLS off; +select * from test1 where NULL = NULL; +select * from test1 where 1 = NULL; +select * from test1 where NULL <> NULL; +select * from test1 where 1 <> NULL; +select * from test1 where NULL > NULL; +select * from test1 where 1 > NULL; +select * from test1 where NULL IS NULL; +select * from test1 where 1 IS NULL; +select * from test1 where NULL IS NOT NULL; +select * from test1 where 1 IS NOT NULL; +select * from test1 where 1 != NULL; +select * from test1 where NULL != NULL; + +-- part3 : body and rownum +create table body(body varchar); +insert into body values ('body'); +select body from body; + +create table rownum(rownum varchar); +insert into rownum values ('rownum'); +select rownum from rownum; + +create table pivot(pivot varchar); +insert into pivot values ('pivot'); +select pivot from pivot; + +create table unpivot(unpivot varchar); +insert into unpivot values ('unpivot'); +select unpivot from unpivot; + +drop table sales; +drop table categorytable2; +drop view v1; +drop table sales2; +drop table aaa; +drop view v2; +drop table test1; +drop table body; +drop table rownum; +drop table pivot; +drop table unpivot; + +drop schema sql_server_test_part2 cascade; diff --git a/contrib/shark/src/backend_parser/gram-tsql-decl.y b/contrib/shark/src/backend_parser/gram-tsql-decl.y index c7f206e134..6752051914 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-decl.y +++ b/contrib/shark/src/backend_parser/gram-tsql-decl.y @@ -1,4 +1,5 @@ -%type tsql_stmtmulti +%type tsql_stmtmulti from_clause_no_empty %type tsql_stmt tsql_CreateProcedureStmt -%token TSQL_COLUMNSTORE \ No newline at end of file +%token PIVOT TSQL_COLUMNSTORE UNPIVOT +%type unpivot_clause diff --git a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp index 791c4ebc23..868b314f03 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp +++ b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp @@ -10,5 +10,6 @@ pgtsql_base_yyerror(YYLTYPE * yylloc, core_yyscan_t yyscanner, const char *msg) base_yyerror(yylloc, yyscanner, msg); } + #include "scan-backend.inc" #undef SCANINC diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index c9c8e5de06..848461acd6 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -186,6 +186,44 @@ tsql_CreateProcedureStmt: } ; + +rotate_clause: + ROTATE '(' func_application_list rotate_for_clause rotate_in_clause ')' alias_clause %prec ROTATE + { + RotateClause *n = makeNode(RotateClause); + n->aggregateFuncCallList = $3; + n->forColName = $4; + n->inExprList = $5; + n->inExprList = TransformToConstStrNode(n->inExprList); + n->alias = $7; + $$ = n; + } + ; + +unrotate_clause: + NOT ROTATE include_exclude_null_clause '(' unrotate_name_list rotate_for_clause unrotate_in_clause ')' alias_clause %prec ROTATE + { + UnrotateClause *n = makeNode(UnrotateClause); + n->includeNull = $3; + n->colNameList = $5; + n->forColName = $6; + n->inExprList = $7; + $$ = n; + } + ; + +VariableSetStmt: + SET IDENT var_value + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; + n->name = $2; + n->args = list_make1($3); + n->is_local = false; + $$ = (Node *) n; + } + ; + tsql_stmt : AlterAppWorkloadGroupMappingStmt | AlterCoordinatorStmt @@ -245,8 +283,8 @@ tsql_stmt : | CreateAsStmt | CreateAssertStmt | CreateCastStmt - | CreateContQueryStmt - | CreateStreamStmt + | CreateContQueryStmt + | CreateStreamStmt | CreateConversionStmt | CreateDomainStmt | CreateDirectoryStmt @@ -386,4 +424,9 @@ tsql_stmt : | /*EMPTY*/ { $$ = NULL; } | DelimiterStmt - ; \ No newline at end of file + ; + +unreserved_keyword: + PIVOT + | UNPIVOT + ; diff --git a/contrib/shark/src/backend_parser/kwlist.h b/contrib/shark/src/backend_parser/kwlist.h index a96c03e71f..e3325d9672 100644 --- a/contrib/shark/src/backend_parser/kwlist.h +++ b/contrib/shark/src/backend_parser/kwlist.h @@ -572,9 +572,6 @@ PG_KEYWORD("rotate", ROTATE, UNRESERVED_KEYWORD) PG_KEYWORD("rotation", ROTATION, UNRESERVED_KEYWORD) PG_KEYWORD("row", ROW, COL_NAME_KEYWORD) PG_KEYWORD("row_count", ROW_COUNT, UNRESERVED_KEYWORD) -#ifndef ENABLE_MULTIPLE_NODES -PG_KEYWORD("rownum", ROWNUM, RESERVED_KEYWORD) -#endif PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD) PG_KEYWORD("rowtype", ROWTYPE_P, UNRESERVED_KEYWORD) PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD) diff --git a/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp b/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp index 289910e677..9ad350ea4f 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp +++ b/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp @@ -10,6 +10,8 @@ pgtsql_scanner_init(const char *str, Size slen = strlen(str); yyscan_t scanner; + GetSessionContext()->dialect_sql = true; + if (yylex_init(&scanner) != 0) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), diff --git a/contrib/shark/src/backend_parser/scan-tsql-prologue-top.l.h b/contrib/shark/src/backend_parser/scan-tsql-prologue-top.l.h index 290faf6af0..1df9b40f0c 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-prologue-top.l.h +++ b/contrib/shark/src/backend_parser/scan-tsql-prologue-top.l.h @@ -1 +1,2 @@ -#include "parser/gramparse.h" \ No newline at end of file +#include "parser/gramparse.h" +#include "shark.h" \ No newline at end of file diff --git a/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h b/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h index 753ce79c0a..02ca534523 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h +++ b/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h @@ -22,8 +22,9 @@ const uint16 pgtsql_ScanKeywordTokens[] = { */ #define YY_USER_INIT \ - if (g_instance.raw_parser_hook[DB_CMPT_D]) \ + if (g_instance.raw_parser_hook[DB_CMPT_D] && GetSessionContext()->dialect_sql) \ { \ + GetSessionContext()->dialect_sql = false; \ *yylloc = 0; \ return DIALECT_TSQL; \ } diff --git a/contrib/shark/src/pltsql/gram.y b/contrib/shark/src/pltsql/gram.y index 343811c817..80e4683a4f 100644 --- a/contrib/shark/src/pltsql/gram.y +++ b/contrib/shark/src/pltsql/gram.y @@ -646,9 +646,9 @@ static void HandleBlockLevel(); %% -pl_body : DIALECT_TSQL pl_package_spec - | DIALECT_TSQL pl_function - | DIALECT_TSQL pl_package_init +pl_body : pl_package_spec + | pl_function + | pl_package_init ; pl_package_spec : K_PACKAGE { SetErrorState(); } decl_sect K_END { @@ -13048,7 +13048,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen) u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc; RawParserHook parser_hook= raw_parser; #if (!defined(ENABLE_MULTIPLE_NODES)) && (!defined(ENABLE_PRIVATEGAUSS)) - if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin) { + if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin || DB_IS_CMPT(D_FORMAT)) { int id = GetCustomParserId(); if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) { parser_hook = (RawParserHook)g_instance.raw_parser_hook[id]; diff --git a/contrib/shark/src/pltsql/pl_scanner.cpp b/contrib/shark/src/pltsql/pl_scanner.cpp index 643babf558..f2aaee1f25 100644 --- a/contrib/shark/src/pltsql/pl_scanner.cpp +++ b/contrib/shark/src/pltsql/pl_scanner.cpp @@ -478,7 +478,7 @@ void pltsql_scanner_init(const char* str) PLpgSQL_compile_context* curr_compile = u_sess->plsql_cxt.curr_compile_context; /* Start up the core scanner */ curr_compile->yyscanner = - pgtsql_scanner_init(str, curr_compile->core_yy, &ReservedPLKeywords, ReservedPLKeywordTokens); + scanner_init(str, curr_compile->core_yy, &ReservedPLKeywords, ReservedPLKeywordTokens); curr_compile->core_yy->isPlpgsqlKeyWord = true; curr_compile->core_yy->plKeywordValue = &keywordsValue; diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index ac44a91e4a..c40d396d93 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -309,6 +309,7 @@ static void CheckUserHostIsValid(); static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStmt*n); static Node* MakeNoArgFunctionCall(List* funcName, int location); static char* IdentResolveToChar(char *ident, core_yyscan_t yyscanner); +static List* TransformToConstStrNode(List *inExprList); /* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */ /*$$include "gram-tsql-prologue.y.h"*/ @@ -26512,7 +26513,7 @@ opt_alias_clause: alias_clause { $$ = $1; } rotate_clause: ROTATE '(' func_application_list rotate_for_clause rotate_in_clause ')' %prec ROTATE { - if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT ) + if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && u_sess->attr.attr_sql.sql_compatibility != D_FORMAT) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("rotate clause is supported only in A_FORMAT database."))); @@ -26520,6 +26521,9 @@ rotate_clause: n->aggregateFuncCallList = $3; n->forColName = $4; n->inExprList = $5; + if (DB_IS_CMPT(D_FORMAT)) { + n->inExprList = TransformToConstStrNode(n->inExprList); + } $$ = n; } ; @@ -26541,7 +26545,7 @@ func_application_list: unrotate_clause: NOT ROTATE include_exclude_null_clause '(' unrotate_name_list rotate_for_clause unrotate_in_clause ')' %prec ROTATE { - if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT ) + if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && u_sess->attr.attr_sql.sql_compatibility != D_FORMAT ) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("not rotate clause is supported only in A_FORMAT database."))); @@ -34894,6 +34898,57 @@ static char* IdentResolveToChar(char *ident, core_yyscan_t yyscanner) } } + +static List* TransformToConstStrNode(List *inExprList) +{ + ListCell* cell = NULL; + ListCell *exprCell = NULL; + ResTarget *resTarget = NULL; + errno_t rc; + + foreach (cell, inExprList) + { + RotateInCell *rotateinCell = (RotateInCell *)lfirst(cell); + foreach (exprCell, rotateinCell->rotateInExpr) { + resTarget = (ResTarget *)lfirst(exprCell); + if (NULL == rotateinCell->aliasname && IsA(resTarget->val, ColumnRef)) { + ColumnRef* column_ref = (ColumnRef*)resTarget->val; + char * aaa = strVal(linitial(column_ref->fields)); + Node* const_node = makeStringConst(aaa, column_ref->location); + resTarget->val = const_node; + } if (NULL == rotateinCell->aliasname && IsA(resTarget->val, A_Const)) { + const Value *val = &((A_Const *)resTarget->val)->val; + char * aaa = NULL; + switch (val->type) { + case T_Integer: { + char* new_col_name = (char*)palloc(NAMEDATALEN); + rc = memset_s(new_col_name, NAMEDATALEN, 0, NAMEDATALEN); + securec_check_c(rc, "\0", "\0"); + rc = snprintf_s(new_col_name, NAMEDATALEN, NAMEDATALEN - 1, "%ld", intVal(val)); + securec_check_ss(rc, "\0", "\0"); + aaa = new_col_name; + break; + } + + case T_Float: + case T_String: + case T_BitString: + aaa = strVal(val); + break; + + default: + break; + } + if (aaa != NULL) { + Node* const_node = makeStringConst(aaa, ((A_Const *)resTarget)->location); + resTarget->val = const_node; + } + } + } + } + return inExprList; +} + /* * Must undefine this stuff before including scan.c, since it has different * definitions for these macros. diff --git a/src/common/backend/parser/parse_clause.cpp b/src/common/backend/parser/parse_clause.cpp index c7de859e12..61f395a572 100644 --- a/src/common/backend/parser/parse_clause.cpp +++ b/src/common/backend/parser/parse_clause.cpp @@ -788,10 +788,15 @@ static RangeTblEntry* transformRangeSubselect(ParseState* pstate, RangeSubselect (errcode(ERRCODE_UNEXPECTED_NODE_STATE), errmsg("unexpected non-SELECT command in subquery in FROM"))); } + Alias* subquery_alias = r->alias; + if (DB_IS_CMPT(D_FORMAT) && r->rotate != NULL && r->rotate->alias != NULL) { + subquery_alias = r->rotate->alias; + } + /* * OK, build an RTE for the subquery. */ - rte = addRangeTableEntryForSubquery(pstate, query, r->alias, r->lateral, true); + rte = addRangeTableEntryForSubquery(pstate, query, subquery_alias, r->lateral, true); return rte; } diff --git a/src/common/backend/parser/parse_expr.cpp b/src/common/backend/parser/parse_expr.cpp index 91bfd112e9..c26946daa0 100644 --- a/src/common/backend/parser/parse_expr.cpp +++ b/src/common/backend/parser/parse_expr.cpp @@ -1448,6 +1448,16 @@ static bool exprIsNullConstant(Node* arg) return false; } + + +static inline bool is_not_null_operator(const char * operator_name) +{ + if (operator_name == NULL) { + return false; + } + return strcmp(operator_name, "!=") == 0 || strcmp(operator_name, "<>") == 0; +} + static Node* transformAExprOp(ParseState* pstate, A_Expr* a) { Node* lexpr = a->lexpr; @@ -1471,7 +1481,18 @@ static Node* transformAExprOp(ParseState* pstate, A_Expr* a) n->arg = exprIsNullConstant(lexpr) ? (Expr *)rexpr : (Expr *)lexpr; result = transformExprRecurse(pstate, (Node*)n); - } else if (lexpr && IsA(lexpr, RowExpr) && rexpr && IsA(rexpr, SubLink) && + } else if (DB_IS_CMPT(D_FORMAT) && u_sess->attr.attr_sql.Transform_null_equals && list_length(a->name) == 1 && + is_not_null_operator(strVal(linitial(a->name))) && (exprIsNullConstant(lexpr) || exprIsNullConstant(rexpr)) && + (!IsA(lexpr, CaseTestExpr) && !IsA(rexpr, CaseTestExpr))) { + NullTest* n = makeNode(NullTest); + + n->nulltesttype = IS_NOT_NULL; + + n->arg = exprIsNullConstant(lexpr) ? (Expr *)rexpr : (Expr *)lexpr; + + result = transformExprRecurse(pstate, (Node*)n); + } + else if (lexpr && IsA(lexpr, RowExpr) && rexpr && IsA(rexpr, SubLink) && ((SubLink*)rexpr)->subLinkType == EXPR_SUBLINK) { /* * Convert "row op subselect" into a ROWCOMPARE sublink. Formerly the diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index bd2789bec2..db70451f63 100755 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -353,6 +353,7 @@ const char* sync_guc_variable_namelist[] = {"work_mem", "standard_conforming_strings", "synchronize_seqscans", "transform_null_equals", + "ansi_nulls", "exit_on_error", #ifdef ENABLE_MULTIPLE_NODES "gtm_backup_barrier", diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index 3c4a2e092d..05c783320a 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -170,6 +170,8 @@ static bool parse_query_dop(int* newval, void** extra, GucSource source); static void AssignQueryDop(int newval, void* extra); +static void AssignAnsiNulls(bool newval, void* extra); +static void AssignTransformNullEquals(bool newval, void* extra); static bool check_job_max_workers(int* newval, void** extra, GucSource source); static bool check_statement_max_mem(int* newval, void** extra, GucSource source); static bool check_statement_mem(int* newval, void** extra, GucSource source); @@ -1127,9 +1129,24 @@ static void InitSqlConfigureNamesBool() &u_sess->attr.attr_sql.Transform_null_equals, false, NULL, + AssignTransformNullEquals, + NULL}, + {{"ansi_nulls", + PGC_USERSET, + NODE_ALL, + COMPAT_OPTIONS_CLIENT, + gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"."), + gettext_noop("When turned on, expressions of the form expr = NULL " + "(or NULL = expr) are treated as expr IS NULL, that is, they " + "return true if expr evaluates to the null value, and false " + "otherwise. The correct behavior of expr = NULL is to always " + "return null (unknown).")}, + &u_sess->attr.attr_sql.ansi_nulls, + true, NULL, + AssignAnsiNulls, NULL}, - {{"transform_to_numeric_operators", + {{"transform_to_numeric_operators", PGC_USERSET, NODE_SINGLENODE, QUERY_TUNING_METHOD, @@ -4626,3 +4643,25 @@ static void assign_restrict_nonsystem_relation_kind(const char *newval, void *ex u_sess->utils_cxt.restrict_nonsystem_relation_kind_flags = result; } + + +/* + * @Description: assign new value to ansi_nulls. + * + * @param[IN] newval: new value + * @param[IN] extra: N/A + * @return: void + */ +static void AssignAnsiNulls(bool newval, void* extra) +{ + u_sess->attr.attr_sql.Transform_null_equals = !newval; +} + + +static void AssignTransformNullEquals(bool newval, void* extra) +{ + u_sess->attr.attr_sql.ansi_nulls = !newval; +} + + + diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index a5ea22de8c..13ddc99326 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -13056,7 +13056,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen) u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc; RawParserHook parser_hook= raw_parser; #if (!defined(ENABLE_MULTIPLE_NODES)) && (!defined(ENABLE_PRIVATEGAUSS)) - if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin) { + if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin || DB_IS_CMPT(D_FORMAT)) { int id = GetCustomParserId(); if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) { parser_hook = (RawParserHook)g_instance.raw_parser_hook[id]; diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 3c0647043e..4187c175c0 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -73,7 +73,7 @@ extern List* raw_parser(const char* query_string, List** query_string_locationli static inline parse_query_func GetRawParser() { #ifndef ENABLE_MULTIPLE_NODES - if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin) { + if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin || DB_IS_CMPT(D_FORMAT)) { int id = GetCustomParserId(); if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) { return (parse_query_func)g_instance.raw_parser_hook[id]; diff --git a/src/include/knl/knl_guc/knl_session_attr_sql.h b/src/include/knl/knl_guc/knl_session_attr_sql.h index 5775df6d9a..735e092d08 100644 --- a/src/include/knl/knl_guc/knl_session_attr_sql.h +++ b/src/include/knl/knl_guc/knl_session_attr_sql.h @@ -111,6 +111,7 @@ typedef struct knl_session_attr_sql { bool enable_autoanalyze; bool SQL_inheritance; bool Transform_null_equals; + bool ansi_nulls; bool check_function_bodies; bool Array_nulls; bool default_with_oids; diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index e678644475..484c0059f9 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -696,6 +696,7 @@ typedef struct UnrotateClause { List *colNameList; List *forColName; List *inExprList; + Alias *alias; /* function aliases */ } UnrotateClause; typedef struct UnrotateInCell { @@ -1872,6 +1873,7 @@ typedef struct RotateClause { List *forColName; List *inExprList; List *aggregateFuncCallList; + Alias *alias; /* function aliases */ } RotateClause; typedef struct RotateInCell { diff --git a/src/include/postgres_fe.h b/src/include/postgres_fe.h index 024074631f..c632e23763 100644 --- a/src/include/postgres_fe.h +++ b/src/include/postgres_fe.h @@ -61,9 +61,11 @@ typedef enum { A_FORMAT = 0x0001, B_FORMAT = 0x0002, C_FORMAT = 0x0004, - PG_FORMAT = 0x0008 + PG_FORMAT = 0x0008, + D_FORMAT = 0x0010 } DBFormatType; #define IS_CMPT(cmpt, flag) (((uint32)(cmpt) & (uint32)(flag)) != 0) +#define DB_IS_CMPT(flag) IS_CMPT(u_sess->attr.attr_sql.sql_compatibility, (flag)) #endif // HAVE_DATABASE_TYPE -- Gitee