From dcf4f58a9ea0930243fd4cb1531868f6bf93096e Mon Sep 17 00:00:00 2001 From: TotaJ Date: Tue, 21 Jun 2022 20:14:30 +0800 Subject: [PATCH] Fix substr compat with pg. --- src/common/backend/utils/adt/varlena.cpp | 10 +- src/common/backend/utils/misc/guc/guc_sql.cpp | 3 +- src/include/miscadmin.h | 4 +- src/test/regress/expected/substr.out | 228 ++++++++++++++++++ src/test/regress/parallel_schedule0 | 2 +- src/test/regress/sql/substr.sql | 118 +++++++++ 6 files changed, 360 insertions(+), 5 deletions(-) create mode 100644 src/test/regress/expected/substr.out create mode 100644 src/test/regress/sql/substr.sql diff --git a/src/common/backend/utils/adt/varlena.cpp b/src/common/backend/utils/adt/varlena.cpp index 3d5c48aab..8f5ce477b 100644 --- a/src/common/backend/utils/adt/varlena.cpp +++ b/src/common/backend/utils/adt/varlena.cpp @@ -42,6 +42,8 @@ #include "executor/node/nodeSort.h" #include "pgxc/groupmgr.h" +#define SUBSTR_WITH_LEN_OFFSET 2 +#define SUBSTR_A_CMPT_OFFSET 4 #define JUDGE_INPUT_VALID(X, Y) ((NULL == (X)) || (NULL == (Y))) #define GET_POSITIVE(X) ((X) > 0 ? (X) : ((-1) * (X))) static int getResultPostionReverse(text* textStr, text* textStrToSearch, int32 beginIndex, int occurTimes); @@ -1278,8 +1280,12 @@ Datum text_substr_orclcompat(PG_FUNCTION_ARGS) FUNC_CHECK_HUGE_POINTER(PG_ARGISNULL(0), DatumGetPointer(str), "text_substr()"); is_compress = (VARATT_IS_COMPRESSED(DatumGetPointer(str)) || VARATT_IS_EXTERNAL(DatumGetPointer(str))); - // orclcompat is true, withlen is true - baseIdx = 6 + (int)is_compress + (eml - 1) * 8; + /* withlen is true */ + baseIdx = SUBSTR_WITH_LEN_OFFSET + (int)is_compress + (eml - 1) * 8; + if (!PGFORMAT_SUBSTR || !DB_IS_CMPT(PG_FORMAT)) { + /* if pgformat_substr is not on or current database is not pg format, use A cmpt */ + baseIdx += SUBSTR_A_CMPT_OFFSET; + } result = (*substr_Array[baseIdx])(str, start, length, &is_null, fun_mblen); diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index 9139bb39d..fb25df0b4 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -329,7 +329,8 @@ static const struct behavior_compat_entry behavior_compat_options[OPT_MAX] = { {"aformat_regexp_match", OPT_AFORMAT_REGEX_MATCH}, {"rownum_type_compat", OPT_ROWNUM_TYPE_COMPAT}, {"compat_cursor", OPT_COMPAT_CURSOR}, - {"char_coerce_compat", OPT_CHAR_COERCE_COMPAT} + {"char_coerce_compat", OPT_CHAR_COERCE_COMPAT}, + {"pgformat_substr", OPT_PGFORMAT_SUBSTR} }; /* diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 4b7754364..420a0dc86 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -127,7 +127,8 @@ extern bool contain_backend_version(uint32 version_number); #define OPT_ROWNUM_TYPE_COMPAT 1048576 #define OPT_COMPAT_CURSOR 2097152 #define OPT_CHAR_COERCE_COMPAT 4194304 -#define OPT_MAX 23 +#define OPT_PGFORMAT_SUBSTR 8388608 +#define OPT_MAX 24 #define DISPLAY_LEADING_ZERO (u_sess->utils_cxt.behavior_compat_flags & OPT_DISPLAY_LEADING_ZERO) @@ -156,6 +157,7 @@ extern bool contain_backend_version(uint32 version_number); #define ROWNUM_TYPE_COMPAT (u_sess->utils_cxt.behavior_compat_flags & OPT_ROWNUM_TYPE_COMPAT) #define COMPAT_CURSOR (u_sess->utils_cxt.behavior_compat_flags & OPT_COMPAT_CURSOR) #define CHAR_COERCE_COMPAT (u_sess->utils_cxt.behavior_compat_flags & OPT_CHAR_COERCE_COMPAT) +#define PGFORMAT_SUBSTR (u_sess->utils_cxt.behavior_compat_flags & OPT_PGFORMAT_SUBSTR) /* define database compatibility Attribute */ typedef struct { diff --git a/src/test/regress/expected/substr.out b/src/test/regress/expected/substr.out new file mode 100644 index 000000000..793907e73 --- /dev/null +++ b/src/test/regress/expected/substr.out @@ -0,0 +1,228 @@ +CREATE DATABASE substr_pg_format with dbcompatibility 'pg'; +\c substr_pg_format +show behavior_compat_options; + behavior_compat_options +------------------------- + +(1 row) + +CREATE TABLE toasttest(f1 text); +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; + substr +-------- + 0 + 0 + 0 + 0 +(4 rows) + +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; + substr +-------- + + + + +(4 rows) + +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; + substr +-------- + 567890 + 567890 + 567890 + 567890 +(4 rows) + +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + substr +-------- + 567890 + 567890 + 567890 + 567890 +(4 rows) + +DROP TABLE toasttest; +-- +-- test substr with toasted bytea values +-- +CREATE TABLE toasttest(f1 bytea); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; + substr +-------- + \x30 + \x30 + \x30 + \x30 +(4 rows) + +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; + substr +-------- + \x + \x + \x + \x +(4 rows) + +ERROR: negative substring length not allowed +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; +ERROR: syntax error at or near "ERROR" +LINE 1: ERROR: negative substring length not allowed + ^ +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + substr +---------------- + \x353637383930 + \x353637383930 + \x353637383930 + \x353637383930 +(4 rows) + +DROP TABLE toasttest; +----------------------------------------------------------------- +--- retest with behavior_compat_options to 'pgformat_substr' +----------------------------------------------------------------- +set behavior_compat_options to 'pgformat_substr'; +show behavior_compat_options; + behavior_compat_options +------------------------- + pgformat_substr +(1 row) + +CREATE TABLE toasttest(f1 text); +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; + substr +-------- + 123 + 123 + 123 + 123 +(4 rows) + +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; +ERROR: negative substring length not allowed +CONTEXT: referenced column: substr +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; + substr +-------- + 567890 + 567890 + 567890 + 567890 +(4 rows) + +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + substr +-------- + 567890 + 567890 + 567890 + 567890 +(4 rows) + +DROP TABLE toasttest; +-- +-- test substr with toasted bytea values +-- +CREATE TABLE toasttest(f1 bytea); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; + substr +-------- + \x30 + \x30 + \x30 + \x30 +(4 rows) + +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; + substr +-------- + \x + \x + \x + \x +(4 rows) + +ERROR: negative substring length not allowed +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; +ERROR: syntax error at or near "ERROR" +LINE 1: ERROR: negative substring length not allowed + ^ +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + substr +---------------- + \x353637383930 + \x353637383930 + \x353637383930 + \x353637383930 +(4 rows) + +DROP TABLE toasttest; +\c regression; +drop database IF EXISTS substr_pg_format; diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 9e3cfb820..e76ccea35 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -915,7 +915,7 @@ test: subscription test: fdw_audit test: gs_global_config_audit test: detail declare_multiple_variable -test: gs_dump_encrypt +test: gs_dump_encrypt substr test: composite_datum_record mysql_function test: join_test_alias diff --git a/src/test/regress/sql/substr.sql b/src/test/regress/sql/substr.sql new file mode 100644 index 000000000..97b77bd9d --- /dev/null +++ b/src/test/regress/sql/substr.sql @@ -0,0 +1,118 @@ +CREATE DATABASE substr_pg_format with dbcompatibility 'pg'; +\c substr_pg_format +show behavior_compat_options; +CREATE TABLE toasttest(f1 text); +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + +DROP TABLE toasttest; +-- +-- test substr with toasted bytea values +-- +CREATE TABLE toasttest(f1 bytea); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; + +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; +ERROR: negative substring length not allowed +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; + +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + +DROP TABLE toasttest; + +----------------------------------------------------------------- +--- retest with behavior_compat_options to 'pgformat_substr' +----------------------------------------------------------------- + +set behavior_compat_options to 'pgformat_substr'; +show behavior_compat_options; + +CREATE TABLE toasttest(f1 text); +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(repeat('1234567890',10000)); +insert into toasttest values(repeat('1234567890',10000)); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + +DROP TABLE toasttest; +-- +-- test substr with toasted bytea values +-- +CREATE TABLE toasttest(f1 bytea); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- +-- Ensure that some values are uncompressed, to test the faster substring +-- operation used in that case +-- +alter table toasttest alter column f1 set storage external; +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +insert into toasttest values(decode(repeat('1234567890',10000),'escape')); +-- If the starting position is zero or less, then return from the start of the string +-- adjusting the length to be consistent with the "negative start" per SQL92. +SELECT substr(f1, -1, 5) from toasttest; + +-- If the length is less than zero, an ERROR is thrown. +SELECT substr(f1, 5, -1) from toasttest; +ERROR: negative substring length not allowed +-- If no third argument (length) is provided, the length to the end of the +-- string is assumed. +SELECT substr(f1, 99995) from toasttest; + +-- If start plus length is > string length, the result is truncated to +-- string length +SELECT substr(f1, 99995, 10) from toasttest; + +DROP TABLE toasttest; + +\c regression; +drop database IF EXISTS substr_pg_format;