YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/ptree/pt_delete.cc
Line
Count
Source (jump to first uncovered line)
1
//--------------------------------------------------------------------------------------------------
2
// Copyright (c) YugaByte, Inc.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
// in compliance with the License.  You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software distributed under the License
10
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
// or implied.  See the License for the specific language governing permissions and limitations
12
// under the License.
13
//
14
//
15
// Treenode implementation for DELETE statements.
16
//--------------------------------------------------------------------------------------------------
17
18
#include "yb/yql/cql/ql/ptree/pt_delete.h"
19
20
#include "yb/common/common.pb.h"
21
22
#include "yb/gutil/casts.h"
23
24
#include "yb/yql/cql/ql/ptree/column_arg.h"
25
#include "yb/yql/cql/ql/ptree/column_desc.h"
26
#include "yb/yql/cql/ql/ptree/pt_dml_using_clause.h"
27
#include "yb/yql/cql/ql/ptree/pt_expr.h"
28
#include "yb/yql/cql/ql/ptree/sem_context.h"
29
#include "yb/yql/cql/ql/ptree/sem_state.h"
30
#include "yb/yql/cql/ql/ptree/yb_location.h"
31
32
namespace yb {
33
namespace ql {
34
35
//--------------------------------------------------------------------------------------------------
36
37
PTDeleteStmt::PTDeleteStmt(MemoryContext *memctx,
38
                           YBLocation::SharedPtr loc,
39
                           PTExprListNode::SharedPtr target,
40
                           PTTableRef::SharedPtr relation,
41
                           PTDmlUsingClausePtr using_clause,
42
                           PTExprPtr where_clause,
43
                           PTExprPtr if_clause,
44
                           const bool else_error,
45
                           const bool returns_status)
46
    : PTDmlStmt(memctx, loc, where_clause, if_clause, else_error, using_clause, returns_status),
47
      target_(target),
48
815
      relation_(relation) {
49
815
}
50
51
749
PTDeleteStmt::~PTDeleteStmt() {
52
749
}
53
54
810
CHECKED_STATUS PTDeleteStmt::Analyze(SemContext *sem_context) {
55
  // If use_cassandra_authentication is set, permissions are checked in PTDmlStmt::Analyze.
56
810
  RETURN_NOT_OK(PTDmlStmt::Analyze(sem_context));
57
58
810
  RETURN_NOT_OK(relation_->Analyze(sem_context));
59
60
  // Collect table's schema for semantic analysis.
61
810
  RETURN_NOT_OK(LookupTable(sem_context));
62
63
  // Analyze the target columns.
64
809
  if (target_) {
65
68
    column_args_->resize(num_columns());
66
68
    TreeNodePtrOperator<SemContext> analyze =
67
68
        std::bind(&PTDeleteStmt::AnalyzeTarget, this, std::placeholders::_1, std::placeholders::_2);
68
68
    RETURN_NOT_OK(target_->Analyze(sem_context, analyze));
69
68
  }
70
71
  // Analyze column args to set if primary and/or static row is modified.
72
803
  RETURN_NOT_OK(AnalyzeColumnArgs(sem_context));
73
74
  // Run error checking on the WHERE conditions.
75
803
  RETURN_NOT_OK(AnalyzeWhereClause(sem_context));
76
765
  bool range_key_missing = key_where_ops_.size() < num_key_columns();
77
78
  // If target columns are given, range key can be omitted only if all columns targeted for
79
  // deletions are static. Then we must also check there are no extra conditions on the range
80
  // columns (e.g. inequality conditions).
81
  // Otherwise, (if no target columns are given) range key can omitted (implying a range delete)
82
  // only if there is no 'IF' clause (not allowed for range deletes).
83
765
  if (target_) {
84
62
    if (range_key_missing) {
85
7
      if (!StaticColumnArgsOnly()) {
86
4
        return sem_context->Error(this,
87
4
            "DELETE statement must give the entire primary key if specifying non-static columns",
88
4
            ErrorCode::CQL_STATEMENT_INVALID);
89
4
      }
90
3
      if (!where_ops_.empty()) {
91
2
        return sem_context->Error(this,
92
2
            "DELETE statement cannot specify both target columns and range condition",
93
2
            ErrorCode::CQL_STATEMENT_INVALID);
94
2
      }
95
3
    }
96
703
  } else if (range_key_missing) {
97
26
    if (if_clause_ != nullptr) {
98
2
      return sem_context->Error(this,
99
2
          "DELETE statement must specify the entire primary key to use an IF clause",
100
2
          ErrorCode::CQL_STATEMENT_INVALID);
101
2
    }
102
    // This is a range delete, affecting an entire hash key.
103
24
    modifies_multiple_rows_ = true;
104
24
  }
105
106
  // Run error checking on the IF conditions.
107
757
  RETURN_NOT_OK(AnalyzeIfClause(sem_context));
108
109
  // Run error checking on USING clause.
110
754
  RETURN_NOT_OK(AnalyzeUsingClause(sem_context));
111
112
  // Analyze indexes for write operations.
113
754
  RETURN_NOT_OK(AnalyzeIndexesForWrites(sem_context));
114
115
754
  if (using_clause_ != nullptr && 
using_clause_->has_ttl_seconds()16
) {
116
    // Delete only supports TIMESTAMP as part of the using clause.
117
2
    return sem_context->Error(this, "DELETE statement cannot have TTL",
118
2
                              ErrorCode::CQL_STATEMENT_INVALID);
119
2
  }
120
121
  // If returning a status we always return back the whole row.
122
752
  if (returns_status_) {
123
5
    AddRefForAllColumns();
124
5
  }
125
126
752
  return Status::OK();
127
754
}
128
129
83
CHECKED_STATUS PTDeleteStmt::AnalyzeTarget(TreeNode *target, SemContext *sem_context) {
130
  // Walking through the target expressions and collect all columns. Currently, CQL doesn't allow
131
  // any expression except for references to table column.
132
83
  if (target->opcode() != TreeNodeOpcode::kPTRef) {
133
2
    return sem_context->Error(target, "Deleting expression is not allowed in CQL",
134
2
                              ErrorCode::CQL_STATEMENT_INVALID);
135
2
  }
136
137
81
  PTRef *ref = static_cast<PTRef *>(target);
138
139
81
  if (ref->name() == nullptr) { // This ref is pointing to the whole table (DELETE *)
140
0
    return sem_context->Error(target, "Deleting '*' is not allowed in this context",
141
0
                              ErrorCode::CQL_STATEMENT_INVALID);
142
81
  } else { // Add the column descriptor to column_args.
143
81
    SemState sem_state(sem_context);
144
81
    RETURN_NOT_OK(ref->Analyze(sem_context));
145
79
    const ColumnDesc *col_desc = ref->desc();
146
79
    if (col_desc->is_primary()) {
147
2
      return sem_context->Error(target, "Delete target cannot be part of primary key",
148
2
                                ErrorCode::INVALID_ARGUMENTS);
149
2
    }
150
151
    // Set rhs expr to nullptr, since it is delete.
152
77
    column_args_->at(col_desc->index()).Init(col_desc, nullptr);
153
77
  }
154
77
  return Status::OK();
155
81
}
156
157
0
void PTDeleteStmt::PrintSemanticAnalysisResult(SemContext *sem_context) {
158
0
  VLOG(3) << "SEMANTIC ANALYSIS RESULT (" << *loc_ << "):\n" << "Not yet avail";
159
0
}
160
161
2
ExplainPlanPB PTDeleteStmt::AnalysisResultToPB() {
162
2
  ExplainPlanPB explain_plan;
163
2
  DeletePlanPB *delete_plan = explain_plan.mutable_delete_plan();
164
2
  delete_plan->set_delete_type("Delete on " + table_name().ToString());
165
2
  if (modifies_multiple_rows_) {
166
2
    delete_plan->set_scan_type("  ->  Range Scan on " + table_name().ToString());
167
2
  } else {
168
0
    delete_plan->set_scan_type("  ->  Primary Key Lookup on " + table_name().ToString());
169
0
  }
170
2
  std::string key_conditions = "        Key Conditions: " + ConditionsToString(key_where_ops());
171
2
  delete_plan->set_key_conditions(key_conditions);
172
2
  if (!where_ops().empty()) {
173
1
    std::string filter = "        Filter: " + ConditionsToString(where_ops());
174
1
    delete_plan->set_filter(filter);
175
1
  }
176
2
  delete_plan->set_output_width(narrow_cast<int32_t>(max({
177
2
    delete_plan->delete_type().length(),
178
2
    delete_plan->scan_type().length(),
179
2
    delete_plan->key_conditions().length(),
180
2
    delete_plan->filter().length()
181
2
  })));
182
2
  return explain_plan;
183
2
}
184
185
}  // namespace ql
186
}  // namespace yb