#include "sql_values.h" #include "sql_group_by.h" #include "sql_query.h" #include "sql_select.h" #include "sql_expression.h" #include "source.h" namespace NSQLTranslationV1 { using namespace NSQLv1Generated; TSourcePtr TSqlValues::Build(const TRule_values_stmt& node, TPosition& valuesPos, const TVector& derivedColumns, TPosition derivedColumnsPos) { Token(node.GetToken1()); valuesPos = Ctx.Pos(); TVector> rows; const auto& rowList = node.GetRule_values_source_row_list2(); if (!BuildRows(rowList, rows)) { return nullptr; } YQL_ENSURE(!rows.empty()); const size_t columnsCount = rows.back().size(); if (derivedColumns.size() > columnsCount) { Ctx.Error(derivedColumnsPos) << "Derived column list size exceeds column count in VALUES"; return nullptr; } 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"; } while (columns.size() < columnsCount) { columns.push_back(TStringBuilder() << "column" << columns.size()); } TVector labels; for (size_t i = 0; i < columnsCount; ++i) { labels.push_back(BuildQuotedAtom(derivedColumnsPos, columns[i])); } TVector items; for (auto& row : rows) { YQL_ENSURE(!row.empty()); YQL_ENSURE(row.size() == columnsCount); items.push_back(BuildOrderedStructure(row.front()->GetPos(), row, labels)); } auto list = new TCallNodeImpl(valuesPos, "AsListMayWarn", items); list = new TCallNodeImpl(valuesPos, "PersistableRepr", { list }); list = new TCallNodeImpl(valuesPos, "AssumeColumnOrder", { list, BuildTuple(valuesPos, labels) }); auto result = BuildNodeSource(valuesPos, list, false); result->AllColumns(); return result; } bool TSqlValues::BuildRows(const TRule_values_source_row_list& node, TVector>& rows) { rows = TVector> {{}}; if (!BuildRow(node.GetRule_values_source_row1(), rows.back())) { return false; } const size_t rowSize = rows.back().size(); for (const auto& valuesSourceRow: node.GetBlock2()) { rows.push_back({}); if (!BuildRow(valuesSourceRow.GetRule_values_source_row2(), rows.back())) { return false; } if (rows.back().size() != rowSize) { Token(valuesSourceRow.GetRule_values_source_row2().GetToken1()); Error() << "All VALUES items should have same size: expecting " << rowSize << ", got " << rows.back().size(); return false; } } return true; } bool TSqlValues::BuildRow(const TRule_values_source_row& inRow, TVector& outRow) { TSqlExpression sqlExpr(Ctx, Mode); return ExprList(sqlExpr, outRow, inRow.GetRule_expr_list2()); } TSourcePtr TSqlValues::ValuesSource(const TRule_values_source& node, const TVector& columnsHint, const TString& operationName) { Ctx.IncrementMonCounter("sql_features", "ValuesSource"); TPosition pos(Ctx.Pos()); switch (node.Alt_case()) { case TRule_values_source::kAltValuesSource1: { TVector> rows {{}}; const auto& rowList = node.GetAlt_values_source1().GetRule_values_stmt1().GetRule_values_source_row_list2(); if (!BuildRows(rowList, rows)) { return nullptr; } return BuildWriteValues(pos, operationName, columnsHint, rows); } case TRule_values_source::kAltValuesSource2: { TSqlSelect select(Ctx, Mode); TPosition selectPos; auto source = select.Build(node.GetAlt_values_source2().GetRule_select_stmt1(), selectPos); if (!source) { return nullptr; } return BuildWriteValues(pos, "UPDATE", columnsHint, std::move(source)); } default: Ctx.IncrementMonCounter("sql_errors", "UnknownValuesSource"); AltNotImplemented("values_source", node); return nullptr; } } TSourcePtr TSqlIntoValues::Build(const TRule_into_values_source& node, const TString& operationName) { switch (node.Alt_case()) { case TRule_into_values_source::kAltIntoValuesSource1: { auto alt = node.GetAlt_into_values_source1(); TVector columnsHint; if (alt.HasBlock1()) { PureColumnListStr(alt.GetBlock1().GetRule_pure_column_list1(), *this, columnsHint); } return ValuesSource(alt.GetRule_values_source2(), columnsHint, operationName); } default: Ctx.IncrementMonCounter("sql_errors", "DefaultValuesOrOther"); AltNotImplemented("into_values_source", node); return nullptr; } } TSourcePtr TSqlAsValues::Build(const TRule_values_source& node, const TString& operationName) { switch (node.Alt_case()) { case TRule_values_source::kAltValuesSource1: { Ctx.IncrementMonCounter("sql_errors", "UnknownValuesSource"); Error() << "AS VALUES statement is not supported for " << operationName << "."; return nullptr; } case TRule_values_source::kAltValuesSource2: { return ValuesSource(node, {}, operationName); } default: Ctx.IncrementMonCounter("sql_errors", "UnknownValuesSource"); AltNotImplemented("values_source", node); return nullptr; } } } // namespace NSQLTranslationV1