diff options
Diffstat (limited to 'yql/essentials/sql/v1/query.cpp')
| -rw-r--r-- | yql/essentials/sql/v1/query.cpp | 109 |
1 files changed, 94 insertions, 15 deletions
diff --git a/yql/essentials/sql/v1/query.cpp b/yql/essentials/sql/v1/query.cpp index 22fc6e7b9cf..6ec40c25ce5 100644 --- a/yql/essentials/sql/v1/query.cpp +++ b/yql/essentials/sql/v1/query.cpp @@ -27,6 +27,26 @@ bool ValidateView(TPosition pos, TContext& ctx, TStringBuf service, TViewDescrip return true; } +namespace { + +bool ValidateColumnIsDefined(TContext& ctx, const TIdentifier& column, const THashSet<TString>& definedColumns, bool allowUndefinedColumns) { + if (!allowUndefinedColumns && !definedColumns.contains(column.Name)) { + ctx.Error(column.Pos) << "Undefined column: " << column.Name; + return false; + } + return true; +} + +bool ValidateNameIsUnique(TContext& ctx, THashSet<TString>& seenNames, const TIdentifier& name, TStringBuf entityKind) { + if (!seenNames.insert(name.Name).second) { + ctx.Error(name.Pos) << entityKind << " " << name.Name << " must be defined once"; + return false; + } + return true; +} + +} // anonymous namespace + class TUniqueTableKey: public ITableKeys { public: TUniqueTableKey(TPosition pos, TString service, TDeferredAtom cluster, @@ -377,6 +397,23 @@ INode::TPtr CreateAlterIndex(const TIndexDescription& index, const INode& node) return alterIndexNode; } +INode::TPtr CreateStatisticsDesc(const TStatisticsDescription& statistics, const INode& node) { + auto statisticsColumns = node.Y(); + for (const auto& col : statistics.Columns) { + statisticsColumns = node.L(statisticsColumns, BuildQuotedAtom(col.Pos, col.Name)); + } + auto statisticsTypes = node.Y(); + for (const auto& type : statistics.Types) { + statisticsTypes = node.L(statisticsTypes, BuildQuotedAtom(type.Pos, type.Name)); + } + const auto& statisticsName = node.Y(node.Q("statisticsName"), BuildQuotedAtom(statistics.Name.Pos, statistics.Name.Name)); + auto statisticsNode = node.Y( + node.Q(statisticsName), + node.Q(node.Y(node.Q("statisticsColumns"), node.Q(statisticsColumns))), + node.Q(node.Y(node.Q("statisticsTypes"), node.Q(statisticsTypes)))); + return statisticsNode; +} + INode::TPtr CreateChangefeedDesc(const TChangefeedDescription& desc, const INode& node) { auto settings = node.Y(); if (desc.Settings.Mode) { @@ -1165,7 +1202,7 @@ public: return false; } - if (!Params_.PkColumns.empty() || !Params_.PartitionByColumns.empty() || !Params_.OrderByColumns.empty() || !Params_.Indexes.empty() || !Params_.Changefeeds.empty()) + if (!Params_.PkColumns.empty() || !Params_.PartitionByColumns.empty() || !Params_.OrderByColumns.empty() || !Params_.Indexes.empty() || !Params_.Statistics.empty() || !Params_.Changefeeds.empty()) { THashSet<TString> columnsSet; for (auto& col : Params_.Columns) { @@ -1176,8 +1213,7 @@ public: THashSet<TString> pkColumns; for (auto& keyColumn : Params_.PkColumns) { - if (!allowUndefinedColumns && !columnsSet.contains(keyColumn.Name)) { - ctx.Error(keyColumn.Pos) << "Undefined column: " << keyColumn.Name; + if (!ValidateColumnIsDefined(ctx, keyColumn, columnsSet, allowUndefinedColumns)) { return false; } if (!pkColumns.insert(keyColumn.Name).second) { @@ -1186,35 +1222,30 @@ public: } } for (auto& keyColumn : Params_.PartitionByColumns) { - if (!allowUndefinedColumns && !columnsSet.contains(keyColumn.Name)) { - ctx.Error(keyColumn.Pos) << "Undefined column: " << keyColumn.Name; + if (!ValidateColumnIsDefined(ctx, keyColumn, columnsSet, allowUndefinedColumns)) { return false; } } for (auto& keyColumn : Params_.OrderByColumns) { - if (!allowUndefinedColumns && !columnsSet.contains(keyColumn.first.Name)) { - ctx.Error(keyColumn.first.Pos) << "Undefined column: " << keyColumn.first.Name; + if (!ValidateColumnIsDefined(ctx, keyColumn.first, columnsSet, allowUndefinedColumns)) { return false; } } THashSet<TString> indexNames; for (const auto& index : Params_.Indexes) { - if (!indexNames.insert(index.Name.Name).second) { - ctx.Error(index.Name.Pos) << "Index " << index.Name.Name << " must be defined once"; + if (!ValidateNameIsUnique(ctx, indexNames, index.Name, "Index")) { return false; } for (const auto& indexColumn : index.IndexColumns) { - if (!allowUndefinedColumns && !columnsSet.contains(indexColumn.Name)) { - ctx.Error(indexColumn.Pos) << "Undefined column: " << indexColumn.Name; + if (!ValidateColumnIsDefined(ctx, indexColumn, columnsSet, allowUndefinedColumns)) { return false; } } for (const auto& dataColumn : index.DataColumns) { - if (!allowUndefinedColumns && !columnsSet.contains(dataColumn.Name)) { - ctx.Error(dataColumn.Pos) << "Undefined column: " << dataColumn.Name; + if (!ValidateColumnIsDefined(ctx, dataColumn, columnsSet, allowUndefinedColumns)) { return false; } } @@ -1222,10 +1253,29 @@ public: THashSet<TString> cfNames; for (const auto& cf : Params_.Changefeeds) { - if (!cfNames.insert(cf.Name.Name).second) { - ctx.Error(cf.Name.Pos) << "Changefeed " << cf.Name.Name << " must be defined once"; + if (!ValidateNameIsUnique(ctx, cfNames, cf.Name, "Changefeed")) { + return false; + } + } + + THashSet<TString> statisticsNames; + for (const auto& statistics : Params_.Statistics) { + if (!ValidateNameIsUnique(ctx, statisticsNames, statistics.Name, "Statistics")) { + return false; + } + + if (statistics.Columns.empty()) { + ctx.Error(statistics.Name.Pos) << "Statistics " << statistics.Name.Name << " must have at least one column"; return false; } + + for (const auto& statisticsColumn : statistics.Columns) { + if (!ValidateColumnIsDefined(ctx, statisticsColumn, columnsSet, allowUndefinedColumns)) { + return false; + } + } + + // statistics.Types may be empty: WITH is optional and its omission means "all supported statistic types" } } @@ -1399,6 +1449,11 @@ public: opts = L(opts, Q(Y(Q("index"), Q(desc)))); } + for (const auto& statistics : Params_.Statistics) { + const auto& desc = CreateStatisticsDesc(statistics, *this); + opts = L(opts, Q(Y(Q("statistics"), Q(desc)))); + } + for (const auto& cf : Params_.Changefeeds) { const auto& desc = CreateChangefeedDesc(cf, *this); opts = L(opts, Q(Y(Q("changefeed"), Q(desc)))); @@ -1856,6 +1911,30 @@ public: actions = L(actions, Q(Y(Q("dropIndex"), indexName))); } + { + THashSet<TString> statisticsNames; + for (const auto& statistics : Params_.AddStatistics) { + if (!ValidateNameIsUnique(ctx, statisticsNames, statistics.Name, "Statistics")) { + return false; + } + + if (statistics.Columns.empty()) { + ctx.Error(statistics.Name.Pos) << "Statistics " << statistics.Name.Name << " must have at least one column"; + return false; + } + + // statistics.Types may be empty: WITH is optional and its omission means "all supported statistic types" + + const auto& desc = CreateStatisticsDesc(statistics, *this); + actions = L(actions, Q(Y(Q("addStatistics"), Q(desc)))); + } + } + + for (const auto& id : Params_.DropStatistics) { + auto statisticsName = BuildQuotedAtom(id.Pos, id.Name); + actions = L(actions, Q(Y(Q("dropStatistics"), statisticsName))); + } + if (Params_.RenameIndexTo) { auto src = BuildQuotedAtom(Params_.RenameIndexTo->first.Pos, Params_.RenameIndexTo->first.Name); auto dst = BuildQuotedAtom(Params_.RenameIndexTo->second.Pos, Params_.RenameIndexTo->second.Name); |
