summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorditimizhev <[email protected]>2025-01-16 16:05:48 +0300
committerditimizhev <[email protected]>2025-01-16 16:30:54 +0300
commit7e86bcaf10a418760708b0be68e02abd715b745b (patch)
treea48b0c9efd485af31384bfaf60c8aada1f9ca3a8
parente812e2c1c25ae5339044634886773f66f443c061 (diff)
Add BATCH to update/delete stmts
Impl BATCH to UPDATE and DELETE stmts without ON for batch execution in YDB. commit_hash:426f8fae0635a8fec07e940e0f0dfba1974531bf
-rw-r--r--yql/essentials/providers/common/provider/yql_provider.cpp4
-rw-r--r--yql/essentials/providers/common/provider/yql_provider.h1
-rw-r--r--yql/essentials/sql/v1/SQLv1.g.in7
-rw-r--r--yql/essentials/sql/v1/SQLv1Antlr4.g.in7
-rw-r--r--yql/essentials/sql/v1/format/sql_format.cpp30
-rw-r--r--yql/essentials/sql/v1/insert.cpp25
-rw-r--r--yql/essentials/sql/v1/source.h2
-rw-r--r--yql/essentials/sql/v1/sql_query.cpp64
-rw-r--r--yql/essentials/sql/v1/sql_ut.cpp47
-rw-r--r--yql/essentials/sql/v1/sql_ut_antlr4.cpp49
10 files changed, 195 insertions, 41 deletions
diff --git a/yql/essentials/providers/common/provider/yql_provider.cpp b/yql/essentials/providers/common/provider/yql_provider.cpp
index ec2c3ca57c9..79156cd8d37 100644
--- a/yql/essentials/providers/common/provider/yql_provider.cpp
+++ b/yql/essentials/providers/common/provider/yql_provider.cpp
@@ -225,6 +225,7 @@ NYson::EYsonFormat GetYsonFormat(const IDataProvider::TFillSettings& fillSetting
TWriteTableSettings ParseWriteTableSettings(TExprList node, TExprContext& ctx) {
TMaybeNode<TCoAtom> mode;
TMaybeNode<TCoAtom> temporary;
+ TMaybeNode<TCoAtom> isBatch;
TMaybeNode<TExprList> columns;
TMaybeNode<TExprList> returningList;
TMaybeNode<TCoAtomList> primaryKey;
@@ -347,6 +348,8 @@ TWriteTableSettings ParseWriteTableSettings(TExprList node, TExprContext& ctx) {
} else if (name == "returning") {
YQL_ENSURE(tuple.Value().Maybe<TExprList>());
returningList = tuple.Value().Cast<TExprList>();
+ } else if (name == "is_batch") {
+ isBatch = Build<TCoAtom>(ctx, node.Pos()).Value("true").Done();
} else {
other.push_back(tuple);
}
@@ -380,6 +383,7 @@ TWriteTableSettings ParseWriteTableSettings(TExprList node, TExprContext& ctx) {
TWriteTableSettings ret(otherSettings);
ret.Mode = mode;
ret.Temporary = temporary;
+ ret.IsBatch = isBatch;
ret.Columns = columns;
ret.ReturningList = returningList;
ret.PrimaryKey = primaryKey;
diff --git a/yql/essentials/providers/common/provider/yql_provider.h b/yql/essentials/providers/common/provider/yql_provider.h
index 362b1e19584..978621d4b16 100644
--- a/yql/essentials/providers/common/provider/yql_provider.h
+++ b/yql/essentials/providers/common/provider/yql_provider.h
@@ -37,6 +37,7 @@ constexpr TStringBuf PgCatalogFileName = "_yql_pg_catalog";
struct TWriteTableSettings {
NNodes::TMaybeNode<NNodes::TCoAtom> Mode;
NNodes::TMaybeNode<NNodes::TCoAtom> Temporary;
+ NNodes::TMaybeNode<NNodes::TCoAtom> IsBatch;
NNodes::TMaybeNode<NNodes::TExprList> Columns;
NNodes::TMaybeNode<NNodes::TExprList> ReturningList;
NNodes::TMaybeNode<NNodes::TCoAtomList> PrimaryKey;
diff --git a/yql/essentials/sql/v1/SQLv1.g.in b/yql/essentials/sql/v1/SQLv1.g.in
index 61e7dc6f251..192a1a6026f 100644
--- a/yql/essentials/sql/v1/SQLv1.g.in
+++ b/yql/essentials/sql/v1/SQLv1.g.in
@@ -930,8 +930,8 @@ simple_table_ref_core: object_ref | COMMAT? bind_parameter;
simple_table_ref: simple_table_ref_core table_hints?;
into_simple_table_ref: simple_table_ref (ERASE BY pure_column_list)?;
-delete_stmt: DELETE FROM simple_table_ref (WHERE expr | ON into_values_source)? returning_columns_list?;
-update_stmt: UPDATE simple_table_ref (SET set_clause_choice (WHERE expr)? | ON into_values_source) returning_columns_list?;
+delete_stmt: BATCH? DELETE FROM simple_table_ref (WHERE expr | ON into_values_source)? returning_columns_list?;
+update_stmt: BATCH? UPDATE simple_table_ref (SET set_clause_choice (WHERE expr)? | ON into_values_source) returning_columns_list?;
/// out of 2003 standart
set_clause_choice: set_clause_list | multiple_column_assignment;
@@ -1278,6 +1278,7 @@ keyword_as_compat:
| ATTRIBUTES
| AUTOINCREMENT
| BACKUP
+ | BATCH
| BEFORE
| BEGIN
| BERNOULLI
@@ -1504,6 +1505,7 @@ keyword_compat: (
| ATTRIBUTES
| AUTOINCREMENT
| BACKUP
+ | BATCH
| BEFORE
| BEGIN
| BERNOULLI
@@ -1830,6 +1832,7 @@ ATTRIBUTES: A T T R I B U T E S;
AUTOINCREMENT: A U T O I N C R E M E N T;
AUTOMAP: A U T O M A P;
BACKUP: B A C K U P;
+BATCH: B A T C H;
COLLECTION: C O L L E C T I O N;
BEFORE: B E F O R E;
BEGIN: B E G I N;
diff --git a/yql/essentials/sql/v1/SQLv1Antlr4.g.in b/yql/essentials/sql/v1/SQLv1Antlr4.g.in
index 96e450501cd..3ae4ad6492d 100644
--- a/yql/essentials/sql/v1/SQLv1Antlr4.g.in
+++ b/yql/essentials/sql/v1/SQLv1Antlr4.g.in
@@ -929,8 +929,8 @@ simple_table_ref_core: object_ref | COMMAT? bind_parameter;
simple_table_ref: simple_table_ref_core table_hints?;
into_simple_table_ref: simple_table_ref (ERASE BY pure_column_list)?;
-delete_stmt: DELETE FROM simple_table_ref (WHERE expr | ON into_values_source)? returning_columns_list?;
-update_stmt: UPDATE simple_table_ref (SET set_clause_choice (WHERE expr)? | ON into_values_source) returning_columns_list?;
+delete_stmt: BATCH? DELETE FROM simple_table_ref (WHERE expr | ON into_values_source)? returning_columns_list?;
+update_stmt: BATCH? UPDATE simple_table_ref (SET set_clause_choice (WHERE expr)? | ON into_values_source) returning_columns_list?;
/// out of 2003 standart
set_clause_choice: set_clause_list | multiple_column_assignment;
@@ -1277,6 +1277,7 @@ keyword_as_compat:
| ATTRIBUTES
| AUTOINCREMENT
| BACKUP
+ | BATCH
| BEFORE
| BEGIN
| BERNOULLI
@@ -1503,6 +1504,7 @@ keyword_compat: (
| ATTRIBUTES
| AUTOINCREMENT
| BACKUP
+ | BATCH
| BEFORE
| BEGIN
| BERNOULLI
@@ -1829,6 +1831,7 @@ ATTRIBUTES: A T T R I B U T E S;
AUTOINCREMENT: A U T O I N C R E M E N T;
AUTOMAP: A U T O M A P;
BACKUP: B A C K U P;
+BATCH: B A T C H;
COLLECTION: C O L L E C T I O N;
BEFORE: B E F O R E;
BEGIN: B E G I N;
diff --git a/yql/essentials/sql/v1/format/sql_format.cpp b/yql/essentials/sql/v1/format/sql_format.cpp
index b7a8d5c48de..b6986310aa1 100644
--- a/yql/essentials/sql/v1/format/sql_format.cpp
+++ b/yql/essentials/sql/v1/format/sql_format.cpp
@@ -1084,11 +1084,11 @@ private:
void VisitUpdate(const TRule_update_stmt& msg) {
NewLine();
- Visit(msg.GetToken1());
- Visit(msg.GetRule_simple_table_ref2());
- switch (msg.GetBlock3().Alt_case()) {
- case TRule_update_stmt_TBlock3::kAlt1: {
- const auto& alt = msg.GetBlock3().GetAlt1();
+ Visit(msg.GetToken2());
+ Visit(msg.GetRule_simple_table_ref3());
+ switch (msg.GetBlock4().Alt_case()) {
+ case TRule_update_stmt_TBlock4::kAlt1: {
+ const auto& alt = msg.GetBlock4().GetAlt1();
NewLine();
Visit(alt.GetToken1());
const auto& choice = alt.GetRule_set_clause_choice2();
@@ -1175,8 +1175,8 @@ private:
PopCurrentIndent();
break;
}
- case TRule_update_stmt_TBlock3::kAlt2: {
- const auto& alt = msg.GetBlock3().GetAlt2();
+ case TRule_update_stmt_TBlock4::kAlt2: {
+ const auto& alt = msg.GetBlock4().GetAlt2();
NewLine();
Visit(alt.GetToken1());
Visit(alt.GetRule_into_values_source2());
@@ -1189,19 +1189,19 @@ private:
void VisitDelete(const TRule_delete_stmt& msg) {
NewLine();
- Visit(msg.GetToken1());
Visit(msg.GetToken2());
- Visit(msg.GetRule_simple_table_ref3());
- if (msg.HasBlock4()) {
- switch (msg.GetBlock4().Alt_case()) {
- case TRule_delete_stmt_TBlock4::kAlt1: {
- const auto& alt = msg.GetBlock4().GetAlt1();
+ Visit(msg.GetToken3());
+ Visit(msg.GetRule_simple_table_ref4());
+ if (msg.HasBlock5()) {
+ switch (msg.GetBlock5().Alt_case()) {
+ case TRule_delete_stmt_TBlock5::kAlt1: {
+ const auto& alt = msg.GetBlock5().GetAlt1();
NewLine();
Visit(alt);
break;
}
- case TRule_delete_stmt_TBlock4::kAlt2: {
- const auto& alt = msg.GetBlock4().GetAlt2();
+ case TRule_delete_stmt_TBlock5::kAlt2: {
+ const auto& alt = msg.GetBlock5().GetAlt2();
NewLine();
Visit(alt);
break;
diff --git a/yql/essentials/sql/v1/insert.cpp b/yql/essentials/sql/v1/insert.cpp
index 181137457f1..4af4986085b 100644
--- a/yql/essentials/sql/v1/insert.cpp
+++ b/yql/essentials/sql/v1/insert.cpp
@@ -300,6 +300,10 @@ public:
Update = std::move(update);
}
+ void ResetIsBatch(bool isBatch) {
+ IsBatch = isBatch;
+ }
+
bool DoInit(TContext& ctx, ISource* src) override {
TTableList tableList;
TNodePtr values;
@@ -347,6 +351,10 @@ public:
options = L(options, Q(Y(Q("update"), Update->Build(ctx))));
}
+ if (IsBatch) {
+ options = L(options, Q(Y(Q("is_batch"), Q("true"))));
+ }
+
auto write = BuildWriteTable(Pos, "values", Table, Mode, std::move(options), Scoped);
if (!write->Init(ctx, FakeSource.Get())) {
return false;
@@ -379,6 +387,7 @@ protected:
TSourcePtr Update;
TSourcePtr FakeSource;
TNodePtr Options;
+ bool IsBatch = false;
};
EWriteColumnMode ToWriteColumnsMode(ESQLWriteColumnMode sqlWriteColumnMode) {
@@ -398,12 +407,28 @@ TNodePtr BuildUpdateColumns(TPosition pos, TScopedStatePtr scoped, const TTableR
return writeNode;
}
+TNodePtr BuildBatchUpdate(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr values, TSourcePtr source, TNodePtr options) {
+ YQL_ENSURE(values, "Invalid values node");
+ TIntrusivePtr<TWriteColumnsNode> writeNode = new TWriteColumnsNode(pos, scoped, table, EWriteColumnMode::Update, nullptr, options);
+ writeNode->ResetSource(std::move(source));
+ writeNode->ResetUpdate(std::move(values));
+ writeNode->ResetIsBatch(true);
+ return writeNode;
+}
+
TNodePtr BuildDelete(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr source, TNodePtr options) {
TIntrusivePtr<TWriteColumnsNode> writeNode = new TWriteColumnsNode(pos, scoped, table, EWriteColumnMode::Delete, nullptr, options);
writeNode->ResetSource(std::move(source));
return writeNode;
}
+TNodePtr BuildBatchDelete(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr source, TNodePtr options) {
+ TIntrusivePtr<TWriteColumnsNode> writeNode = new TWriteColumnsNode(pos, scoped, table, EWriteColumnMode::Delete, nullptr, options);
+ writeNode->ResetSource(std::move(source));
+ writeNode->ResetIsBatch(true);
+ return writeNode;
+}
+
class TEraseColumnsNode: public TAstListNode {
public:
diff --git a/yql/essentials/sql/v1/source.h b/yql/essentials/sql/v1/source.h
index 20a7da80f90..f69684b03e6 100644
--- a/yql/essentials/sql/v1/source.h
+++ b/yql/essentials/sql/v1/source.h
@@ -299,7 +299,9 @@ namespace NSQLTranslationV1 {
TNodePtr BuildIntoTableOptions(TPosition pos, const TVector<TString>& eraseColumns, const TTableHints& hints);
TNodePtr BuildWriteColumns(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, EWriteColumnMode mode, TSourcePtr values, TNodePtr options = nullptr);
TNodePtr BuildUpdateColumns(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr values, TSourcePtr source, TNodePtr options = nullptr);
+ TNodePtr BuildBatchUpdate(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr values, TSourcePtr source, TNodePtr options = nullptr);
TNodePtr BuildDelete(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr source, TNodePtr options = nullptr);
+ TNodePtr BuildBatchDelete(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr source, TNodePtr options = nullptr);
// Implemented in query.cpp
TNodePtr BuildTableKey(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TViewDescription& view);
diff --git a/yql/essentials/sql/v1/sql_query.cpp b/yql/essentials/sql/v1/sql_query.cpp
index ac2baf978b3..9b8c1182db6 100644
--- a/yql/essentials/sql/v1/sql_query.cpp
+++ b/yql/essentials/sql/v1/sql_query.cpp
@@ -3232,28 +3232,30 @@ TNodePtr TSqlQuery::PragmaStatement(const TRule_pragma_stmt& stmt, bool& success
TNodePtr TSqlQuery::Build(const TRule_delete_stmt& stmt) {
TTableRef table;
- if (!SimpleTableRefImpl(stmt.GetRule_simple_table_ref3(), table)) {
+ if (!SimpleTableRefImpl(stmt.GetRule_simple_table_ref4(), table)) {
return nullptr;
}
const bool isKikimr = table.Service == KikimrProviderName;
if (!isKikimr) {
- Ctx.Error(GetPos(stmt.GetToken1())) << "DELETE is unsupported for " << table.Service;
+ Ctx.Error(GetPos(stmt.GetToken2())) << "DELETE is unsupported for " << table.Service;
return nullptr;
}
TSourcePtr source = BuildTableSource(Ctx.Pos(), table);
TNodePtr options = nullptr;
- if (stmt.HasBlock5()) {
- options = ReturningList(stmt.GetBlock5().GetRule_returning_columns_list1());
+ if (stmt.HasBlock6()) {
+ options = ReturningList(stmt.GetBlock6().GetRule_returning_columns_list1());
options = options->Y(options);
}
- if (stmt.HasBlock4()) {
- switch (stmt.GetBlock4().Alt_case()) {
- case TRule_delete_stmt_TBlock4::kAlt1: {
- const auto& alt = stmt.GetBlock4().GetAlt1();
+ const bool isBatch = stmt.HasBlock1();
+
+ if (stmt.HasBlock5()) {
+ switch (stmt.GetBlock5().Alt_case()) {
+ case TRule_delete_stmt_TBlock5::kAlt1: {
+ const auto& alt = stmt.GetBlock5().GetAlt1();
TColumnRefScope scope(Ctx, EColumnRefState::Allow);
TSqlExpression sqlExpr(Ctx, Mode);
@@ -3265,47 +3267,58 @@ TNodePtr TSqlQuery::Build(const TRule_delete_stmt& stmt) {
break;
}
- case TRule_delete_stmt_TBlock4::kAlt2: {
- const auto& alt = stmt.GetBlock4().GetAlt2();
+ case TRule_delete_stmt_TBlock5::kAlt2: {
+ const auto& alt = stmt.GetBlock5().GetAlt2();
auto values = TSqlIntoValues(Ctx, Mode).Build(alt.GetRule_into_values_source2(), "DELETE ON");
if (!values) {
return nullptr;
}
+ if (isBatch) {
+ Ctx.Error(GetPos(stmt.GetToken2())) << "BATCH DELETE is unsupported with ON";
+ return nullptr;
+ }
+
return BuildWriteColumns(Ctx.Pos(), Ctx.Scoped, table, EWriteColumnMode::DeleteOn, std::move(values), options);
}
- case TRule_delete_stmt_TBlock4::ALT_NOT_SET:
+ case TRule_delete_stmt_TBlock5::ALT_NOT_SET:
return nullptr;
}
}
+ if (isBatch) {
+ return BuildBatchDelete(Ctx.Pos(), Ctx.Scoped, table, std::move(source), options);
+ }
+
return BuildDelete(Ctx.Pos(), Ctx.Scoped, table, std::move(source), options);
}
TNodePtr TSqlQuery::Build(const TRule_update_stmt& stmt) {
TTableRef table;
- if (!SimpleTableRefImpl(stmt.GetRule_simple_table_ref2(), table)) {
+ if (!SimpleTableRefImpl(stmt.GetRule_simple_table_ref3(), table)) {
return nullptr;
}
const bool isKikimr = table.Service == KikimrProviderName;
if (!isKikimr) {
- Ctx.Error(GetPos(stmt.GetToken1())) << "UPDATE is unsupported for " << table.Service;
+ Ctx.Error(GetPos(stmt.GetToken2())) << "UPDATE is unsupported for " << table.Service;
return nullptr;
}
TNodePtr options = nullptr;
- if (stmt.HasBlock4()) {
- options = ReturningList(stmt.GetBlock4().GetRule_returning_columns_list1());
+ if (stmt.HasBlock5()) {
+ options = ReturningList(stmt.GetBlock5().GetRule_returning_columns_list1());
options = options->Y(options);
}
- switch (stmt.GetBlock3().Alt_case()) {
- case TRule_update_stmt_TBlock3::kAlt1: {
- const auto& alt = stmt.GetBlock3().GetAlt1();
+ const bool isBatch = stmt.HasBlock1();
+
+ switch (stmt.GetBlock4().Alt_case()) {
+ case TRule_update_stmt_TBlock4::kAlt1: {
+ const auto& alt = stmt.GetBlock4().GetAlt1();
TSourcePtr values = Build(alt.GetRule_set_clause_choice2());
auto source = BuildTableSource(Ctx.Pos(), table);
@@ -3319,21 +3332,30 @@ TNodePtr TSqlQuery::Build(const TRule_update_stmt& stmt) {
source->AddFilter(Ctx, whereExpr);
}
+ if (isBatch) {
+ return BuildBatchUpdate(Ctx.Pos(), Ctx.Scoped, table, std::move(values), std::move(source), options);
+ }
+
return BuildUpdateColumns(Ctx.Pos(), Ctx.Scoped, table, std::move(values), std::move(source), options);
}
- case TRule_update_stmt_TBlock3::kAlt2: {
- const auto& alt = stmt.GetBlock3().GetAlt2();
+ case TRule_update_stmt_TBlock4::kAlt2: {
+ const auto& alt = stmt.GetBlock4().GetAlt2();
auto values = TSqlIntoValues(Ctx, Mode).Build(alt.GetRule_into_values_source2(), "UPDATE ON");
if (!values) {
return nullptr;
}
+ if (isBatch) {
+ Ctx.Error(GetPos(stmt.GetToken2())) << "BATCH UPDATE is unsupported with ON";
+ return nullptr;
+ }
+
return BuildWriteColumns(Ctx.Pos(), Ctx.Scoped, table, EWriteColumnMode::UpdateOn, std::move(values), options);
}
- case TRule_update_stmt_TBlock3::ALT_NOT_SET:
+ case TRule_update_stmt_TBlock4::ALT_NOT_SET:
return nullptr;
}
}
diff --git a/yql/essentials/sql/v1/sql_ut.cpp b/yql/essentials/sql/v1/sql_ut.cpp
index efbed0e6653..e7b30928c32 100644
--- a/yql/essentials/sql/v1/sql_ut.cpp
+++ b/yql/essentials/sql/v1/sql_ut.cpp
@@ -1214,6 +1214,23 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
}
+ Y_UNIT_TEST(DeleteFromTableBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch delete from plato.Input;", 10, "kikimr");
+ UNIT_ASSERT(res.Root);
+
+ TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
+ if (word == "Write") {
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'delete)"));
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('is_batch 'true)"));
+ }
+ };
+
+ TWordCountHive elementStat = {{TString("Write"), 0}};
+ VerifyProgram(res, elementStat, verifyLine);
+
+ UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
+ }
+
Y_UNIT_TEST(DeleteFromTableOnValues) {
NYql::TAstParseResult res = SqlToYql("delete from plato.Input on (key) values (1);",
10, "kikimr");
@@ -1248,6 +1265,13 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
}
+ Y_UNIT_TEST(DeleteFromTableOnBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch delete from plato.Input on (key) values (1);",
+ 10, "kikimr");
+ UNIT_ASSERT(!res.Root);
+ UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:6: Error: BATCH DELETE is unsupported with ON\n");
+ }
+
Y_UNIT_TEST(UpdateByValues) {
NYql::TAstParseResult res = SqlToYql("update plato.Input set key = 777, value = 'cool' where key = 200;", 10, "kikimr");
UNIT_ASSERT(res.Root);
@@ -1274,6 +1298,23 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["AsStruct"]);
}
+ Y_UNIT_TEST(UpdateByValuesBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch update plato.Input set key = 777, value = 'cool' where key = 200;", 10, "kikimr");
+ UNIT_ASSERT(res.Root);
+
+ TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
+ if (word == "Write") {
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update)"));
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('is_batch 'true)"));
+ }
+ };
+
+ TWordCountHive elementStat = {{TString("Write"), 0}};
+ VerifyProgram(res, elementStat, verifyLine);
+
+ UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
+ }
+
Y_UNIT_TEST(UpdateByMultiValues) {
NYql::TAstParseResult res = SqlToYql("update plato.Input set (key, value, subkey) = ('2','ddd',':') where key = 200;", 10, "kikimr");
UNIT_ASSERT(res.Root);
@@ -1384,6 +1425,12 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
}
+ Y_UNIT_TEST(UpdateOnBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch update plato.Input on (key, value) values (5, 'cool')", 10, "kikimr");
+ UNIT_ASSERT(!res.Root);
+ UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:6: Error: BATCH UPDATE is unsupported with ON\n");
+ }
+
Y_UNIT_TEST(UnionAllTest) {
NYql::TAstParseResult res = SqlToYql("PRAGMA DisableEmitUnionMerge; SELECT key FROM plato.Input UNION ALL select subkey FROM plato.Input;");
UNIT_ASSERT(res.Root);
diff --git a/yql/essentials/sql/v1/sql_ut_antlr4.cpp b/yql/essentials/sql/v1/sql_ut_antlr4.cpp
index c5df28bbaa3..5337f573510 100644
--- a/yql/essentials/sql/v1/sql_ut_antlr4.cpp
+++ b/yql/essentials/sql/v1/sql_ut_antlr4.cpp
@@ -1290,6 +1290,23 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
}
+ Y_UNIT_TEST(DeleteFromTableBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch delete from plato.Input;", 10, "kikimr");
+ UNIT_ASSERT(res.Root);
+
+ TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
+ if (word == "Write") {
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'delete)"));
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('is_batch 'true)"));
+ }
+ };
+
+ TWordCountHive elementStat = {{TString("Write"), 0}};
+ VerifyProgram(res, elementStat, verifyLine);
+
+ UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
+ }
+
Y_UNIT_TEST(DeleteFromTableOnValues) {
NYql::TAstParseResult res = SqlToYql("delete from plato.Input on (key) values (1);",
10, "kikimr");
@@ -1324,6 +1341,13 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
}
+ Y_UNIT_TEST(DeleteFromTableOnBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch delete from plato.Input on (key) values (1);",
+ 10, "kikimr");
+ UNIT_ASSERT(!res.Root);
+ UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:6: Error: BATCH DELETE is unsupported with ON\n");
+ }
+
Y_UNIT_TEST(UpdateByValues) {
NYql::TAstParseResult res = SqlToYql("update plato.Input set key = 777, value = 'cool' where key = 200;", 10, "kikimr");
UNIT_ASSERT(res.Root);
@@ -1350,6 +1374,23 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["AsStruct"]);
}
+ Y_UNIT_TEST(UpdateByValuesBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch update plato.Input set key = 777, value = 'cool' where key = 200;", 10, "kikimr");
+ UNIT_ASSERT(res.Root);
+
+ TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
+ if (word == "Write") {
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update)"));
+ UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('is_batch 'true)"));
+ }
+ };
+
+ TWordCountHive elementStat = {{TString("Write"), 0}};
+ VerifyProgram(res, elementStat, verifyLine);
+
+ UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
+ }
+
Y_UNIT_TEST(UpdateByMultiValues) {
NYql::TAstParseResult res = SqlToYql("update plato.Input set (key, value, subkey) = ('2','ddd',':') where key = 200;", 10, "kikimr");
UNIT_ASSERT(res.Root);
@@ -1460,6 +1501,12 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
}
+ Y_UNIT_TEST(UpdateOnBatch) {
+ NYql::TAstParseResult res = SqlToYql("batch update plato.Input on (key, value) values (5, 'cool')", 10, "kikimr");
+ UNIT_ASSERT(!res.Root);
+ UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:6: Error: BATCH UPDATE is unsupported with ON\n");
+ }
+
Y_UNIT_TEST(UnionAllTest) {
NYql::TAstParseResult res = SqlToYql("PRAGMA DisableEmitUnionMerge; SELECT key FROM plato.Input UNION ALL select subkey FROM plato.Input;");
UNIT_ASSERT(res.Root);
@@ -5860,7 +5907,7 @@ Y_UNIT_TEST_SUITE(AnsiIdentsNegative) {
"*/ select 1;";
res = SqlToYql(req);
UNIT_ASSERT(!res.Root);
- UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:0: Error: mismatched input '*' expecting {';', '(', '$', ALTER, ANALYZE, BACKUP, COMMIT, CREATE, DECLARE, DEFINE, DELETE, DISCARD, DO, DROP, EVALUATE, EXPLAIN, EXPORT, FOR, FROM, GRANT, IF, IMPORT, INSERT, PARALLEL, PRAGMA, PROCESS, REDUCE, REPLACE, RESTORE, REVOKE, ROLLBACK, SELECT, UPDATE, UPSERT, USE, VALUES}\n");
+ UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:0: Error: mismatched input '*' expecting {';', '(', '$', ALTER, ANALYZE, BACKUP, BATCH, COMMIT, CREATE, DECLARE, DEFINE, DELETE, DISCARD, DO, DROP, EVALUATE, EXPLAIN, EXPORT, FOR, FROM, GRANT, IF, IMPORT, INSERT, PARALLEL, PRAGMA, PROCESS, REDUCE, REPLACE, RESTORE, REVOKE, ROLLBACK, SELECT, UPDATE, UPSERT, USE, VALUES}\n");
res = SqlToYqlWithAnsiLexer(req);
UNIT_ASSERT(res.Root);
}