Skip to content

Commit bacfdb2

Browse files
committed
[#26512] YSQL: Support MOD and some text expression pushdown in mixed mode
Summary: Add support and tests for pushing down MOD, LIKE, ASCII, SUBSTRING when in mixed mode of a major version upgrade. Also, update the initiatial definition of `yb_mixed_mode_expression_pushdown` to `true` in `ybc_guc.cc` to match it's default in `guc.c`. **Upgrade/Rollback safety** This is safe without autoflags because tservers (both PG11 and PG15) already know how to handle each of these functions. Versions before this change will not push them down, versions with this change will push down these functions. However, in either case, whatever is sent to DocDB can be handled by default. Jira: DB-15879 Test Plan: ``` ./yb_build.sh --cxx-test integration-tests_ysql_major_upgrade_expression_pushdown-test ./yb_build.sh --cxx-test integration-tests_ysql_major_upgrade_expression_pushdown-test --gtest_filter YsqlMajorUpgradeExpressionPushdownTest.TestStringOperations ``` Output of the python collector script: ``` UNTESTED WHITELISTED FUNCTIONS 1 / 276 {2074: 'F_SUBSTRING_TEXT_TEXT_TEXT'} ``` `SUBSTRING_TEXT_TEXT_TEXT` is difficult to test, as it always gets rewritten to another function. It is left whitelisted though. ``` explain analyze select * from tttt where (substring(t, 'h.'::text, c) = 'he'::text); QUERY PLAN ---------------------------------------------------------------------------------------------------- Seq Scan on tttt (cost=0.00..110.00 rows=1000 width=40) (actual time=3.630..3.631 rows=0 loops=1) Storage Filter: ("substring"(t, similar_to_escape('h.'::text, (c)::text)) = 'he'::text) Planning Time: 1.686 ms Execution Time: 3.754 ms (4 rows) ``` Notice that `substring(t, 'h.'::text, c)` was rewritten to `"substring"(t, similar_to_escape('h.'::text, (c)::text))` Reviewers: hsunder, amartsinchyk, fizaa Reviewed By: fizaa Subscribers: svc_phabricator, jason, yql Differential Revision: https://phorge.dev.yugabyte.com/D42372
1 parent a5e67ea commit bacfdb2

File tree

3 files changed

+130
-1
lines changed

3 files changed

+130
-1
lines changed

src/postgres/src/backend/utils/misc/yb_exceptions_for_func_pushdown.c

+29
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,35 @@ const uint32 yb_funcs_safe_for_mixed_mode_pushdown[] = {
195195
COMPARISON_OPS(TIMESTAMPTZ_),
196196
COMPARISON_OPS(DATE_),
197197
COMPARISON_OPS(INTERVAL_),
198+
199+
F_INT2MOD,
200+
F_INT4MOD,
201+
F_INT8MOD,
202+
F_NUMERIC_MOD,
203+
F_MOD_INT2_INT2,
204+
F_MOD_INT4_INT4,
205+
F_MOD_INT8_INT8,
206+
F_MOD_NUMERIC_NUMERIC,
207+
208+
F_TEXTLIKE,
209+
F_TEXTNLIKE,
210+
F_LIKE_TEXT_TEXT,
211+
F_NOTLIKE_TEXT_TEXT,
212+
F_BPCHARLIKE,
213+
F_BPCHARNLIKE,
214+
F_TEXTICLIKE,
215+
F_TEXTICNLIKE,
216+
F_BPCHARICLIKE,
217+
F_BPCHARICNLIKE,
218+
F_TEXTREGEXEQ,
219+
F_TEXTREGEXNE,
220+
221+
F_ASCII,
222+
223+
F_SUBSTRING_TEXT_TEXT,
224+
F_SUBSTRING_TEXT_TEXT_TEXT,
225+
F_SUBSTRING_TEXT_INT4,
226+
F_SUBSTRING_TEXT_INT4_INT4,
198227
};
199228

200229
#define DEFINE_ARRAY_SIZE(array) const int array##_count = lengthof(array)

src/yb/integration-tests/upgrade-tests/ysql_major_upgrade_expression_pushdown-test.cc

+100
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,46 @@ class YsqlMajorUpgradeExpressionPushdownTest : public YsqlMajorUpgradeTestBase {
331331
}
332332
}
333333

334+
const auto get_mod_name = [](std::string &col) {
335+
if (col == kInt2Column) {
336+
return "int2mod";
337+
} else if (col == kInt4Column) {
338+
return "int4mod";
339+
} else if (col == kInt8Column) {
340+
return "int8mod";
341+
} else if (col == kNumericColumn) {
342+
return "numeric_mod";
343+
}
344+
return "invalid mod function";
345+
};
346+
347+
// Add MOD expressions
348+
for (auto t1 : numeric_types) {
349+
if (is_float(t1))
350+
continue;
351+
if (t1 == kInt4Column) {
352+
for (const auto& mod_name : {get_mod_name(t1), "mod"}) {
353+
exprs.push_back(Expression(Format("($0($1, 10) = 0)", mod_name, t1),
354+
Behaviour::kPushable, Behaviour::kMMPushable));
355+
}
356+
exprs.push_back(Expression(Format("(($0 % 10) = 0)", t1),
357+
Behaviour::kPushable, Behaviour::kMMPushable));
358+
} else if (is_int(t1)) {
359+
for (const auto& mod_name : {get_mod_name(t1), "mod"}) {
360+
exprs.push_back(Expression(Format("($0($1, '10'::$2) = 0)", mod_name, t1, get_cast(t1)),
361+
Behaviour::kPushable, Behaviour::kMMPushable));
362+
}
363+
exprs.push_back(Expression(Format("(($0 % '10'::$1) = 0)", t1, get_cast(t1)),
364+
Behaviour::kPushable, Behaviour::kMMPushable));
365+
} else {
366+
for (const auto &mod_name : {"numeric_mod", "mod"}) {
367+
exprs.push_back(Expression(Format("($0($1, '10'::numeric) = 0.0)", mod_name, t1),
368+
Behaviour::kPushable, Behaviour::kMMPushable));
369+
}
370+
exprs.push_back(Expression(Format("(($0 % '10'::numeric) = 0.0)", t1),
371+
Behaviour::kPushable, Behaviour::kMMPushable));
372+
}
373+
}
334374

335375
exprs.push_back(Expression(Format("(($0)::integer = $1)", kBoolColumn, kInt4Column),
336376
Behaviour::kPushable, Behaviour::kMMPushable));
@@ -564,6 +604,66 @@ TEST_F(YsqlMajorUpgradeExpressionPushdownTest, TestNewPg15Functions) {
564604
}));
565605
}
566606

607+
TEST_F(YsqlMajorUpgradeExpressionPushdownTest, TestStringOperations) {
608+
static const auto kTable = "text_tbl";
609+
static const auto kTextColumn = "text_col";
610+
static const auto kVarcharColumn = "varchar_col";
611+
static const auto kCharColumn = "char_col";
612+
static const auto kBpCharColumn = "bpchar_col";
613+
614+
{
615+
auto conn = ASSERT_RESULT(CreateConnToTs(kAnyTserver));
616+
ASSERT_OK(conn.ExecuteFormat(
617+
"CREATE TABLE $0($1 TEXT, $2 VARCHAR, $3 CHAR, $4 BPCHAR)",
618+
kTable, kTextColumn, kVarcharColumn, kCharColumn, kBpCharColumn));
619+
ASSERT_OK(conn.ExecuteFormat(
620+
"INSERT INTO $0 VALUES ('hello', 'world', 'a', 'b')", kTable));
621+
}
622+
623+
std::vector<Expression> exprs;
624+
for (const auto &cond : {
625+
Format("($0 ~~ 'h%'::text)", kTextColumn), // F_TEXTLIKE
626+
Format("($0 !~~ 'h%'::text)", kTextColumn), // F_TEXTNLIKE
627+
Format("($0 ~~ ($1)::text)", kTextColumn, kVarcharColumn), // F_LIKE_TEXT_TEXT
628+
Format("($0 !~~ ($1)::text)", kTextColumn, kVarcharColumn), // F_NOTLIKE_TEXT_TEXT
629+
Format("($0 ~~ 'b%'::text)", kBpCharColumn), // F_BPCHARLIKE
630+
Format("($0 !~~ 'b%'::text)", kBpCharColumn), // F_BPCHARNLIKE
631+
Format("($0 ~~* 'H%'::text)", kTextColumn), // F_TEXTICLIKE
632+
Format("($0 !~~* 'H%'::text)", kTextColumn), // F_TEXTICNLIKE
633+
Format("($0 ~~* 'B%'::text)", kBpCharColumn), // F_BPCHARICLIKE
634+
Format("($0 !~~* 'B%'::text)", kBpCharColumn), // F_BPCHARICNLIKE
635+
Format("($0 ~ 'h.*'::text)", kTextColumn), // F_TEXTREGEXEQ
636+
Format("($0 !~ 'h.*'::text)", kTextColumn), // F_TEXTREGEXNE
637+
Format("(ascii($0) = 104)", kTextColumn), // F_ASCII
638+
Format("(\"substring\"($0, 'h.'::text) = 'he'::text)", kTextColumn), // F_SUBSTRING_TEXT_TEXT
639+
Format("(\"substring\"($0, 2) = 'ello'::text)", kTextColumn), // F_SUBSTRING_TEXT_INT4
640+
Format("(\"substring\"($0, 2, 3) = 'ell'::text)", kTextColumn), // F_SUBSTRING_TEXT_INT4_INT4
641+
}) {
642+
exprs.push_back(Expression(cond, Behaviour::kPushable, Behaviour::kMMPushable));
643+
}
644+
645+
// special cases: the formatting for these conditions changes in the output depending on the YSQL
646+
// version, so use a regex to check that the correct condition is present in the output
647+
exprs.push_back(Expression(Format("like($0, 'h%'::text)", kTextColumn), // F_LIKE_TEXT_TEXT
648+
Behaviour::kPushable, Behaviour::kMMPushable, ".*like.*"));
649+
exprs.push_back(Expression(Format("notlike($0, 'h%'::text)", kTextColumn), // F_NOTLIKE_TEXT_TEXT
650+
Behaviour::kPushable, Behaviour::kMMPushable, ".*notlike.*"));
651+
652+
// these functions don't exist in PG11, so they can't be pushed
653+
exprs.push_back(Expression(Format("regexp_like($0, 'h.*'::text)", kTextColumn),
654+
Behaviour::kFunctionError, Behaviour::kPushable, ".*regexp_like.*"));
655+
656+
for (const auto& cond : {
657+
Format("(regexp_substr($0, 'h.'::text) = 'he'::text)", kTextColumn),
658+
Format("(regexp_substr($0, 'h.'::text, 1) = 'he'::text)", kTextColumn),
659+
}) {
660+
exprs.push_back(Expression(cond, Behaviour::kFunctionError, Behaviour::kPushable));
661+
}
662+
663+
const auto prefix = Format("EXPLAIN $0 SELECT * FROM $1 WHERE", kExplainArgs, kTable);
664+
ASSERT_OK(TestPushdowns(prefix, exprs));
665+
}
666+
567667
TEST_F(YsqlMajorUpgradeExpressionPushdownTest, TestTimePushdowns) {
568668
static const auto kTimeTable = "time_tbl";
569669
static const auto kTimestampCol = "timestamp_col";

src/yb/yql/pggate/util/ybc_guc.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,4 @@ bool yb_disable_auto_analyze = false;
119119

120120
bool yb_extension_upgrade = false;
121121

122-
bool yb_mixed_mode_expression_pushdown = false;
122+
bool yb_mixed_mode_expression_pushdown = true;

0 commit comments

Comments
 (0)