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_column_definition.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
// Column Definition Tree node implementation.
16
//--------------------------------------------------------------------------------------------------
17
18
#include "yb/yql/cql/ql/ptree/pt_column_definition.h"
19
20
#include "yb/yql/cql/ql/ptree/column_desc.h"
21
#include "yb/yql/cql/ql/ptree/pt_create_index.h"
22
#include "yb/yql/cql/ql/ptree/pt_create_table.h"
23
#include "yb/yql/cql/ql/ptree/pt_expr.h"
24
#include "yb/yql/cql/ql/ptree/sem_context.h"
25
26
DEFINE_bool(cql_allow_static_column_index, false,
27
            "Raise unsupported error when creating an index on static columns");
28
29
namespace yb {
30
namespace ql {
31
32
PTColumnDefinition::PTColumnDefinition(MemoryContext *memctx,
33
                                       YBLocationPtr loc,
34
                                       const MCSharedPtr<MCString>& name,
35
                                       const PTBaseType::SharedPtr& datatype,
36
                                       const PTListNode::SharedPtr& qualifiers)
37
    : TreeNode(memctx, loc),
38
      name_(name),
39
      datatype_(datatype),
40
      qualifiers_(qualifiers),
41
      is_primary_key_(false),
42
      is_hash_key_(false),
43
      is_static_(false),
44
      order_(-1),
45
      sorting_type_(SortingType::kNotSpecified),
46
10.0k
      coldef_name_(*name) {
47
10.0k
}
48
49
9.25k
PTColumnDefinition::~PTColumnDefinition() {
50
9.25k
}
51
52
10.5k
CHECKED_STATUS PTColumnDefinition::Analyze(SemContext *sem_context) {
53
  // When creating INDEX, this node is not yet defined and processed.
54
10.5k
  if (!sem_context->processing_column_definition()) {
55
5.25k
    return Status::OK();
56
5.25k
  }
57
58
  // Save context state, and set "this" as current column in the context.
59
5.30k
  SymbolEntry cached_entry = *sem_context->current_processing_id();
60
5.30k
  sem_context->set_current_column(this);
61
62
  // Analyze column datatype.
63
5.30k
  RETURN_NOT_OK(datatype_->Analyze(sem_context));
64
65
  // Analyze column qualifiers (not null, primary key, ...).
66
5.28k
  RETURN_NOT_OK(sem_context->MapSymbol(*name_, this));
67
5.28k
  if (qualifiers_ != nullptr) {
68
304
    RETURN_NOT_OK(qualifiers_->Analyze(sem_context));
69
304
  }
70
71
  // Add the analyzed column to table.
72
5.28k
  PTCreateTable *table = sem_context->current_create_table_stmt();
73
5.28k
  RETURN_NOT_OK(table->AppendColumn(sem_context, this));
74
75
  // Restore the context value as we are done with this colummn.
76
5.28k
  sem_context->set_current_processing_id(cached_entry);
77
78
5.28k
  return Status::OK();
79
5.28k
}
80
81
1.92k
void PTColumnDefinition::AddIndexedRef(int32_t col_id) {
82
1.92k
  DCHECK(indexed_ref_ == -1 || indexed_ref_ == col_id)
83
0
    << "Indexed expression cannot reference more than one column";
84
1.92k
  indexed_ref_ = col_id;
85
1.92k
}
86
87
//--------------------------------------------------------------------------------------------------
88
89
PTIndexColumn::PTIndexColumn(MemoryContext *memctx,
90
                             YBLocationPtr loc,
91
                             const MCSharedPtr<MCString>& name,
92
                             const PTExpr::SharedPtr& colexpr)
93
4.72k
  : PTColumnDefinition(memctx, loc, name, nullptr, nullptr), colexpr_(colexpr) {
94
4.72k
  const string colname = colexpr->MangledName();
95
4.72k
  coldef_name_ = colname.c_str();
96
4.72k
}
97
98
4.39k
PTIndexColumn::~PTIndexColumn() {
99
4.39k
}
100
101
4.64k
CHECKED_STATUS PTIndexColumn::Analyze(SemContext *sem_context) {
102
  // Seek the table that is being created currently.
103
4.64k
  const PTCreateTable* table = sem_context->current_create_table_stmt();
104
105
  // Look for column definition of the given name.
106
4.64k
  coldef_ = sem_context->GetColumnDefinition(*name_);
107
108
4.64k
  if (table->opcode() == TreeNodeOpcode::kPTCreateTable) {
109
    // CREATE TABLE: this object is a column in PRIMARY KEY( index_columns ) clause.
110
2.72k
    if (!coldef_) {
111
0
      return sem_context->Error(this, "Column does not exist", ErrorCode::UNDEFINED_COLUMN);
112
0
    }
113
114
    // Check if this column has already been declared as PRIMARY previously.
115
2.72k
    if (coldef_->is_primary_key()) {
116
0
      return sem_context->Error(this, ErrorCode::DUPLICATE_COLUMN);
117
0
    }
118
119
    // Only allow column-ref to be used as PRIMARY KEY for a table.
120
2.72k
    if (colexpr_->opcode() != TreeNodeOpcode::kPTRef) {
121
0
      return sem_context->Error(colexpr_, "PRIMARY KEY element must be a column",
122
0
                                ErrorCode::SQL_STATEMENT_INVALID);
123
0
    }
124
125
2.72k
    return Status::OK();
126
2.72k
  }
127
128
  // CREATE INDEX statement processing.
129
1.92k
  if (coldef_) {
130
    // Error: Column is already included in the index.
131
5
    return sem_context->Error(this, ErrorCode::DUPLICATE_COLUMN);
132
5
  }
133
134
  // Analyze new column definition for expression such as column-ref or JSON attribute-ref.
135
  // Example for column ref.
136
  //   TABLE (a, b, c)
137
  //   INDEX (c)
138
  //   This column in the index-table is "defined" the same as the column in the data-table.
139
  // Example for JSON index
140
  //   TABLE (a, b, j)
141
  //   INDEX (j->>'b') -> INDEX is a table whose column 'j->>b' is referencing to TABLE(j)
142
1.92k
  SemState sem_state(sem_context);
143
1.92k
  sem_state.set_processing_index_column(this);
144
1.92k
  RETURN_NOT_OK(colexpr_->Analyze(sem_context));
145
1.92k
  sem_state.set_processing_index_column(nullptr);
146
147
  // Check if indexing expression is supported.
148
1.92k
  if (colexpr_->opcode() == TreeNodeOpcode::kPTRef) {
149
    // Transfer information from indexed_table::column_desc to this index::column_def.
150
1.88k
    const ColumnDesc *coldesc = sem_context->GetColumnDesc(*name_);
151
1.88k
    is_static_ = coldesc->is_static();
152
1.88k
    if(!FLAGS_cql_allow_static_column_index && 
is_static_1.88k
)
153
1
      return sem_context->Error(this, "Static columns cannot be indexed.",
154
1
                                ErrorCode::SQL_STATEMENT_INVALID);
155
156
1.88k
  } else 
if (33
colexpr_->opcode() != TreeNodeOpcode::kPTJsonOp33
) {
157
    // Currently only JSon refereence is allowed for indexing.
158
0
    return sem_context->Error(this, "Only columns and JSONB attributes can be used for indexing",
159
0
                              ErrorCode::SQL_STATEMENT_INVALID);
160
0
  }
161
162
  // For CREATE INDEX, column is not defined in this statement, so this node is used as definition.
163
1.91k
  coldef_ = this;
164
1.91k
  RETURN_NOT_OK(sem_context->MapSymbol(*name_, this));
165
166
1.91k
  return Status::OK();
167
1.91k
}
168
169
2.14k
CHECKED_STATUS PTIndexColumn::SetupPrimaryKey(SemContext *sem_context) {
170
2.14k
  RETURN_NOT_OK(Analyze(sem_context));
171
2.14k
  PTCreateTable* table = sem_context->current_create_table_stmt();
172
2.14k
  return table->AppendPrimaryColumn(sem_context, coldef_);
173
2.14k
}
174
175
1.26k
CHECKED_STATUS PTIndexColumn::SetupHashKey(SemContext *sem_context) {
176
1.26k
  RETURN_NOT_OK(Analyze(sem_context));
177
1.26k
  PTCreateTable* table = sem_context->current_create_table_stmt();
178
1.26k
  return table->AppendHashColumn(sem_context, coldef_);
179
1.26k
}
180
181
4.02k
std::shared_ptr<QLType> PTIndexColumn::ql_type() const {
182
4.02k
  return colexpr_->ql_type();
183
4.02k
}
184
185
175
CHECKED_STATUS PTIndexColumn::SetupCoveringIndexColumn(SemContext *sem_context) {
186
175
  coldef_ = sem_context->GetColumnDefinition(*name_);
187
175
  if (coldef_ && 
coldef_->colexpr()->opcode() == TreeNodeOpcode::kPTRef8
) {
188
    // Ignore as column is already defined as a part of INDEX.
189
7
    return Status::OK();
190
7
  }
191
192
  // Analyze column as it has not been included in the INDEX.
193
168
  RETURN_NOT_OK(Analyze(sem_context));
194
195
  // Not allow static columns.
196
167
  if (coldef_->is_static()) {
197
0
    return sem_context->Error(coldef_, "Static column not supported as a covering index column",
198
0
                              ErrorCode::SQL_STATEMENT_INVALID);
199
0
  }
200
201
  // Not allow expressions in INCLUDE.
202
167
  if (colexpr_->opcode() != TreeNodeOpcode::kPTRef) {
203
0
    return sem_context->Error(coldef_, "Only columns can be used for COVERING clause",
204
0
                              ErrorCode::SQL_STATEMENT_INVALID);
205
0
  }
206
207
167
  if (!QLType::IsValidPrimaryType(ql_type()->main()) || ql_type()->main() == DataType::FROZEN) {
208
0
    return sem_context->Error(coldef_, "Unsupported index datatype",
209
0
                              ErrorCode::SQL_STATEMENT_INVALID);
210
0
  }
211
212
  // Add the analyzed covering index column to table. Need to check for proper datatype and set
213
  // column location because column definition is loaded from the indexed table definition actually.
214
167
  DCHECK(sem_context->current_create_table_stmt()->opcode() == TreeNodeOpcode::kPTCreateIndex);
215
167
  PTCreateIndex* tab = static_cast<PTCreateIndex*>(sem_context->current_create_table_stmt());
216
167
  return tab->AppendIndexColumn(sem_context, coldef_);
217
167
}
218
219
}  // namespace ql
220
}  // namespace yb