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_create_index.cc
Line
Count
Source (jump to first uncovered line)
1
//--------------------------------------------------------------------------------------------------
2
// Copyright (c) YugaByte, Inc.
3
//
4
// Treenode definitions for CREATE INDEX statements.
5
//--------------------------------------------------------------------------------------------------
6
#include "yb/yql/cql/ql/ptree/pt_create_index.h"
7
8
#include "yb/client/schema.h"
9
#include "yb/client/table.h"
10
#include "yb/common/schema.h"
11
#include "yb/gutil/strings/ascii_ctype.h"
12
#include "yb/yql/cql/ql/ptree/column_desc.h"
13
#include "yb/yql/cql/ql/ptree/pt_column_definition.h"
14
#include "yb/yql/cql/ql/ptree/pt_expr.h"
15
#include "yb/yql/cql/ql/ptree/pt_option.h"
16
#include "yb/yql/cql/ql/ptree/sem_context.h"
17
18
DEFINE_bool(cql_raise_index_where_clause_error, false,
19
            "Raise unsupported error if where clause is specified for create index");
20
21
namespace yb {
22
namespace ql {
23
24
using std::shared_ptr;
25
using std::to_string;
26
using client::YBColumnSchema;
27
using client::YBSchema;
28
using client::YBTableName;
29
30
//--------------------------------------------------------------------------------------------------
31
32
PTCreateIndex::PTCreateIndex(MemoryContext *memctx,
33
                             YBLocationPtr loc,
34
                             bool is_backfill_deferred,
35
                             bool is_unique,
36
                             const MCSharedPtr<MCString>& name,
37
                             const PTQualifiedNamePtr& table_name,
38
                             const PTListNodePtr& columns,
39
                             const bool create_if_not_exists,
40
                             const PTTablePropertyListNodePtr& ordering_list,
41
                             const PTListNodePtr& covering,
42
                             const PTExpr::SharedPtr& where_clause)
43
    : PTCreateTable(memctx, loc, table_name, columns, create_if_not_exists, ordering_list),
44
      is_unique_(is_unique),
45
      is_backfill_deferred_(is_backfill_deferred),
46
      name_(name),
47
      covering_(covering),
48
      is_local_(false),
49
      column_descs_(memctx),
50
      auto_includes_(memctx),
51
      where_clause_(where_clause),
52
512
      where_clause_column_refs_(nullptr) {
53
512
}
54
55
510
PTCreateIndex::~PTCreateIndex() {
56
510
}
57
58
namespace {
59
60
175
CHECKED_STATUS SetupCoveringColumn(PTIndexColumn *node, SemContext *sem_context) {
61
175
  RETURN_NOT_OK(node->SetupCoveringIndexColumn(sem_context));
62
174
  return Status::OK();
63
175
}
64
65
} // namespace
66
67
511
CHECKED_STATUS PTCreateIndex::Analyze(SemContext *sem_context) {
68
  // Look up indexed table.
69
511
  bool is_system_ignored;
70
511
  RETURN_NOT_OK(relation_->AnalyzeName(sem_context, ObjectType::TABLE));
71
72
511
  RETURN_NOT_OK(sem_context->LookupTable(relation_->ToTableName(), relation_->loc(),
73
511
                                         true /* write_table */,
74
511
                                         PermissionType::ALTER_PERMISSION,
75
511
                                         &table_, &is_system_ignored,
76
511
                                         &column_descs_));
77
78
  // Save context state, and set "this" as current create-table statement in the context.
79
508
  SymbolEntry cached_entry = *sem_context->current_processing_id();
80
508
  sem_context->set_current_create_table_stmt(this);
81
82
  // Analyze index table like a regular table for the primary key definitions.
83
  // If flag use_cassandra_authentication is enabled, we will not check for the create permission
84
  // on the table because creating an index requires the alter permission on the table.
85
508
  RETURN_NOT_OK(PTCreateTable::Analyze(sem_context));
86
87
504
  if (!name_) {
88
52
    string auto_name = relation_->last_name().c_str();
89
90
52
    for (const auto& column : hash_columns_) {
91
52
      auto_name += string("_") + column->yb_name();
92
52
    }
93
94
52
    for (const auto& column : primary_columns_) {
95
0
      auto_name += string("_") + column->yb_name();
96
0
    }
97
98
52
    auto_name += "_idx";
99
52
    string final_name;
100
101
1.02k
    for (char& c : auto_name) {
102
1.02k
      if (ascii_isalnum(c) || 
c == '_'218
) { // Accepted a-z, A-Z, 0-9, _.
103
1.02k
        final_name += c;
104
1.02k
      }
105
1.02k
    }
106
107
52
    LOG(INFO) << "Set automatic name for the new index: " << final_name;
108
52
    name_ = MCMakeShared<MCString>(sem_context->PTreeMem(), final_name.c_str());
109
52
  }
110
111
  // Add covering columns.
112
504
  if (covering_ != nullptr) {
113
137
    RETURN_NOT_OK((covering_->Apply<SemContext, PTIndexColumn>(sem_context, &SetupCoveringColumn)));
114
137
  }
115
116
  // Add remaining primary key columns from the indexed table. For non-unique index, add the columns
117
  // to the primary key of the index table to make the non-unique values unique. For unique index,
118
  // they should be added as non-primary-key columns.
119
503
  const YBSchema& schema = table_->schema();
120
1.78k
  for (size_t idx = 0; idx < schema.num_key_columns(); 
idx++1.28k
) {
121
    // Not adding key-column schema.columns(idx) to the INDEX metadata if it is already referred to
122
    // by one of the index-columns.
123
1.28k
    const MCString key_name(schema.Column(idx).name().c_str(), sem_context->PTempMem());
124
1.28k
    PTColumnDefinition *coldef = sem_context->GetColumnDefinition(key_name);
125
1.28k
    if (coldef && 
coldef->colexpr()->opcode() == TreeNodeOpcode::kPTRef214
) {
126
      // Column is already defined as a part of INDEX.
127
213
      continue;
128
213
    }
129
130
    // Create a new treenode PTIndexColumn for column definition.
131
1.07k
    MCSharedPtr<MCString> col_name =
132
1.07k
      MCMakeShared<MCString>(sem_context->PSemMem(), key_name.c_str());
133
1.07k
    PTQualifiedName::SharedPtr ref_name =
134
1.07k
      PTQualifiedName::MakeShared(sem_context->PSemMem(), loc_ptr(), col_name);
135
1.07k
    PTRef::SharedPtr col_ref = PTRef::MakeShared(sem_context->PSemMem(), loc_ptr(), ref_name);
136
1.07k
    PTIndexColumn::SharedPtr col =
137
1.07k
      PTIndexColumn::MakeShared(sem_context->PSemMem(), loc_ptr(), col_name, col_ref);
138
1.07k
    RETURN_NOT_OK(col->Analyze(sem_context));
139
140
    // Add this key column to INDEX as it is not yet in the INDEX description.
141
1.07k
    auto_includes_.push_back(col);
142
1.07k
    RETURN_NOT_OK(AppendIndexColumn(sem_context, col.get()));
143
1.07k
  }
144
145
  // Check whether the index is local, i.e. whether the hash keys match (including being in the
146
  // same order).
147
502
  is_local_ = true;
148
502
  if (schema.num_hash_key_columns() != hash_columns_.size()) {
149
191
    is_local_ = false;
150
311
  } else {
151
311
    int idx = 0;
152
311
    for (const auto& column : hash_columns_) {
153
311
      if (column->yb_name() != column_descs_[idx].name()) {
154
308
        is_local_ = false;
155
308
        break;
156
308
      }
157
3
      idx++;
158
3
    }
159
311
  }
160
161
  // Verify transactions and consistency settings.
162
502
  TableProperties table_properties;
163
502
  RETURN_NOT_OK(ToTableProperties(&table_properties));
164
502
  if (table_->InternalSchema().table_properties().is_transactional()) {
165
362
    if (!table_properties.is_transactional()) {
166
24
      return sem_context->Error(this,
167
24
                                "Transactions must be enabled in an index of a "
168
24
                                "transactions-enabled table.",
169
24
                                ErrorCode::INVALID_TABLE_DEFINITION);
170
24
    }
171
338
    if (table_properties.consistency_level() == YBConsistencyLevel::USER_ENFORCED) {
172
9
      return sem_context->Error(this,
173
9
                                "User-enforced consistency level not allowed in a "
174
9
                                "transactions-enabled index.",
175
9
                                ErrorCode::INVALID_TABLE_DEFINITION);
176
9
    }
177
338
  } else {
178
140
    if (table_properties.is_transactional()) {
179
18
      return sem_context->Error(this,
180
18
                                "Transactions cannot be enabled in an index of a table without "
181
18
                                "transactions enabled.",
182
18
                                ErrorCode::INVALID_TABLE_DEFINITION);
183
18
    }
184
122
    if (table_properties.consistency_level() != YBConsistencyLevel::USER_ENFORCED) {
185
3
      return sem_context->Error(this,
186
3
                                "Consistency level must be user-enforced in an index without "
187
3
                                "transactions enabled.",
188
3
                                ErrorCode::INVALID_TABLE_DEFINITION);
189
3
    }
190
122
  }
191
192
  // TODO: create local index when co-partition table is available.
193
448
  if (is_local_) {
194
3
    LOG(WARNING) << "Creating local secondary index " << yb_table_name().ToString()
195
3
                 << " as global index.";
196
3
    is_local_ = false;
197
3
  }
198
199
  // If partial index (i.e., where clause predicate present in CREATE INDEX), analyze the index's
200
  // predicate.
201
448
  if (where_clause_.get()) {
202
132
    IdxPredicateState idx_predicate_state(sem_context->PTempMem(), opcode());
203
132
    SemState sem_state(sem_context, QLType::Create(BOOL), InternalType::kBoolValue);
204
132
    sem_state.SetIdxPredicateState(&idx_predicate_state);
205
132
    RETURN_NOT_OK(where_clause_->Analyze(sem_context));
206
129
    where_clause_column_refs_ = idx_predicate_state.column_refs();
207
129
  }
208
209
  // Restore the context value as we are done with this table.
210
445
  sem_context->set_current_processing_id(cached_entry);
211
445
  if (VLOG_IS_ON(3)) {
212
0
    PrintSemanticAnalysisResult(sem_context);
213
0
  }
214
215
445
  return Status::OK();
216
448
}
217
218
1.23k
Status PTCreateIndex::AppendIndexColumn(SemContext *sem_context, PTColumnDefinition *column) {
219
1.23k
  if (!is_unique_ && 
sem_context->GetColumnDesc(*column->name())->is_primary()979
) {
220
857
    return AppendPrimaryColumn(sem_context, column);
221
857
  }
222
223
380
  return AppendColumn(sem_context, column);
224
1.23k
}
225
226
0
void PTCreateIndex::PrintSemanticAnalysisResult(SemContext *sem_context) {
227
0
  PTCreateTable::PrintSemanticAnalysisResult(sem_context);
228
0
}
229
230
947
Status PTCreateIndex::ToTableProperties(TableProperties *table_properties) const {
231
947
  table_properties->SetTransactional(true);
232
947
  table_properties->SetUseMangledColumnName(true);
233
947
  return PTCreateTable::ToTableProperties(table_properties);
234
947
}
235
236
890
const std::string& PTCreateIndex::indexed_table_id() const {
237
890
  return table_->id();
238
890
}
239
240
708
client::YBTableName PTCreateIndex::yb_table_name() const {
241
708
  return client::YBTableName(YQL_DATABASE_CQL,
242
708
                             PTCreateTable::yb_table_name().namespace_name().c_str(),
243
708
                             name_->c_str());
244
708
}
245
246
890
client::YBTableName PTCreateIndex::indexed_table_name() const {
247
890
  return PTCreateTable::yb_table_name();
248
890
}
249
250
}  // namespace ql
251
}  // namespace yb