aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/sql/v1/sql_values.cpp
blob: c035489387fa88a7ac0a0fe171e264093a7bdf8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#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<TString>& derivedColumns, TPosition derivedColumnsPos) {
    Token(node.GetToken1());
    valuesPos = Ctx.Pos();

    TVector<TVector<TNodePtr>> 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<TNodePtr> labels;
    for (size_t i = 0; i < columnsCount; ++i) {
        labels.push_back(BuildQuotedAtom(derivedColumnsPos, columns[i]));
    }

    TVector<TNodePtr> 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<TVector<TNodePtr>>& rows) {
    rows = TVector<TVector<TNodePtr>> {{}};


    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<TNodePtr>& outRow) {
    TSqlExpression sqlExpr(Ctx, Mode);
    return ExprList(sqlExpr, outRow, inRow.GetRule_expr_list2());
}

TSourcePtr TSqlValues::ValuesSource(const TRule_values_source& node, const TVector<TString>& columnsHint,
    const TString& operationName)
{
    Ctx.IncrementMonCounter("sql_features", "ValuesSource");
    TPosition pos(Ctx.Pos());
    switch (node.Alt_case()) {
        case TRule_values_source::kAltValuesSource1: {
            TVector<TVector<TNodePtr>> 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<TString> 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