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 0000000000000000000000000000000000000000..f44e8cc496f3f075d4a3800fd04ca0678fcd38a8 --- /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 e172544464b330b31296e8951ca15a5167df7a78..8be7faadcbb4b200fe7c2ed5ac10bdc578ec93e1 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 f327ade7f0168b061402fa4820410316ea248081..b041be21a39f011a8762d0379e380ae316cd5a7f 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 14b6b2849cf7eac82029e70da177c06812b371d4..18ec33792807251e3eb6e320771e39c047309d18 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 0000000000000000000000000000000000000000..d30bdc05b4710e2e271e4d924483b8cffd343fc3 --- /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 c7f206e134fdafab2ad2cbb8a64544aa07ce0682..6752051914931ed7f5eacdd723e954a0bf01c732 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 791c4ebc2395d155f75ccd06c23885e12b82ca23..868b314f03506fa389a28a6c375a58f55b3fda37 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 c9c8e5de069fd05baf87c85524571493a6b74882..848461acd63c7341432f4e0f0c7520c23f59f702 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 a96c03e71f648aae6abc5936aed3333de3d4e8c0..e3325d9672b31e246728c7dd7ae4295d99240464 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 289910e677ca4b8426585f6d2c87cdc71f2650d4..9ad350ea4fb17c1c6b7ad625906102817f1a9289 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 290faf6af09aed865bd40245dbb39993859a672a..1df9b40f0c0eb1fa283f9dbef90a01d7e333e435 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 753ce79c0a5341de3b1ef24047b16da15eba8c61..02ca534523a32f2f588b873911e8942e4083629b 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 343811c8178603cc41edbecb4da5d50976b3d3e1..80e4683a4fa432eb858bbe4967cb20a78a9bc092 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 643babf55886867c6ca6aebcaf9fe25da11cba5b..f2aaee1f255590e50fce091f8f04b20e3f8cc35d 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 ac44a91e4a6f60f062ce40ac162bbe41bab77026..c40d396d93ab03a7b96d8a195255e8ae081f7bc1 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 c7de859e12ece9b86d56581760f0f921ceb3f642..61f395a5722579ffa1428c3c62c63b4c77f7ff9c 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 91bfd112e9657286c9fad2400b2c77d854a4a8cf..c26946daa028f40563f051910101016f53018455 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 bd2789bec2e14a443d88c2215737874b13090d94..db70451f63e0c67f30053f54d414ae6825a809c3 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 3c4a2e092d851c53d27b92d5572cc02aa7807b48..05c783320a8a55fdd75e8881ecc605754131a16b 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 a5ea22de8cf2359d6f9a194b1c846305c0ae0e1c..13ddc993261380bd43ce23720d064774feea6991 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 3c0647043e9c12dc8c97100e39f1bb68ec48fae8..4187c175c082a861ee9c048da12694679976e5ba 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 5775df6d9a36af4cd41e0ea4777a9fad5b94774b..735e092d086cecc30770e4f61c021a8fbdf16ab9 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 e678644475fb6d5e7bc91d6b9858401ed5724d64..484c0059f91e916633a7661d8127a708569624fb 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 024074631fa04f7139c07b6246696e6b024dcc3b..c632e237635fb0f1ef24a13393431798aa4c46a6 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