From 6f31632edf391574bb7748214b66ed63c2894804 Mon Sep 17 00:00:00 2001 From: huyinghao Date: Tue, 15 Nov 2022 10:07:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BC=9A=E8=AF=9D=E7=BA=A7?= =?UTF-8?q?=E5=BC=80=E5=85=B3enable=5Fignore=5Fcase=5Fin=5Fdquotes(?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=A0=87=E8=AF=86=E7=AC=A6=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E5=8F=8C=E5=BC=95=E5=8F=B7=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B?= =?UTF-8?q?=E4=B9=9F=E5=BF=BD=E7=95=A5=E5=A4=A7=E5=B0=8F=E5=86=99),=20?= =?UTF-8?q?=E5=8F=8A=E7=9B=B8=E5=85=B3check=E5=87=BD=E6=95=B0=E3=80=81?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bin/gs_guc/cluster_guc.conf | 1 + src/common/backend/parser/gram.y | 39 +- src/common/backend/utils/misc/guc/guc_sql.cpp | 22 ++ .../utils/misc/postgresql_single.conf.sample | 1 + .../knl/knl_guc/knl_session_attr_sql.h | 1 + .../regress/expected/ignore_double_quotes.out | 354 ++++++++++++++++++ .../regress/output/recovery_2pc_tools.source | 1 + src/test/regress/parallel_schedule0 | 2 +- src/test/regress/parallel_schedule0B | 2 +- src/test/regress/sql/ignore_double_quotes.sql | 158 ++++++++ 10 files changed, 576 insertions(+), 5 deletions(-) create mode 100644 src/test/regress/expected/ignore_double_quotes.out create mode 100644 src/test/regress/sql/ignore_double_quotes.sql diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index fe35aecc1..ee0a77543 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -131,6 +131,7 @@ config_file|string|0,0|NULL|NULL| connection_alarm_rate|real|0,1|NULL|NULL| constraint_exclusion|enum|partition,on,off,true,false,yes,no,1,0|NULL|NULL| enable_union_all_subquery_orderby|bool|0,0|NULL|NULL| +enable_ignore_case_in_dquotes|bool|0,0|NULL|NULL| instr_unique_sql_track_type|enum|all,top|NULL|NULL| transform_to_numeric_operators|bool|0,0|NULL|NULL| convert_string_to_digit|bool|0,0|NULL|Please don't modify this parameter which will change the type conversion rule and may lead to unpredictable behavior!| diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 45abf0fce..4a40970f0 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -28882,14 +28882,36 @@ SignedIconst: Iconst { $$ = $1; } /* Column identifier --- names that can be column, table, etc names. */ -ColId: IDENT { $$ = $1; } +ColId: IDENT + { + if (u_sess->attr.attr_sql.enable_ignore_case_in_dquotes + && (pg_yyget_extra(yyscanner))->core_yy_extra.ident_quoted) + { + $$ = pg_strtolower(pstrdup($1)); + } + else + { + $$ = $1; + } + } | unreserved_keyword { $$ = pstrdup($1); } | col_name_keyword { $$ = pstrdup($1); } ; /* Type/function identifier --- names that can be type or function names. */ -type_function_name: IDENT { $$ = $1; } +type_function_name: IDENT + { + if (u_sess->attr.attr_sql.enable_ignore_case_in_dquotes + && (pg_yyget_extra(yyscanner))->core_yy_extra.ident_quoted) + { + $$ = pg_strtolower(pstrdup($1)); + } + else + { + $$ = $1; + } + } | unreserved_keyword { $$ = pstrdup($1); } | type_func_name_keyword { $$ = pstrdup($1); } ; @@ -28897,7 +28919,18 @@ type_function_name: IDENT { $$ = $1; } /* Column label --- allowed labels in "AS" clauses. * This presently includes *all* Postgres keywords. */ -ColLabel: IDENT { $$ = $1; } +ColLabel: IDENT + { + if (u_sess->attr.attr_sql.enable_ignore_case_in_dquotes + && (pg_yyget_extra(yyscanner))->core_yy_extra.ident_quoted) + { + $$ = pg_strtolower(pstrdup($1)); + } + else + { + $$ = $1; + } + } | unreserved_keyword { $$ = pstrdup($1); } | col_name_keyword { $$ = pstrdup($1); } | type_func_name_keyword { $$ = pstrdup($1); } diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index 12f870a36..89aad464d 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -182,6 +182,7 @@ static void assign_plsql_compile_behavior_compat_options(const char* newval, voi static void assign_connection_info(const char* newval, void* extra); static bool check_application_type(int* newval, void** extra, GucSource source); static void assign_convert_string_to_digit(bool newval, void* extra); +static bool check_enable_ignore_case_in_dquotes(bool* newval, void** extra, GucSource source); static bool CheckUStoreAttr(char** newval, void** extra, GucSource source); static void AssignUStoreAttr(const char* newval, void* extra); static bool check_snapshot_delimiter(char** newval, void** extra, GucSource source); @@ -1726,6 +1727,17 @@ static void InitSqlConfigureNamesBool() NULL, NULL, NULL}, + {{"enable_ignore_case_in_dquotes", + PGC_USERSET, + NODE_ALL, + QUERY_TUNING_METHOD, + gettext_noop("Enable ignore case in double quotes for some driver."), + NULL}, + &u_sess->attr.attr_sql.enable_ignore_case_in_dquotes, + false, + check_enable_ignore_case_in_dquotes, + NULL, + NULL}, {{"enable_streaming", PGC_POSTMASTER, NODE_DISTRIBUTE, @@ -3762,6 +3774,16 @@ static void assign_convert_string_to_digit(bool newval, void* extra) return; } +static bool check_enable_ignore_case_in_dquotes(bool* newval, void** extra, GucSource source) +{ + if (*newval && (currentGucContext == PGC_SUSET || currentGucContext == PGC_USERSET)) { + ereport(WARNING, (errmsg("if tables with the same name but different case already\n" + "exists in the database, this will result in only being able to\n" + "manipulate tables with table names that are entirely lowercase."))); + } + return true; +} + #define IS_NULL_STR(str) ((str) == NULL || (str)[0] == '\0') const int MIN_USTATS_TRACKER_NAPTIME = 1; diff --git a/src/common/backend/utils/misc/postgresql_single.conf.sample b/src/common/backend/utils/misc/postgresql_single.conf.sample index 1f00fca98..30a55e8f4 100644 --- a/src/common/backend/utils/misc/postgresql_single.conf.sample +++ b/src/common/backend/utils/misc/postgresql_single.conf.sample @@ -820,6 +820,7 @@ job_queue_processes = 10 # Number of concurrent jobs, optional: [0..1000] #plsql_show_all_error=off #enable_seqscan_fusion = off #enable_cachedplan_mgr=on +#enable_ignore_case_in_dquotes=off #------------------------------------------------------------------------------ # SHARED STORAGE OPTIONS 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 537296e93..ee24c2666 100644 --- a/src/include/knl/knl_guc/knl_session_attr_sql.h +++ b/src/include/knl/knl_guc/knl_session_attr_sql.h @@ -246,6 +246,7 @@ typedef struct knl_session_attr_sql { char* db4ai_snapshot_mode; char* db4ai_snapshot_version_delimiter; char* db4ai_snapshot_version_separator; + bool enable_ignore_case_in_dquotes; int pldebugger_timeout; bool partition_page_estimation; bool enable_opfusion_reuse; diff --git a/src/test/regress/expected/ignore_double_quotes.out b/src/test/regress/expected/ignore_double_quotes.out new file mode 100644 index 000000000..25bf04255 --- /dev/null +++ b/src/test/regress/expected/ignore_double_quotes.out @@ -0,0 +1,354 @@ +DROP SCHEMA sch_ignore_quote_01 CASCADE; +ERROR: schema "sch_ignore_quote_01" does not exist +CREATE SCHEMA sch_ignore_quote_01; +SET CURRENT_SCHEMA TO sch_ignore_quote_01; +-- test tables with the same name but different case already exists in the database +-- table +create table "TeSt" ("A" int); +select * from test; +ERROR: relation "test" does not exist on datanode1 +LINE 1: select * from test; + ^ +select * from "TeSt"; + A +--- +(0 rows) + +create table test ("A" int, "a" int); +insert into test("A","a") values(1,2); +select * from test; + A | a +---+--- + 1 | 2 +(1 row) + +-- view +CREATE VIEW test_view AS SELECT * FROM test; +CREATE VIEW "TeSt_view" AS SELECT * FROM "TeSt"; +select * from test_view; + A | a +---+--- + 1 | 2 +(1 row) + +select * from "TeSt_view"; + A +--- +(0 rows) + +-- materialized view +CREATE MATERIALIZED VIEW m_test_view AS SELECT * FROM test; +CREATE MATERIALIZED VIEW "M_teSt_view" AS SELECT * FROM "TeSt"; +select * from m_test_view; + A | a +---+--- + 1 | 2 +(1 row) + +select * from "M_teSt_view"; + A +--- +(0 rows) + +-- index +CREATE INDEX i1 ON test USING btree(a); +CREATE INDEX "I1" ON "TeSt" USING btree("A"); +drop index "I1"; +-- Chinese characters +create table "¥" ("¥" int, "$" int); +create table "啊啊" ("," int, "," int); +select * from "¥"; + ¥ | $ +----+--- +(0 rows) + +select * from ¥; + ¥ | $ +----+--- +(0 rows) + +select * from "$"; -- errors +ERROR: relation "$" does not exist on datanode1 +LINE 1: select * from "$"; + ^ +select * from "啊啊"; + , | , +----+--- +(0 rows) + +insert into ¥("¥","$") values(1,2); +insert into ¥(¥,"$") values(4,3); +insert into "啊啊"(",",",") values(1,2); +-- function +create function f1(b int) returns int +as $$ +begin + return b; +end; +$$language plpgsql; +create function "F1"(b int) returns int +as $$ +begin + b=b+1; + return b; +end; +$$language plpgsql; +call f1(8); + f1 +---- + 8 +(1 row) + +call "F1"(8); + F1 +---- + 9 +(1 row) + +-- procedure +create procedure p1() is +begin + insert into test("A","a") values(5,9); +end; +/ +create procedure "P1"() is +begin + insert into "TeSt"("A") values(10); +end; +/ +call p1(); + p1 +---- + +(1 row) + +select * from test; + A | a +---+--- + 1 | 2 + 5 | 9 +(2 rows) + +call "P1"(); + P1 +---- + +(1 row) + +select * from "TeSt"; + A +---- + 10 +(1 row) + +-- type +CREATE TYPE compfoo AS (f1 int, f2 text); +CREATE TYPE "CompFoo" AS (f3 text, f4 int, f5 int); +CREATE TABLE t1_compfoo(a int, b compfoo); +CREATE TABLE t2_compfoo(a int, b "CompFoo"); +INSERT INTO t1_compfoo values(1,(1,'demo1')); +INSERT INTO t2_compfoo values(2,('demo2', 3, 5)); +select * from t1_compfoo; + a | b +---+----------- + 1 | (1,demo1) +(1 row) + +select * from t2_compfoo; + a | b +---+------------- + 2 | (demo2,3,5) +(1 row) + +-- sequence +CREATE SEQUENCE s1 START 101 CACHE 20; +CREATE SEQUENCE "S1" START 801 CACHE 90; +drop sequence "S1"; +-- test enable_ignore_case_in_dquotes=on +set enable_ignore_case_in_dquotes=on; +WARNING: if tables with the same name but different case already +exists in the database, this will result in only being able to +manipulate tables with table names that are entirely lowercase. +create table test1 ("A" int, 'a' int);-- error +ERROR: syntax error at or near "'a'" +LINE 1: create table test1 ("A" int, 'a' int); + ^ +insert into test("A","a") values(2,3);-- error +ERROR: column "a" specified more than once +LINE 1: insert into test("A","a") values(2,3); + ^ +select * from test; + A | a +---+--- + 1 | 2 + 5 | 9 +(2 rows) + +select * from test_view; + A | a +---+--- + 1 | 2 + 5 | 9 +(2 rows) + +select * from "TeSt_view";-- lowcase + A | a +---+--- + 1 | 2 + 5 | 9 +(2 rows) + +select * from m_test_view; + A | a +---+--- + 1 | 2 +(1 row) + +select * from "M_teSt_view";-- lowcase + A | a +---+--- + 1 | 2 +(1 row) + +call f1(8); + f1 +---- + 8 +(1 row) + +call "F1"(8); -- lowcase + f1 +---- + 8 +(1 row) + +call p1(8); +ERROR: function "p1" with 1 parameters doesn't exist +call "P1"(8); -- lowcase +ERROR: function "p1" with 1 parameters doesn't exist +CREATE TABLE t3_compfoo(a int, b "CompFoo"); +CREATE INDEX "I1" ON "TeSt" USING btree("A"); +ERROR: relation "i1" already exists +INSERT INTO t3_compfoo values(2,('demo2', 3, 5));-- error +ERROR: invalid input syntax for integer: "demo2" +LINE 1: INSERT INTO t3_compfoo values(2,('demo2', 3, 5)); + ^ +CONTEXT: referenced column: b +INSERT INTO t3_compfoo values(1,(1,'demo1')); +select * from t3_compfoo; + a | b +---+----------- + 1 | (1,demo1) +(1 row) + +CREATE SEQUENCE "S1" START 801 CACHE 90;-- error +ERROR: relation "s1" already exists in schema "sch_ignore_quote_01" +DETAIL: creating new table with existing name in the same schema +call p1(); + p1 +---- + +(1 row) + +select * from test; + A | a +---+--- + 1 | 2 + 5 | 9 + 5 | 9 +(3 rows) + +call "P1"(); + p1 +---- + +(1 row) + +select * from "TeSt"; + A | a +---+--- + 1 | 2 + 5 | 9 + 5 | 9 + 5 | 9 +(4 rows) + +create table "SCH_ignore_quote_01"."TAB_quote"("A" int); +insert into tab_quote (a) values (4); +insert into "SCH_IGNORE_QUOTE_01"."TAB_QUOTE" ("A") values (5); +select a from tab_quote; + a +--- + 4 + 5 +(2 rows) + +select t.a from sch_ignore_quote_01.tab_quote t; + a +--- + 4 + 5 +(2 rows) + +select t."A" from "SCH_IGNORE_QUOTE_01"."TAB_QUOTE" t; + a +--- + 4 + 5 +(2 rows) + +create table "¥¥" ("¥" int, "$" int); +create table "$" ("," int, "," int); +select * from "¥"; + ¥ | $ +----+--- + 1 | 2 + 4 | 3 +(2 rows) + +select * from ¥; + ¥ | $ +----+--- + 1 | 2 + 4 | 3 +(2 rows) + +select * from "$"; + , | , +----+--- +(0 rows) + +select * from "啊啊"; + , | , +----+--- + 1 | 2 +(1 row) + +insert into ¥("¥","$") values(5,6); +insert into ¥(¥,"$") values(7,8); +insert into "啊啊"(",",",") values(10,11); +-- clean +drop table TAB_quote; +set enable_ignore_case_in_dquotes=off; +drop materialized view m_test_view; +drop materialized view "M_teSt_view"; +drop index i1; +drop view test_view; +drop view "TeSt_view"; +drop table test; +drop table "TeSt"; +drop table "¥¥"; +drop table "$"; +drop table ¥; +drop table "啊啊"; +drop function f1; +drop function "F1"; +drop procedure p1; +drop procedure "P1"; +drop table t1_compfoo; +drop table t2_compfoo; +drop table t3_compfoo; +drop type compfoo; +drop type "CompFoo"; +drop sequence s1; +drop schema sch_ignore_quote_01; diff --git a/src/test/regress/output/recovery_2pc_tools.source b/src/test/regress/output/recovery_2pc_tools.source index 5c163e9de..a7692c586 100644 --- a/src/test/regress/output/recovery_2pc_tools.source +++ b/src/test/regress/output/recovery_2pc_tools.source @@ -284,6 +284,7 @@ select name,vartype,unit,min_val,max_val from pg_settings where name <> 'qunit_c enable_hdfs_predicate_pushdown | bool | | | enable_huge_pages | bool | | | enable_hypo_index | bool | | | + enable_ignore_case_in_dquotes | bool | | | enable_incremental_catchup | bool | | | enable_incremental_checkpoint | bool | | | enable_index_nestloop | bool | | | diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 23582c261..6c0a65a53 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -143,7 +143,7 @@ test: single_node_numerology # ---------- # The second group of parallel tests # ---------- -test: single_node_point single_node_lseg single_node_box single_node_path single_node_polygon single_node_circle single_node_date single_node_time single_node_timetz single_node_timestamp single_node_timestamptz +test: single_node_point single_node_lseg single_node_box single_node_path single_node_polygon single_node_circle single_node_date single_node_time single_node_timetz single_node_timestamp single_node_timestamptz ignore_double_quotes #test: single_node_interval test: single_node_abstime single_node_reltime #test: single_node_tinterval diff --git a/src/test/regress/parallel_schedule0B b/src/test/regress/parallel_schedule0B index 6ce031e1a..dc24cc79d 100644 --- a/src/test/regress/parallel_schedule0B +++ b/src/test/regress/parallel_schedule0B @@ -172,7 +172,7 @@ test: boolean name oid bit txid uuid numeric_hide_tailing_zero rawlike # The second group of parallel tests # ---------- #test: lseg box path polygon circle date time timetz timestamptz abstime reltime inet -test: interval tinterval macaddr tstypes comments +test: interval tinterval macaddr tstypes comments ignore_double_quotes #test: point timestamp # ---------- diff --git a/src/test/regress/sql/ignore_double_quotes.sql b/src/test/regress/sql/ignore_double_quotes.sql new file mode 100644 index 000000000..d9a4a7e09 --- /dev/null +++ b/src/test/regress/sql/ignore_double_quotes.sql @@ -0,0 +1,158 @@ +DROP SCHEMA sch_ignore_quote_01 CASCADE; +CREATE SCHEMA sch_ignore_quote_01; +SET CURRENT_SCHEMA TO sch_ignore_quote_01; + +-- test tables with the same name but different case already exists in the database +-- table +create table "TeSt" ("A" int); +select * from test; +select * from "TeSt"; +create table test ("A" int, "a" int); +insert into test("A","a") values(1,2); +select * from test; + +-- view +CREATE VIEW test_view AS SELECT * FROM test; +CREATE VIEW "TeSt_view" AS SELECT * FROM "TeSt"; +select * from test_view; +select * from "TeSt_view"; + +-- materialized view +CREATE MATERIALIZED VIEW m_test_view AS SELECT * FROM test; +CREATE MATERIALIZED VIEW "M_teSt_view" AS SELECT * FROM "TeSt"; +select * from m_test_view; +select * from "M_teSt_view"; + +-- index +CREATE INDEX i1 ON test USING btree(a); +CREATE INDEX "I1" ON "TeSt" USING btree("A"); +drop index "I1"; + +-- Chinese characters +create table "¥" ("¥" int, "$" int); +create table "啊啊" ("," int, "," int); +select * from "¥"; +select * from ¥; +select * from "$"; -- errors +select * from "啊啊"; +insert into ¥("¥","$") values(1,2); +insert into ¥(¥,"$") values(4,3); +insert into "啊啊"(",",",") values(1,2); + +-- function +create function f1(b int) returns int +as $$ +begin + return b; +end; +$$language plpgsql; + +create function "F1"(b int) returns int +as $$ +begin + b=b+1; + return b; +end; +$$language plpgsql; + +call f1(8); +call "F1"(8); + +-- procedure +create procedure p1() is +begin + insert into test("A","a") values(5,9); +end; +/ + +create procedure "P1"() is +begin + insert into "TeSt"("A") values(10); +end; +/ + +call p1(); +select * from test; +call "P1"(); +select * from "TeSt"; + +-- type +CREATE TYPE compfoo AS (f1 int, f2 text); +CREATE TYPE "CompFoo" AS (f3 text, f4 int, f5 int); +CREATE TABLE t1_compfoo(a int, b compfoo); +CREATE TABLE t2_compfoo(a int, b "CompFoo"); +INSERT INTO t1_compfoo values(1,(1,'demo1')); +INSERT INTO t2_compfoo values(2,('demo2', 3, 5)); +select * from t1_compfoo; +select * from t2_compfoo; + +-- sequence +CREATE SEQUENCE s1 START 101 CACHE 20; +CREATE SEQUENCE "S1" START 801 CACHE 90; +drop sequence "S1"; + +-- test enable_ignore_case_in_dquotes=on +set enable_ignore_case_in_dquotes=on; + +create table test1 ("A" int, 'a' int);-- error +insert into test("A","a") values(2,3);-- error +select * from test; +select * from test_view; +select * from "TeSt_view";-- lowcase +select * from m_test_view; +select * from "M_teSt_view";-- lowcase +call f1(8); +call "F1"(8); -- lowcase +call p1(8); +call "P1"(8); -- lowcase +CREATE TABLE t3_compfoo(a int, b "CompFoo"); +CREATE INDEX "I1" ON "TeSt" USING btree("A"); +INSERT INTO t3_compfoo values(2,('demo2', 3, 5));-- error +INSERT INTO t3_compfoo values(1,(1,'demo1')); +select * from t3_compfoo; +CREATE SEQUENCE "S1" START 801 CACHE 90;-- error +call p1(); +select * from test; +call "P1"(); +select * from "TeSt"; +create table "SCH_ignore_quote_01"."TAB_quote"("A" int); +insert into tab_quote (a) values (4); +insert into "SCH_IGNORE_QUOTE_01"."TAB_QUOTE" ("A") values (5); +select a from tab_quote; +select t.a from sch_ignore_quote_01.tab_quote t; +select t."A" from "SCH_IGNORE_QUOTE_01"."TAB_QUOTE" t; +create table "¥¥" ("¥" int, "$" int); +create table "$" ("," int, "," int); +select * from "¥"; +select * from ¥; +select * from "$"; +select * from "啊啊"; +insert into ¥("¥","$") values(5,6); +insert into ¥(¥,"$") values(7,8); +insert into "啊啊"(",",",") values(10,11); + +-- clean +drop table TAB_quote; +set enable_ignore_case_in_dquotes=off; +drop materialized view m_test_view; +drop materialized view "M_teSt_view"; +drop index i1; +drop view test_view; +drop view "TeSt_view"; +drop table test; +drop table "TeSt"; +drop table "¥¥"; +drop table "$"; +drop table ¥; +drop table "啊啊"; +drop function f1; +drop function "F1"; +drop procedure p1; +drop procedure "P1"; +drop table t1_compfoo; +drop table t2_compfoo; +drop table t3_compfoo; +drop type compfoo; +drop type "CompFoo"; +drop sequence s1; +drop schema sch_ignore_quote_01;