summaryrefslogtreecommitdiffstats
path: root/yql/essentials/sql
diff options
context:
space:
mode:
authorvitya-smirnov <[email protected]>2025-09-03 16:23:37 +0300
committervitya-smirnov <[email protected]>2025-09-03 16:53:40 +0300
commit1a6fddffd17953f4ed4d20de9fdd5c010166acd1 (patch)
tree1f90d4097dccbfa041bc9ef3ce695e75f51a3ed3 /yql/essentials/sql
parentdb0b30ed142b14352bba1fb6e67768928da20d49 (diff)
YQL-20189: Track warnings as errors
There was an issue that a query with warnings as errors passed translation. commit_hash:890d18853380b5ad669e9684553cdb6991827cff
Diffstat (limited to 'yql/essentials/sql')
-rw-r--r--yql/essentials/sql/v1/builtin.cpp49
-rw-r--r--yql/essentials/sql/v1/context.cpp72
-rw-r--r--yql/essentials/sql/v1/context.h15
-rw-r--r--yql/essentials/sql/v1/insert.cpp6
-rw-r--r--yql/essentials/sql/v1/node.cpp57
-rw-r--r--yql/essentials/sql/v1/node.h2
-rw-r--r--yql/essentials/sql/v1/query.cpp15
-rw-r--r--yql/essentials/sql/v1/select.cpp32
-rw-r--r--yql/essentials/sql/v1/sql_expression.cpp28
-rw-r--r--yql/essentials/sql/v1/sql_query.cpp48
-rw-r--r--yql/essentials/sql/v1/sql_select.cpp31
-rw-r--r--yql/essentials/sql/v1/sql_translation.cpp38
-rw-r--r--yql/essentials/sql/v1/sql_ut_common.h50
-rw-r--r--yql/essentials/sql/v1/sql_values.cpp8
14 files changed, 346 insertions, 105 deletions
diff --git a/yql/essentials/sql/v1/builtin.cpp b/yql/essentials/sql/v1/builtin.cpp
index c660d35817c..f8d84095259 100644
--- a/yql/essentials/sql/v1/builtin.cpp
+++ b/yql/essentials/sql/v1/builtin.cpp
@@ -487,14 +487,20 @@ public:
// TODO: TablePath() and TableRecordIndex() have more strict limitations
if (src->GetJoin()) {
- ctx.Warning(Pos_,
- TIssuesIds::YQL_EMPTY_TABLENAME_RESULT) << "TableName() may produce empty result when used in ambiguous context (with JOIN)";
+ if (!ctx.Warning(Pos_, TIssuesIds::YQL_EMPTY_TABLENAME_RESULT, [](auto& out) {
+ out << "TableName() may produce empty result when used in ambiguous context (with JOIN)";
+ })) {
+ return false;
+ }
}
if (src->HasAggregations()) {
- ctx.Warning(Pos_,
- TIssuesIds::YQL_EMPTY_TABLENAME_RESULT) << "TableName() will produce empty result when used with aggregation.\n"
- "Please consult documentation for possible workaround";
+ if (!ctx.Warning(Pos_, TIssuesIds::YQL_EMPTY_TABLENAME_RESULT, [](auto& out) {
+ out << "TableName() will produce empty result when used with aggregation.\n"
+ "Please consult documentation for possible workaround";
+ })) {
+ return false;
+ }
}
Args_.push_back(Y("TablePath", Y("DependsOn", "row")));
@@ -1615,10 +1621,13 @@ private:
// TODO: 'IN ((select ...))' is parsed exactly like 'IN (select ...)' instead of a single element tuple
if (singleElement->GetSource() || singleElement->IsSelect()) {
TStringBuf parenKind = singleElement->GetSource() ? "" : "external ";
- ctx.Warning(pos,
- TIssuesIds::YQL_CONST_SUBREQUEST_IN_LIST) << "Using subrequest in scalar context after IN, "
- << "perhaps you should remove "
- << parenKind << "parenthesis here";
+ if (!ctx.Warning(pos, TIssuesIds::YQL_CONST_SUBREQUEST_IN_LIST, [&](auto& out) {
+ out << "Using subrequest in scalar context after IN, "
+ << "perhaps you should remove "
+ << parenKind << "parenthesis here";
+ })) {
+ return false;
+ }
}
}
@@ -3448,7 +3457,12 @@ TNodePtr BuildBuiltinFunc(TContext& ctx, TPosition pos, TString name, const TVec
}
if (ns == "datetime2") {
- ctx.Warning(pos, TIssuesIds::YQL_DEPRECATED_DATETIME2) << "DateTime2:: is a temporary alias for DateTime:: which will be removed in the future, use DateTime:: instead";
+ if (!ctx.Warning(pos, TIssuesIds::YQL_DEPRECATED_DATETIME2, [](auto& out) {
+ out << "DateTime2:: is a temporary alias for DateTime:: which will be "
+ << "removed in the future, use DateTime:: instead";
+ })) {
+ return nullptr;
+ }
}
if (ns == "datetime") {
@@ -3475,9 +3489,12 @@ TNodePtr BuildBuiltinFunc(TContext& ctx, TPosition pos, TString name, const TVec
if (ns == "yql" || ns == "@yql") {
if (warnOnYqlNameSpace && GetEnv("YQL_DETERMINISTIC_MODE").empty()) {
- ctx.Warning(pos, TIssuesIds::YQL_S_EXPRESSIONS_CALL)
- << "It is not recommended to directly access s-expressions functions via YQL::" << Endl
- << "This mechanism is mostly intended for temporary workarounds or internal testing purposes";
+ if (!ctx.Warning(pos, TIssuesIds::YQL_S_EXPRESSIONS_CALL, [](auto& out) {
+ out << "It is not recommended to directly access s-expressions functions via YQL::" << Endl
+ << "This mechanism is mostly intended for temporary workarounds or internal testing purposes";
+ })) {
+ return nullptr;
+ }
}
if (ns == "yql") {
@@ -3890,7 +3907,11 @@ TNodePtr BuildBuiltinFunc(TContext& ctx, TPosition pos, TString name, const TVec
TNodePtr customUserType = nullptr;
if (ns == "json") {
- ctx.Warning(pos, TIssuesIds::YQL_DEPRECATED_JSON_UDF) << "Json UDF is deprecated. Please use JSON API instead";
+ if (!ctx.Warning(pos, TIssuesIds::YQL_DEPRECATED_JSON_UDF, [](auto& out) {
+ out << "Json UDF is deprecated. Please use JSON API instead";
+ })) {
+ return nullptr;
+ }
ns = "yson";
nameSpace = "Yson";
diff --git a/yql/essentials/sql/v1/context.cpp b/yql/essentials/sql/v1/context.cpp
index cdf2a60824d..440f7ca11df 100644
--- a/yql/essentials/sql/v1/context.cpp
+++ b/yql/essentials/sql/v1/context.cpp
@@ -7,6 +7,7 @@
#include <util/folder/pathsplit.h>
#include <util/string/join.h>
#include <util/stream/null.h>
+#include <util/generic/scope.h>
#ifdef GetMessage
#undef GetMessage
@@ -108,6 +109,7 @@ TContext::TContext(const TLexers& lexers, const TParsers& parsers,
, AnsiQuotedIdentifiers(settings.AnsiLexer)
, WarningPolicy(settings.IsReplay)
, BlockEngineEnable(Settings.BlockDefaultAuto->Allow())
+ , StrictWarningAsError(Settings.Flags.contains("StrictWarningAsError"))
{
if (settings.LangVer >= MakeLangVersion(2025, 2)) {
GroupByExprAfterWhere = true;
@@ -188,15 +190,20 @@ IOutputStream& TContext::Error(NYql::TIssueCode code) {
IOutputStream& TContext::Error(NYql::TPosition pos, NYql::TIssueCode code) {
HasPendingErrors = true;
- return MakeIssue(TSeverityIds::S_ERROR, code, pos);
+ bool isError;
+ return MakeIssue(TSeverityIds::S_ERROR, code, pos, isError);
}
-IOutputStream& TContext::Warning(NYql::TPosition pos, NYql::TIssueCode code) {
- return MakeIssue(TSeverityIds::S_WARNING, code, pos);
+bool TContext::Warning(NYql::TPosition pos, NYql::TIssueCode code, std::function<void(IOutputStream&)> message) {
+ bool isError;
+ IOutputStream& out = MakeIssue(TSeverityIds::S_WARNING, code, pos, isError);
+ message(out);
+ return !StrictWarningAsError || !isError;
}
IOutputStream& TContext::Info(NYql::TPosition pos) {
- return MakeIssue(TSeverityIds::S_INFO, TIssuesIds::INFO, pos);
+ bool isError;
+ return MakeIssue(TSeverityIds::S_INFO, TIssuesIds::INFO, pos, isError);
}
void TContext::SetWarningPolicyFor(NYql::TIssueCode code, NYql::EWarningAction action) {
@@ -221,22 +228,28 @@ TVector<NSQLTranslation::TSQLHint> TContext::PullHintForToken(NYql::TPosition to
return result;
}
-void TContext::WarnUnusedHints() {
- if (!SqlHints_.empty()) {
- // warn about first unused hint
- auto firstUnused = SqlHints_.begin();
- YQL_ENSURE(!firstUnused->second.empty());
- const NSQLTranslation::TSQLHint& hint = firstUnused->second.front();
- Warning(hint.Pos, TIssuesIds::YQL_UNUSED_HINT) << "Hint " << hint.Name << " will not be used";
+bool TContext::WarnUnusedHints() {
+ if (SqlHints_.empty()) {
+ return true;
}
+
+ auto firstUnused = SqlHints_.begin();
+ YQL_ENSURE(!firstUnused->second.empty());
+ const NSQLTranslation::TSQLHint& hint = firstUnused->second.front();
+ return Warning(hint.Pos, TIssuesIds::YQL_UNUSED_HINT, [&](auto& out) {
+ out << "Hint " << hint.Name << " will not be used";
+ });
}
-IOutputStream& TContext::MakeIssue(ESeverity severity, TIssueCode code, NYql::TPosition pos) {
+IOutputStream& TContext::MakeIssue(ESeverity severity, TIssueCode code, NYql::TPosition pos, bool& isError) {
+ isError = (severity == TSeverityIds::S_ERROR);
+
if (severity == TSeverityIds::S_WARNING) {
auto action = WarningPolicy.GetAction(code);
if (action == EWarningAction::ERROR) {
severity = TSeverityIds::S_ERROR;
HasPendingErrors = true;
+ isError = true;
} else if (action == EWarningAction::DISABLE) {
return Cnull;
}
@@ -635,35 +648,52 @@ TString TTranslation::PushNamedAtom(TPosition namePos, const TString& name) {
return PushNamedNode(namePos, name, buildAtom);
}
-void TTranslation::PopNamedNode(const TString& name) {
+bool TTranslation::PopNamedNode(const TString& name) {
auto mapIt = Ctx_.Scoped->NamedNodes.find(name);
Y_DEBUG_ABORT_UNLESS(mapIt != Ctx_.Scoped->NamedNodes.end());
Y_DEBUG_ABORT_UNLESS(mapIt->second.size() > 0);
+
+ Y_DEFER {
+ mapIt->second.pop_front();
+ if (mapIt->second.empty()) {
+ Ctx_.Scoped->NamedNodes.erase(mapIt);
+ }
+ };
+
auto& top = mapIt->second.front();
if (!top->IsUsed && !Ctx_.HasPendingErrors && !name.StartsWith("$_")) {
- Ctx_.Warning(top->NamePos, TIssuesIds::YQL_UNUSED_SYMBOL) << "Symbol " << name << " is not used";
- }
- mapIt->second.pop_front();
- if (mapIt->second.empty()) {
- Ctx_.Scoped->NamedNodes.erase(mapIt);
+ if (!Ctx_.Warning(top->NamePos, TIssuesIds::YQL_UNUSED_SYMBOL, [&](auto& out) {
+ out << "Symbol " << name << " is not used";
+ })) {
+ return false;
+ }
}
+ return true;
}
-void TTranslation::WarnUnusedNodes() const {
+bool TTranslation::WarnUnusedNodes() const {
if (Ctx_.HasPendingErrors) {
// result is not reliable in this case
- return;
+ return true;
}
+
for (const auto& [name, items]: Ctx_.Scoped->NamedNodes) {
if (name.StartsWith("$_")) {
continue;
}
+
for (const auto& item : items) {
if (!item->IsUsed && item->Level == Ctx_.ScopeLevel) {
- Ctx_.Warning(item->NamePos, TIssuesIds::YQL_UNUSED_SYMBOL) << "Symbol " << name << " is not used";
+ if (!Ctx_.Warning(item->NamePos, TIssuesIds::YQL_UNUSED_SYMBOL, [&](auto& out) {
+ out << "Symbol " << name << " is not used";
+ })) {
+ return false;
+ }
}
}
}
+
+ return true;
}
TString GetDescription(const google::protobuf::Message& node, const google::protobuf::FieldDescriptor* d) {
diff --git a/yql/essentials/sql/v1/context.h b/yql/essentials/sql/v1/context.h
index 7ae995059a8..5289b9e213d 100644
--- a/yql/essentials/sql/v1/context.h
+++ b/yql/essentials/sql/v1/context.h
@@ -107,7 +107,7 @@ namespace NSQLTranslationV1 {
IOutputStream& Error(NYql::TIssueCode code = NYql::TIssuesIds::DEFAULT_ERROR);
IOutputStream& Error(NYql::TPosition pos, NYql::TIssueCode code = NYql::TIssuesIds::DEFAULT_ERROR);
- IOutputStream& Warning(NYql::TPosition pos, NYql::TIssueCode code);
+ bool Warning(NYql::TPosition pos, NYql::TIssueCode code, std::function<void(IOutputStream&)> message);
IOutputStream& Info(NYql::TPosition pos);
void SetWarningPolicyFor(NYql::TIssueCode code, NYql::EWarningAction action);
@@ -243,12 +243,16 @@ namespace NSQLTranslationV1 {
}
TVector<NSQLTranslation::TSQLHint> PullHintForToken(NYql::TPosition tokenPos);
- void WarnUnusedHints();
+ bool WarnUnusedHints();
TScopedStatePtr CreateScopedState() const;
private:
- IOutputStream& MakeIssue(NYql::ESeverity severity, NYql::TIssueCode code, NYql::TPosition pos);
+ IOutputStream& MakeIssue(
+ NYql::ESeverity severity,
+ NYql::TIssueCode code,
+ NYql::TPosition pos,
+ bool& isError);
public:
const TLexers Lexers;
@@ -382,6 +386,7 @@ namespace NSQLTranslationV1 {
bool OptimizeSimpleIlike = false;
bool PersistableFlattenAndAggrExprs = false;
bool DebugPositions = false;
+ bool StrictWarningAsError = false;
TVector<size_t> ForAllStatementsParts;
TMaybe<TString> Engine;
@@ -460,8 +465,8 @@ namespace NSQLTranslationV1 {
TString PushNamedNode(TPosition namePos, const TString& name, const TNodeBuilderByName& builder);
TString PushNamedNode(TPosition namePos, const TString& name, TNodePtr node);
TString PushNamedAtom(TPosition namePos, const TString& name);
- void PopNamedNode(const TString& name);
- void WarnUnusedNodes() const;
+ bool PopNamedNode(const TString& name);
+ bool WarnUnusedNodes() const;
template <typename TNode>
void AltNotImplemented(const TString& ruleName, const TNode& node) {
diff --git a/yql/essentials/sql/v1/insert.cpp b/yql/essentials/sql/v1/insert.cpp
index 9590b7642fb..42bddd74ca0 100644
--- a/yql/essentials/sql/v1/insert.cpp
+++ b/yql/essentials/sql/v1/insert.cpp
@@ -220,7 +220,11 @@ public:
}
}
if (mismatchFound) {
- ctx.Warning(Pos_, TIssuesIds::YQL_SOURCE_SELECT_COLUMN_MISMATCH) << str.Str();
+ if (!ctx.Warning(Pos_, TIssuesIds::YQL_SOURCE_SELECT_COLUMN_MISMATCH, [&](auto& out) {
+ out << str.Str();
+ })) {
+ return false;
+ }
}
}
return true;
diff --git a/yql/essentials/sql/v1/node.cpp b/yql/essentials/sql/v1/node.cpp
index 6075eb195fd..1c87734edad 100644
--- a/yql/essentials/sql/v1/node.cpp
+++ b/yql/essentials/sql/v1/node.cpp
@@ -1204,11 +1204,17 @@ bool TWinRank::DoInit(TContext& ctx, ISource* src) {
const auto& orderSpec = winSpecPtr->OrderBy;
if (orderSpec.empty()) {
if (Args_.empty()) {
- ctx.Warning(GetPos(), TIssuesIds::YQL_RANK_WITHOUT_ORDER_BY) <<
- OpName_ << "() is used with unordered window - all rows will be considered equal to each other";
+ if (!ctx.Warning(GetPos(), TIssuesIds::YQL_RANK_WITHOUT_ORDER_BY, [&](auto& out) {
+ out << OpName_ << "() is used with unordered window - all rows will be considered equal to each other";
+ })) {
+ return false;
+ }
} else {
- ctx.Warning(GetPos(), TIssuesIds::YQL_RANK_WITHOUT_ORDER_BY) <<
- OpName_ << "(<expression>) is used with unordered window - the result is likely to be undefined";
+ if (!ctx.Warning(GetPos(), TIssuesIds::YQL_RANK_WITHOUT_ORDER_BY, [&](auto& out) {
+ out << OpName_ << "(<expression>) is used with unordered window - the result is likely to be undefined";
+ })) {
+ return false;
+ }
}
}
@@ -1873,8 +1879,11 @@ StringContentInternal(TContext& ctx, TPosition pos, const TString& input, EStrin
result.Type = NKikimr::NUdf::EDataSlot::Utf8;
} else {
if (ctx.Scoped->WarnUntypedStringLiterals) {
- ctx.Warning(pos, TIssuesIds::YQL_UNTYPED_STRING_LITERALS)
- << "Please add suffix u for Utf8 strings or s for arbitrary binary strings";
+ if (!ctx.Warning(pos, TIssuesIds::YQL_UNTYPED_STRING_LITERALS, [](auto& out) {
+ out << "Please add suffix u for Utf8 strings or s for arbitrary binary strings";
+ })) {
+ return {};
+ }
}
if (ctx.Scoped->UnicodeLiterals) {
@@ -2687,7 +2696,7 @@ TNodePtr BuildAccess(TPosition pos, const TVector<INode::TIdPart>& ids, bool isL
return new TAccessNode(pos, ids, isLookup);
}
-void WarnIfAliasFromSelectIsUsedInGroupBy(TContext& ctx, const TVector<TNodePtr>& selectTerms, const TVector<TNodePtr>& groupByTerms,
+bool WarnIfAliasFromSelectIsUsedInGroupBy(TContext& ctx, const TVector<TNodePtr>& selectTerms, const TVector<TNodePtr>& groupByTerms,
const TVector<TNodePtr>& groupByExprTerms)
{
THashMap<TString, TNodePtr> termsByLabel;
@@ -2718,9 +2727,10 @@ void WarnIfAliasFromSelectIsUsedInGroupBy(TContext& ctx, const TVector<TNodePtr>
}
if (termsByLabel.empty()) {
- return;
+ return true;
}
+ bool isError = false;
bool found = false;
auto visitor = [&](const INode& current) {
if (found) {
@@ -2736,10 +2746,17 @@ void WarnIfAliasFromSelectIsUsedInGroupBy(TContext& ctx, const TVector<TNodePtr>
auto it = termsByLabel.find(*columnName);
if (it != termsByLabel.end()) {
found = true;
- ctx.Warning(current.GetPos(), TIssuesIds::YQL_PROJECTION_ALIAS_IS_REFERENCED_IN_GROUP_BY)
- << "GROUP BY will aggregate by column `" << *columnName << "` instead of aggregating by SELECT expression with same alias";
- ctx.Warning(it->second->GetPos(), TIssuesIds::YQL_PROJECTION_ALIAS_IS_REFERENCED_IN_GROUP_BY)
- << "You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details";
+
+ ctx.Warning(current.GetPos(), TIssuesIds::YQL_PROJECTION_ALIAS_IS_REFERENCED_IN_GROUP_BY, [&](auto& out) {
+ out << "GROUP BY will aggregate by column `" << *columnName
+ << "` instead of aggregating by SELECT expression with same alias";
+ });
+
+ isError = isError || !ctx.Warning(it->second->GetPos(), TIssuesIds::YQL_PROJECTION_ALIAS_IS_REFERENCED_IN_GROUP_BY, [](auto& out) {
+ out << "You should probably use alias in GROUP BY instead of using it here. "
+ << "Please consult documentation for more details";
+ });
+
return false;
}
}
@@ -2769,10 +2786,14 @@ void WarnIfAliasFromSelectIsUsedInGroupBy(TContext& ctx, const TVector<TNodePtr>
for (auto& groupByTerm : originalGroupBy) {
groupByTerm->VisitTree(visitor);
+ if (isError) {
+ return false;
+ }
if (found) {
- return;
+ return true;
}
}
+ return true;
}
bool ValidateAllNodesForAggregation(TContext& ctx, const TVector<TNodePtr>& nodes) {
@@ -3201,9 +3222,13 @@ TNodePtr BuildBinaryOp(TContext& ctx, TPosition pos, const TString& opName, TNod
const bool oneArgNull = a->IsNull() || b->IsNull();
if (bothArgNull || (oneArgNull && opName != "Or" && opName != "And")) {
- ctx.Warning(pos, TIssuesIds::YQL_OPERATION_WILL_RETURN_NULL) << "Binary operation "
- << opName.substr(0, opName.size() - 7 * opName.EndsWith("MayWarn"))
- << " will return NULL here";
+ if (!ctx.Warning(pos, TIssuesIds::YQL_OPERATION_WILL_RETURN_NULL, [&](auto& out) {
+ out << "Binary operation "
+ << opName.substr(0, opName.size() - 7 * opName.EndsWith("MayWarn"))
+ << " will return NULL here";
+ })) {
+ return nullptr;
+ }
}
}
diff --git a/yql/essentials/sql/v1/node.h b/yql/essentials/sql/v1/node.h
index 3d0b79f18aa..7ebc7c1e250 100644
--- a/yql/essentials/sql/v1/node.h
+++ b/yql/essentials/sql/v1/node.h
@@ -820,7 +820,7 @@ namespace NSQLTranslationV1 {
TWinSpecs CloneContainer(const TWinSpecs& specs);
- void WarnIfAliasFromSelectIsUsedInGroupBy(TContext& ctx, const TVector<TNodePtr>& selectTerms, const TVector<TNodePtr>& groupByTerms,
+ bool WarnIfAliasFromSelectIsUsedInGroupBy(TContext& ctx, const TVector<TNodePtr>& selectTerms, const TVector<TNodePtr>& groupByTerms,
const TVector<TNodePtr>& groupByExprTerms);
bool ValidateAllNodesForAggregation(TContext& ctx, const TVector<TNodePtr>& nodes);
diff --git a/yql/essentials/sql/v1/query.cpp b/yql/essentials/sql/v1/query.cpp
index ab863cc32ff..6d4b7617454 100644
--- a/yql/essentials/sql/v1/query.cpp
+++ b/yql/essentials/sql/v1/query.cpp
@@ -584,7 +584,12 @@ public:
if (func.StartsWith("regexp")) {
if (!ctx.PragmaRegexUseRe2) {
- ctx.Warning(Pos_, TIssuesIds::CORE_LEGACY_REGEX_ENGINE) << "Legacy regex engine works incorrectly with unicode. Use PRAGMA RegexUseRe2='true';";
+ if (!ctx.Warning(Pos_, TIssuesIds::CORE_LEGACY_REGEX_ENGINE, [&](auto& out) {
+ out << "Legacy regex engine works incorrectly with unicode. "
+ << "Use PRAGMA RegexUseRe2='true';";
+ })) {
+ return nullptr;
+ }
}
auto pattern = Args_[1].Id;
@@ -742,8 +747,12 @@ public:
postHandler = arg.Expr;
}
else {
- ctx.Warning(Pos_, DEFAULT_ERROR) << "Unsupported named argument: "
- << label << " in " << Func_;
+ if (!ctx.Warning(Pos_, DEFAULT_ERROR, [&](auto& out) {
+ out << "Unsupported named argument: "
+ << label << " in " << Func_;
+ })) {
+ return nullptr;
+ }
}
}
if (rootAttributes == nullptr) {
diff --git a/yql/essentials/sql/v1/select.cpp b/yql/essentials/sql/v1/select.cpp
index c75f18df30a..f20668ddbc6 100644
--- a/yql/essentials/sql/v1/select.cpp
+++ b/yql/essentials/sql/v1/select.cpp
@@ -1689,8 +1689,12 @@ public:
"core",
BuildLambda(Pos_, Y("row"), Y("Coalesce", Having_, Y("Bool", Q("false"))))
);
- ctx.Warning(Having_->GetPos(), TIssuesIds::YQL_HAVING_WITHOUT_AGGREGATION_IN_SELECT_DISTINCT)
- << "The usage of HAVING without aggregations with SELECT DISTINCT is non-standard and will stop working soon. Please use WHERE instead.";
+ if (!ctx.Warning(Having_->GetPos(), TIssuesIds::YQL_HAVING_WITHOUT_AGGREGATION_IN_SELECT_DISTINCT, [](auto& out) {
+ out << "The usage of HAVING without aggregations with SELECT DISTINCT is "
+ << "non-standard and will stop working soon. Please use WHERE instead.";
+ })) {
+ return false;
+ }
} else {
ctx.Error(Having_->GetPos()) << "HAVING with meaning GROUP BY () should be with aggregation function.";
return false;
@@ -2009,8 +2013,11 @@ private:
label = Columns_.AddUnnamed();
hasName = false;
if (ctx.WarnUnnamedColumns) {
- ctx.Warning(term->GetPos(), TIssuesIds::YQL_UNNAMED_COLUMN)
- << "Autogenerated column name " << label << " will be used for expression";
+ if (!ctx.Warning(term->GetPos(), TIssuesIds::YQL_UNNAMED_COLUMN, [&](auto& out) {
+ out << "Autogenerated column name " << label << " will be used for expression";
+ })) {
+ return false;
+ }
}
}
}
@@ -2063,7 +2070,9 @@ private:
hasError = true;
}
if (!src->IsCompositeSource() && !Columns_.All && src->HasAggregations()) {
- WarnIfAliasFromSelectIsUsedInGroupBy(ctx, Terms_, GroupBy_, GroupByExpr_);
+ if (!WarnIfAliasFromSelectIsUsedInGroupBy(ctx, Terms_, GroupBy_, GroupByExpr_)) {
+ hasError = true;
+ }
/// verify select aggregation compatibility
TVector<TNodePtr> exprs(Terms_);
@@ -3039,7 +3048,11 @@ public:
if (IgnoreSort()) {
Source_->DisableSort();
- ctx.Warning(Source_->GetPos(), TIssuesIds::YQL_ORDER_BY_WITHOUT_LIMIT_IN_SUBQUERY) << "ORDER BY without LIMIT in subquery will be ignored";
+ if (!ctx.Warning(Source_->GetPos(), TIssuesIds::YQL_ORDER_BY_WITHOUT_LIMIT_IN_SUBQUERY, [](auto& out) {
+ out << "ORDER BY without LIMIT in subquery will be ignored";
+ })) {
+ return false;
+ }
}
if (!Source_->Init(ctx, src)) {
@@ -3052,7 +3065,12 @@ public:
return false;
}
if (SkipTake_->HasSkip() && Source_->GetOrderKind() != EOrderKind::Sort && Source_->GetOrderKind() != EOrderKind::Assume) {
- ctx.Warning(Source_->GetPos(), TIssuesIds::YQL_OFFSET_WITHOUT_SORT) << "LIMIT with OFFSET without [ASSUME] ORDER BY may provide different results from run to run";
+ if (!ctx.Warning(Source_->GetPos(), TIssuesIds::YQL_OFFSET_WITHOUT_SORT, [](auto& out) {
+ out << "LIMIT with OFFSET without [ASSUME] ORDER BY may provide "
+ << "different results from run to run";
+ })) {
+ return false;
+ }
}
}
diff --git a/yql/essentials/sql/v1/sql_expression.cpp b/yql/essentials/sql/v1/sql_expression.cpp
index bceda17f2eb..9876371f27d 100644
--- a/yql/essentials/sql/v1/sql_expression.cpp
+++ b/yql/essentials/sql/v1/sql_expression.cpp
@@ -1233,7 +1233,9 @@ TNodePtr TSqlExpression::LambdaRule(const TRule_lambda& rule) {
TVector<TString> argNames;
for (const auto& arg : args) {
argNames.push_back(arg.Name);
- PopNamedNode(arg.Name);
+ if (!PopNamedNode(arg.Name)) {
+ return {};
+ }
}
if (!ret) {
return {};
@@ -1659,7 +1661,9 @@ bool TSqlExpression::SqlLambdaExprBody(TContext& ctx, const TRule_lambda_body& n
}
for (const auto& name : localNames) {
- PopNamedNode(name);
+ if (!PopNamedNode(name)) {
+ return false;
+ }
}
if (!nodeExpr) {
@@ -1903,7 +1907,12 @@ TNodePtr TSqlExpression::SubExpr(const TRule_xor_subexpr& node, const TTrailingQ
}
if (!Ctx_.PragmaRegexUseRe2) {
- Ctx_.Warning(pos, TIssuesIds::CORE_LEGACY_REGEX_ENGINE) << "Legacy regex engine works incorrectly with unicode. Use PRAGMA RegexUseRe2='true';";
+ if (!Ctx_.Warning(pos, TIssuesIds::CORE_LEGACY_REGEX_ENGINE, [](auto& out) {
+ out << "Legacy regex engine works incorrectly with unicode. "
+ << "Use PRAGMA RegexUseRe2='true';";
+ })) {
+ return nullptr;
+ }
}
const auto& matcher = Ctx_.PragmaRegexUseRe2 ?
@@ -1957,7 +1966,11 @@ TNodePtr TSqlExpression::SubExpr(const TRule_xor_subexpr& node, const TTrailingQ
if (altCase == TRule_cond_expr::TAlt3::TBlock1::kAlt4 &&
!cond.GetAlt_cond_expr3().GetBlock1().GetAlt4().HasBlock1())
{
- Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_MISSING_IS_BEFORE_NOT_NULL) << "Missing IS keyword before NOT NULL";
+ if (!Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_MISSING_IS_BEFORE_NOT_NULL, [](auto& out) {
+ out << "Missing IS keyword before NOT NULL";
+ })) {
+ return {};
+ }
}
auto isNull = BuildIsNullOp(pos, res);
@@ -1978,8 +1991,11 @@ TNodePtr TSqlExpression::SubExpr(const TRule_xor_subexpr& node, const TTrailingQ
const bool oneArgNull = left->IsNull() || right->IsNull();
if (res->IsNull() || bothArgNull || (symmetric && oneArgNull)) {
- Ctx_.Warning(pos, TIssuesIds::YQL_OPERATION_WILL_RETURN_NULL)
- << "BETWEEN operation will return NULL here";
+ if (!Ctx_.Warning(pos, TIssuesIds::YQL_OPERATION_WILL_RETURN_NULL, [](auto& out) {
+ out << "BETWEEN operation will return NULL here";
+ })) {
+ return {};
+ }
}
auto buildSubexpr = [&](const TNodePtr& left, const TNodePtr& right) {
diff --git a/yql/essentials/sql/v1/sql_query.cpp b/yql/essentials/sql/v1/sql_query.cpp
index b84e2df0add..5f29be58d4d 100644
--- a/yql/essentials/sql/v1/sql_query.cpp
+++ b/yql/essentials/sql/v1/sql_query.cpp
@@ -2157,7 +2157,11 @@ bool TSqlQuery::DeclareStatement(const TRule_declare_stmt& stmt) {
}
if (Ctx_.IsAlreadyDeclared(varName)) {
- Ctx_.Warning(varPos, TIssuesIds::YQL_DUPLICATE_DECLARE) << "Duplicate declaration of '" << varName << "' will be ignored";
+ if (!Ctx_.Warning(varPos, TIssuesIds::YQL_DUPLICATE_DECLARE, [&](auto& out) {
+ out << "Duplicate declaration of '" << varName << "' will be ignored";
+ })) {
+ return false;
+ }
} else {
PushNamedAtom(varPos, varName);
Ctx_.DeclareVariable(varName, varPos, typeNode);
@@ -3111,7 +3115,11 @@ THashMap<TString, TPragmaDescr> PragmaDescrs{
query.Error() << "Expected string literal as a single argument for: " << pragma;
return {};
}
- ctx.Warning(ctx.Pos(), TIssuesIds::YQL_PRAGMA_WARNING_MSG) << *values[0].GetLiteral();
+ if (!ctx.Warning(ctx.Pos(), TIssuesIds::YQL_PRAGMA_WARNING_MSG, [&](auto& out) {
+ out << *values[0].GetLiteral();
+ })) {
+ return {};
+ }
return TNodePtr{};
}),
TableElemExt("ErrorMsg", [](CB_SIG) -> TMaybe<TNodePtr> {
@@ -3141,8 +3149,11 @@ THashMap<TString, TPragmaDescr> PragmaDescrs{
}),
TableElemExt("DisableUnordered", [](CB_SIG) -> TMaybe<TNodePtr> {
auto& ctx = query.Context();
- ctx.Warning(ctx.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA)
- << "Use of deprecated DisableUnordered pragma. It will be dropped soon";
+ if (!ctx.Warning(ctx.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA, [](auto& out) {
+ out << "Use of deprecated DisableUnordered pragma. It will be dropped soon";
+ })) {
+ return {};
+ }
return TNodePtr{};
}),
TableElemExt("RotateJoinTree", [](CB_SIG) -> TMaybe<TNodePtr> {
@@ -3253,9 +3264,12 @@ THashMap<TString, TPragmaDescr> PragmaDescrs{
}),
TableElemExt("DisableFlexibleTypes", [](CB_SIG) -> TMaybe<TNodePtr> {
auto& ctx = query.Context();
- ctx.Warning(ctx.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA)
- << "Deprecated pragma DisableFlexibleTypes - it will be removed soon. "
- "Consider submitting bug report if FlexibleTypes doesn't work for you";
+ if (!ctx.Warning(ctx.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA, [](auto& out) {
+ out << "Deprecated pragma DisableFlexibleTypes - it will be removed soon. "
+ << "Consider submitting bug report if FlexibleTypes doesn't work for you";
+ })) {
+ return {};
+ }
ctx.FlexibleTypes = false;
return TNodePtr{};
}),
@@ -3287,9 +3301,12 @@ THashMap<TString, TPragmaDescr> PragmaDescrs{
}),
TableElemExt("DisableCompactNamedExprs", [](CB_SIG) -> TMaybe<TNodePtr> {
auto& ctx = query.Context();
- ctx.Warning(ctx.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA)
- << "Deprecated pragma DisableCompactNamedExprs - it will be removed soon. "
- "Consider submitting bug report if CompactNamedExprs doesn't work for you";
+ if (!ctx.Warning(ctx.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA, [](auto& out) {
+ out << "Deprecated pragma DisableCompactNamedExprs - it will be removed soon. "
+ << "Consider submitting bug report if CompactNamedExprs doesn't work for you";
+ })) {
+ return {};
+ }
ctx.CompactNamedExprs = false;
return TNodePtr{};
}),
@@ -3536,8 +3553,11 @@ TMaybe<TNodePtr> TSqlQuery::PragmaStatement(const TRule_pragma_stmt& stmt) {
return {};
}
if (normalizedPragma == "fast") {
- Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA)
- << "Use of deprecated yson.Fast pragma. It will be dropped soon";
+ if (!Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_DEPRECATED_PRAGMA, [](auto& out) {
+ out << "Use of deprecated yson.Fast pragma. It will be dropped soon";
+ })) {
+ return {};
+ }
return TNodePtr{};
} else if (normalizedPragma == "autoconvert") {
Ctx_.PragmaYsonAutoConvert = true;
@@ -3899,7 +3919,9 @@ TNodePtr TSqlQuery::Build(const TSQLv1ParserAST& ast) {
}
auto result = BuildQuery(Ctx_.Pos(), blocks, true, Ctx_.Scoped, Ctx_.SeqMode);
- WarnUnusedNodes();
+ if (!WarnUnusedNodes()) {
+ return nullptr;
+ }
return result;
}
diff --git a/yql/essentials/sql/v1/sql_select.cpp b/yql/essentials/sql/v1/sql_select.cpp
index 3dd5043438d..acfc83ae293 100644
--- a/yql/essentials/sql/v1/sql_select.cpp
+++ b/yql/essentials/sql/v1/sql_select.cpp
@@ -38,7 +38,11 @@ bool CollectJoinLinkSettings(TPosition pos, TJoinLinkSettings& linkSettings, TCo
linkSettings.Compact = true;
continue;
} else {
- ctx.Warning(hint.Pos, TIssuesIds::YQL_UNUSED_HINT) << "Unsupported join hint: " << hint.Name;
+ if (!ctx.Warning(hint.Pos, TIssuesIds::YQL_UNUSED_HINT, [&](auto& out) {
+ out << "Unsupported join hint: " << hint.Name;
+ })) {
+ return false;
+ }
}
if (TJoinLinkSettings::EStrategy::Default == linkSettings.Strategy) {
@@ -159,7 +163,11 @@ bool TSqlSelect::JoinOp(ISource* join, const TRule_join_source::TBlock3& block,
}
joinOp = NormalizeJoinOp(joinOp);
if (linkSettings.Strategy != TJoinLinkSettings::EStrategy::Default && joinOp == "Cross") {
- Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_UNUSED_HINT) << "Non-default join strategy will not be used for CROSS JOIN";
+ if (!Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_UNUSED_HINT, [](auto& out) {
+ out << "Non-default join strategy will not be used for CROSS JOIN";
+ })) {
+ return false;
+ }
linkSettings.Strategy = TJoinLinkSettings::EStrategy::Default;
}
@@ -999,7 +1007,11 @@ TSourcePtr TSqlSelect::SelectCore(const TRule_select_core& node, const TWriteSet
uniqueSets.insert_unique(NSorted::TSimpleSet<TString>(hint.Values.cbegin(), hint.Values.cend()));
distinctSets.insert_unique(NSorted::TSimpleSet<TString>(hint.Values.cbegin(), hint.Values.cend()));
} else {
- Ctx_.Warning(hint.Pos, TIssuesIds::YQL_UNUSED_HINT) << "Hint " << hint.Name << " will not be used";
+ if (!Ctx_.Warning(hint.Pos, TIssuesIds::YQL_UNUSED_HINT, [&](auto& out) {
+ out << "Hint " << hint.Name << " will not be used";
+ })) {
+ return nullptr;
+ }
}
}
@@ -1395,11 +1407,14 @@ TSourcePtr TSqlSelect::BuildStmt(const TRule& node, TPosition& pos) {
if (assumeOrderBy) {
YQL_ENSURE(!orderBy.empty());
- Ctx_.Warning(orderBy[0]->OrderExpr->GetPos(), TIssuesIds::WARNING)
- << "ASSUME ORDER BY is used, "
- << "but UNION, INTERSECT and EXCEPT "
- << "operators have no ordering guarantees, "
- << "therefore consider using ORDER BY";
+ if (!Ctx_.Warning(orderBy[0]->OrderExpr->GetPos(), TIssuesIds::WARNING, [](auto& out) {
+ out << "ASSUME ORDER BY is used, "
+ << "but UNION, INTERSECT and EXCEPT "
+ << "operators have no ordering guarantees, "
+ << "therefore consider using ORDER BY";
+ })) {
+ return nullptr;
+ }
}
if (orderBy) {
diff --git a/yql/essentials/sql/v1/sql_translation.cpp b/yql/essentials/sql/v1/sql_translation.cpp
index 7d1dc51c20f..e3ff7464795 100644
--- a/yql/essentials/sql/v1/sql_translation.cpp
+++ b/yql/essentials/sql/v1/sql_translation.cpp
@@ -1216,7 +1216,12 @@ bool TSqlTranslation::ClusterExpr(const TRule_cluster_expr& node, bool allowWild
isBinding = true;
break;
case NSQLTranslation::EBindingsMode::DROP_WITH_WARNING:
- Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_DEPRECATED_BINDINGS) << "Please remove 'bindings.' from your query, the support for this syntax will be dropped soon";
+ if (!Ctx_.Warning(Ctx_.Pos(), TIssuesIds::YQL_DEPRECATED_BINDINGS, [](auto& out) {
+ out << "Please remove 'bindings.' from your query, "
+ << "the support for this syntax will be dropped soon";
+ })) {
+ return false;
+ }
Ctx_.IncrementMonCounter("sql_errors", "DeprecatedBinding");
[[fallthrough]];
case NSQLTranslation::EBindingsMode::DROP:
@@ -3537,8 +3542,12 @@ bool TSqlTranslation::TableHintImpl(const TRule_table_hint& rule, TTableHints& h
auto pos = Ctx_.Pos();
if (!altCurrent && !warn) {
- Ctx_.Warning(pos, TIssuesIds::YQL_DEPRECATED_POSITIONAL_SCHEMA)
- << "Deprecated syntax for positional schema: please use 'column type' instead of 'type AS column'";
+ if (!Ctx_.Warning(pos, TIssuesIds::YQL_DEPRECATED_POSITIONAL_SCHEMA, [](auto& out) {
+ out << "Deprecated syntax for positional schema: "
+ << "please use 'column type' instead of 'type AS column'";
+ })) {
+ return false;
+ }
warn = true;
}
@@ -4472,7 +4481,11 @@ bool TSqlTranslation::IsValidFrameSettings(TContext& ctx, const TFrameSpecificat
if (*beginValue > *endValue) {
YQL_ENSURE(begin.Bound);
- ctx.Warning(begin.Bound->GetPos(), TIssuesIds::YQL_EMPTY_WINDOW_FRAME) << "Used frame specification implies empty window frame";
+ if (!ctx.Warning(begin.Bound->GetPos(), TIssuesIds::YQL_EMPTY_WINDOW_FRAME, [](auto& out) {
+ out << "Used frame specification implies empty window frame";
+ })) {
+ return false;
+ }
}
}
@@ -4779,7 +4792,9 @@ TNodePtr TSqlTranslation::DoStatement(const TRule_do_stmt& stmt, bool makeLambda
const bool hasValidBody = DefineActionOrSubqueryBody(query, innerBlocks, body);
auto ret = hasValidBody ? BuildQuery(Ctx_.Pos(), innerBlocks, false, Ctx_.Scoped, Ctx_.SeqMode) : nullptr;
- WarnUnusedNodes();
+ if (!WarnUnusedNodes()) {
+ return nullptr;
+ }
Ctx_.ScopeLevel--;
Ctx_.Scoped = saveScoped;
@@ -4894,7 +4909,9 @@ bool TSqlTranslation::DefineActionOrSubqueryStatement(const TRule_define_action_
}
auto ret = hasValidBody ? BuildQuery(Ctx_.Pos(), innerBlocks, false, Ctx_.Scoped, Ctx_.SeqMode) : nullptr;
- WarnUnusedNodes();
+ if (!WarnUnusedNodes()) {
+ return false;
+ }
Ctx_.Scoped = saveScoped;
Ctx_.ScopeLevel--;
Ctx_.Settings.Mode = saveMode;
@@ -4975,7 +4992,10 @@ TNodePtr TSqlTranslation::ForStatement(const TRule_for_stmt& stmt) {
--Ctx_.ParallelModeCount;
}
- PopNamedNode(itemArgName);
+ if (!PopNamedNode(itemArgName)) {
+ return {};
+ }
+
if (!bodyNode) {
return{};
}
@@ -5646,7 +5666,9 @@ bool TSqlTranslation::ParseStreamingQueryDefinition(const TRule_streaming_query_
const auto& inlineAction = node.GetRule_inline_action3();
const bool hasValidBody = DefineActionOrSubqueryBody(query, innerBlocks, inlineAction.GetRule_define_action_or_subquery_body2());
auto queryNode = hasValidBody ? BuildQuery(Ctx_.Pos(), innerBlocks, false, Ctx_.Scoped, Ctx_.SeqMode) : nullptr;
- WarnUnusedNodes();
+ if (!WarnUnusedNodes()) {
+ return false;
+ }
Ctx_.ScopeLevel--;
Ctx_.Scoped = saveScoped;
diff --git a/yql/essentials/sql/v1/sql_ut_common.h b/yql/essentials/sql/v1/sql_ut_common.h
index a47b22aa0bc..d961a33ea6c 100644
--- a/yql/essentials/sql/v1/sql_ut_common.h
+++ b/yql/essentials/sql/v1/sql_ut_common.h
@@ -4328,6 +4328,39 @@ Y_UNIT_TEST_SUITE(SqlToYQLErrors) {
"<main>:1:10: Warning: You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details, code: 4532\n");
}
+ Y_UNIT_TEST(WarnForAggregationBySelectAliasAsError) {
+ NSQLTranslation::TTranslationSettings settings;
+
+ NYql::TAstParseResult res = SqlToYqlWithSettings(R"sql(
+ PRAGMA Warning("error", "*");
+ SELECT c + 1 AS c
+ FROM plato.Input
+ GROUP BY c;
+ )sql", settings);
+
+ UNIT_ASSERT_C(res.IsOk(), res.Issues.ToString());
+ UNIT_ASSERT_NO_DIFF(Err2Str(res),
+ "<main>:5:22: Error: GROUP BY will aggregate by column `c` instead of aggregating by SELECT expression with same alias, code: 4532\n"
+ "<main>:3:22: Error: You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details, code: 4532\n");
+ }
+
+ Y_UNIT_TEST(WarnForAggregationBySelectAliasAsErrorStrict) {
+ NSQLTranslation::TTranslationSettings settings;
+ settings.Flags.emplace("StrictWarningAsError");
+
+ NYql::TAstParseResult res = SqlToYqlWithSettings(R"sql(
+ PRAGMA Warning("error", "*");
+ SELECT c + 1 AS c
+ FROM plato.Input
+ GROUP BY c;
+ )sql", settings);
+
+ UNIT_ASSERT_C(!res.IsOk(), res.Issues.ToString());
+ UNIT_ASSERT_NO_DIFF(Err2Str(res),
+ "<main>:5:22: Error: GROUP BY will aggregate by column `c` instead of aggregating by SELECT expression with same alias, code: 4532\n"
+ "<main>:3:22: Error: You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details, code: 4532\n");
+ }
+
Y_UNIT_TEST(NoWarnForAggregationBySelectAliasWhenAggrFunctionsAreUsedInAlias) {
NYql::TAstParseResult res = SqlToYql("select\n"
" cast(avg(val) as int) as value,\n"
@@ -5873,6 +5906,23 @@ select FormatType($f());
UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:23: Warning: Hint foo will not be used, code: 4534\n");
}
+ Y_UNIT_TEST(WarnForUnusedSqlHintAsError) {
+ NSQLTranslation::TTranslationSettings settings;
+
+ TString query = R"sql(
+ pragma warning("error", "*");
+
+ select * from plato.Input1 as a
+ join /*+ merge() */ plato.Input2 as b using(key);
+ select --+ foo(bar)
+ 1;
+ )sql";
+
+ NYql::TAstParseResult res = SqlToYqlWithSettings(query, settings);
+ UNIT_ASSERT_C(!res.IsOk(), res.Issues.ToString());
+ UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:6:35: Error: Hint foo will not be used, code: 4534\n");
+ }
+
Y_UNIT_TEST(WarnForDeprecatedSchema) {
NSQLTranslation::TTranslationSettings settings;
settings.ClusterMapping["s3bucket"] = NYql::S3ProviderName;
diff --git a/yql/essentials/sql/v1/sql_values.cpp b/yql/essentials/sql/v1/sql_values.cpp
index 2375fa6ec91..83608995c50 100644
--- a/yql/essentials/sql/v1/sql_values.cpp
+++ b/yql/essentials/sql/v1/sql_values.cpp
@@ -28,8 +28,12 @@ TSourcePtr TSqlValues::Build(const TRule_values_stmt& node, TPosition& valuesPos
auto columns = derivedColumns;
if (Ctx_.WarnUnnamedColumns && columns.size() < columnsCount) {
- Ctx_.Warning(valuesPos, TIssuesIds::YQL_UNNAMED_COLUMN)
- << "Autogenerated column names column" << columns.size() << "...column" << columnsCount - 1 << " will be used here";
+ if (!Ctx_.Warning(valuesPos, TIssuesIds::YQL_UNNAMED_COLUMN, [&](auto& out) {
+ out << "Autogenerated column names column" << columns.size()
+ << "...column" << columnsCount - 1 << " will be used here";
+ })) {
+ return nullptr;
+ }
}
while (columns.size() < columnsCount) {