/Users/deen/code/yugabyte-db/src/yb/master/yql_indexes_vtable.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #include "yb/master/yql_indexes_vtable.h" |
15 | | |
16 | | #include "yb/common/index_column.h" |
17 | | #include "yb/common/ql_name.h" |
18 | | #include "yb/common/ql_type.h" |
19 | | #include "yb/common/ql_value.h" |
20 | | #include "yb/common/schema.h" |
21 | | |
22 | | #include "yb/master/catalog_entity_info.h" |
23 | | #include "yb/master/catalog_manager_if.h" |
24 | | |
25 | | #include "yb/util/status_log.h" |
26 | | |
27 | | namespace yb { |
28 | | namespace master { |
29 | | |
30 | | YQLIndexesVTable::YQLIndexesVTable(const TableName& table_name, |
31 | | const NamespaceName& namespace_name, |
32 | | Master* const master) |
33 | 3.00k | : YQLVirtualTable(table_name, namespace_name, master, CreateSchema()) { |
34 | 3.00k | } |
35 | | |
36 | | namespace { |
37 | | |
38 | 1.23k | const string& ColumnName(const Schema& schema, const ColumnId id) { |
39 | 1.23k | auto column = schema.column_by_id(id); |
40 | 1.23k | DCHECK(column.ok()); |
41 | 1.23k | return column->name(); |
42 | 1.23k | } |
43 | | |
44 | 4.01k | string QLExpressionPBToPredicateString(const QLExpressionPB& where_expr, const Schema& schema) { |
45 | | // TODO(Piyush): Move this to some sort of util file and handle more cases if later we support |
46 | | // them in partial index predicate. |
47 | 4.01k | switch (where_expr.expr_case()) { |
48 | 0 | case yb::QLExpressionPB::EXPR_NOT_SET: return "NULL"; |
49 | 1.23k | case QLExpressionPB::kValue: |
50 | 1.23k | return QLValue(where_expr.value()).ToValueString(QuotesType::kSingleQuotes); |
51 | 1.23k | case QLExpressionPB::kColumnId: return ColumnName(schema, ColumnId(where_expr.column_id())); |
52 | 1.53k | case QLExpressionPB::kCondition: |
53 | 1.53k | { |
54 | 1.53k | std::string res; |
55 | 1.53k | res += QLExpressionPBToPredicateString(where_expr.condition().operands(0), schema); |
56 | 1.53k | switch (where_expr.condition().op()) { |
57 | 298 | case QLOperator::QL_OP_AND: |
58 | 298 | res += " AND "; |
59 | 298 | break; |
60 | 373 | case QLOperator::QL_OP_EQUAL: |
61 | 373 | res += " = "; |
62 | 373 | break; |
63 | 301 | case QLOperator::QL_OP_NOT_EQUAL: |
64 | 301 | res += " != "; |
65 | 301 | break; |
66 | 491 | case QLOperator::QL_OP_GREATER_THAN: |
67 | 491 | res += " > "; |
68 | 491 | break; |
69 | 25 | case QLOperator::QL_OP_GREATER_THAN_EQUAL: |
70 | 25 | res += " >= "; |
71 | 25 | break; |
72 | 25 | case QLOperator::QL_OP_LESS_THAN: |
73 | 25 | res += " < "; |
74 | 25 | break; |
75 | 25 | case QLOperator::QL_OP_LESS_THAN_EQUAL: |
76 | 25 | res += " <= "; |
77 | 25 | break; |
78 | 0 | default: |
79 | 0 | LOG_IF(DFATAL, false) << "We should have handled anything required."; |
80 | 0 | break; |
81 | 1.53k | } |
82 | 1.53k | res += QLExpressionPBToPredicateString(where_expr.condition().operands(1), schema); |
83 | 1.53k | return res; |
84 | 1.53k | } |
85 | 0 | default: |
86 | 0 | LOG_IF(DFATAL, false) << "We should have handled anything required."; |
87 | 4.01k | } |
88 | 0 | return std::string(); |
89 | 4.01k | } |
90 | | |
91 | | } // namespace |
92 | | |
93 | | Result<std::shared_ptr<QLRowBlock>> YQLIndexesVTable::RetrieveData( |
94 | 14.5k | const QLReadRequestPB& request) const { |
95 | 14.5k | auto vtable = std::make_shared<QLRowBlock>(schema()); |
96 | 14.5k | auto* catalog_manager = &this->catalog_manager(); |
97 | | |
98 | 14.5k | auto tables = catalog_manager->GetTables(GetTablesMode::kVisibleToClient); |
99 | 270k | for (const auto& table : tables) { |
100 | 270k | const auto indexed_table_id = table->indexed_table_id(); |
101 | 270k | if (indexed_table_id.empty()) { |
102 | 262k | continue; |
103 | 262k | } |
104 | | |
105 | | // Skip non-YQL indexes. |
106 | 8.52k | if (!IsYcqlTable(*table)) { |
107 | 2.57k | continue; |
108 | 2.57k | } |
109 | | |
110 | 5.94k | scoped_refptr<TableInfo> indexed_table = catalog_manager->GetTableInfo(indexed_table_id); |
111 | | // Skip if the index is invalid (bad schema). |
112 | 5.94k | if (indexed_table == nullptr) { |
113 | 0 | continue; |
114 | 0 | } |
115 | 5.94k | Schema indexed_schema; |
116 | 5.94k | RETURN_NOT_OK(indexed_table->GetSchema(&indexed_schema)); |
117 | | |
118 | | // Get namespace for table. |
119 | 5.94k | auto ns_info = VERIFY_RESULT(catalog_manager->FindNamespaceById(table->namespace_id())); |
120 | | |
121 | | // Create appropriate row for the table; |
122 | 0 | QLRow& row = vtable->Extend(); |
123 | 5.94k | RETURN_NOT_OK(SetColumnValue(kKeyspaceName, ns_info->name(), &row)); |
124 | 5.94k | RETURN_NOT_OK(SetColumnValue(kTableName, indexed_table->name(), &row)); |
125 | 5.94k | RETURN_NOT_OK(SetColumnValue(kIndexName, table->name(), &row)); |
126 | 5.94k | RETURN_NOT_OK(SetColumnValue(kKind, "COMPOSITES", &row)); |
127 | | |
128 | 5.94k | string target; |
129 | 5.94k | IndexInfo index_info = indexed_table->GetIndexInfo(table->id()); |
130 | 12.6k | for (size_t i = 0; i < index_info.hash_column_count(); i++6.72k ) { |
131 | 6.72k | if (index_info.use_mangled_column_name()) { |
132 | | // Newer IndexInfo uses mangled name of expression instead of column ID of the table |
133 | | // that was indexed. |
134 | 6.72k | target += YcqlName::DemangleName(index_info.columns()[i].column_name); |
135 | 6.72k | } else { |
136 | 0 | target += ColumnName(indexed_schema, index_info.columns()[i].indexed_column_id); |
137 | 0 | } |
138 | 6.72k | if (i != index_info.hash_column_count() - 1) { |
139 | 776 | target += ", "; |
140 | 776 | } |
141 | 6.72k | } |
142 | 5.94k | if (index_info.hash_column_count() > 1) { |
143 | 763 | target = '(' + target + ')'; |
144 | 763 | } |
145 | 5.94k | for (size_t i = index_info.hash_column_count(); |
146 | 20.6k | i < index_info.hash_column_count() + index_info.range_column_count(); i++14.6k ) { |
147 | 14.6k | target += ", "; |
148 | 14.6k | if (index_info.use_mangled_column_name()14.6k ) { |
149 | | // Newer IndexInfo uses mangled name of expression instead of column ID of the table |
150 | | // that was indexed. |
151 | 14.6k | target += YcqlName::DemangleName(index_info.columns()[i].column_name); |
152 | 18.4E | } else { |
153 | 18.4E | target += ColumnName(indexed_schema, index_info.columns()[i].indexed_column_id); |
154 | 18.4E | } |
155 | 14.6k | } |
156 | | |
157 | 5.94k | string include; |
158 | 5.94k | for (size_t i = index_info.hash_column_count() + index_info.range_column_count(); |
159 | 10.2k | i < index_info.columns().size(); i++4.25k ) { |
160 | 4.25k | if (index_info.use_mangled_column_name()) { |
161 | | // Newer IndexInfo uses mangled name of expression instead of column ID of the table |
162 | | // that was indexed. |
163 | 4.25k | include += YcqlName::DemangleName(index_info.columns()[i].column_name); |
164 | 4.25k | } else { |
165 | 0 | include += ColumnName(indexed_schema, index_info.columns()[i].indexed_column_id); |
166 | 0 | } |
167 | 4.25k | if (i != index_info.columns().size() - 1) { |
168 | 1.89k | include += ", "; |
169 | 1.89k | } |
170 | 4.25k | } |
171 | | |
172 | 5.94k | string predicate; |
173 | 5.94k | if (index_info.where_predicate_spec()) { |
174 | 941 | predicate = QLExpressionPBToPredicateString(index_info.where_predicate_spec()->where_expr(), |
175 | 941 | indexed_schema); |
176 | 941 | } |
177 | | |
178 | 5.94k | QLValue options; |
179 | 5.94k | options.set_map_value(); |
180 | 5.94k | options.add_map_key()->set_string_value("target"); |
181 | 5.94k | options.add_map_value()->set_string_value(target); |
182 | 5.94k | if (!include.empty()) { |
183 | 2.36k | options.add_map_key()->set_string_value("include"); |
184 | 2.36k | options.add_map_value()->set_string_value(include); |
185 | 2.36k | } |
186 | 5.94k | if (!predicate.empty()) { |
187 | 940 | options.add_map_key()->set_string_value("predicate"); |
188 | 940 | options.add_map_value()->set_string_value(predicate); |
189 | 940 | } |
190 | 5.94k | RETURN_NOT_OK(SetColumnValue(kOptions, options.value(), &row)); |
191 | | |
192 | | // Create appropriate table uuids. |
193 | 5.94k | Uuid uuid; |
194 | | // Note: table id is in host byte order. |
195 | 5.94k | RETURN_NOT_OK(uuid.FromHexString(indexed_table_id)); |
196 | 5.94k | RETURN_NOT_OK(SetColumnValue(kTableId, uuid, &row)); |
197 | 5.94k | RETURN_NOT_OK(uuid.FromHexString(table->id())); |
198 | 5.94k | RETURN_NOT_OK(SetColumnValue(kIndexId, uuid, &row)); |
199 | | |
200 | 5.94k | Schema schema; |
201 | 5.94k | RETURN_NOT_OK(table->GetSchema(&schema)); |
202 | 5.94k | const auto & table_properties = schema.table_properties(); |
203 | | |
204 | 5.94k | if (table_properties.HasNumTablets()) { |
205 | 30 | int32_t num_tablets = table_properties.num_tablets(); |
206 | 30 | RETURN_NOT_OK(SetColumnValue(kNumTablets, num_tablets, &row)); |
207 | 30 | } |
208 | | |
209 | 5.94k | QLValue txn; |
210 | 5.94k | txn.set_map_value(); |
211 | 5.94k | txn.add_map_key()->set_string_value("enabled"); |
212 | 5.94k | txn.add_map_value()->set_string_value(table_properties.is_transactional() ? "true"3.86k : "false"2.08k ); |
213 | 5.94k | if (table_properties.consistency_level() == YBConsistencyLevel::USER_ENFORCED) { |
214 | | // If consistency level is user-encorced, show it also. Omit the other consistency levels |
215 | | // which are not recognized by "CREATE INDEX" syntax. |
216 | 2.08k | txn.add_map_key()->set_string_value("consistency_level"); |
217 | 2.08k | txn.add_map_value()->set_string_value("user_enforced"); |
218 | 2.08k | } |
219 | 5.94k | RETURN_NOT_OK(SetColumnValue(kTransactions, txn.value(), &row)); |
220 | | |
221 | 5.94k | RETURN_NOT_OK(SetColumnValue(kIsUnique, table->is_unique_index(), &row)); |
222 | 5.94k | } |
223 | | |
224 | 14.5k | return vtable; |
225 | 14.5k | } |
226 | | |
227 | 3.00k | Schema YQLIndexesVTable::CreateSchema() const { |
228 | 3.00k | SchemaBuilder builder; |
229 | 3.00k | CHECK_OK(builder.AddHashKeyColumn(kKeyspaceName, QLType::Create(DataType::STRING))); |
230 | 3.00k | CHECK_OK(builder.AddKeyColumn(kTableName, QLType::Create(DataType::STRING))); |
231 | 3.00k | CHECK_OK(builder.AddKeyColumn(kIndexName, QLType::Create(DataType::STRING))); |
232 | 3.00k | CHECK_OK(builder.AddColumn(kKind, QLType::Create(DataType::STRING))); |
233 | 3.00k | CHECK_OK(builder.AddColumn(kOptions, |
234 | 3.00k | QLType::CreateTypeMap(DataType::STRING, DataType::STRING))); |
235 | 3.00k | CHECK_OK(builder.AddColumn(kTableId, QLType::Create(DataType::UUID))); |
236 | 3.00k | CHECK_OK(builder.AddColumn(kIndexId, QLType::Create(DataType::UUID))); |
237 | 3.00k | CHECK_OK(builder.AddColumn(kTransactions, |
238 | 3.00k | QLType::CreateTypeMap(DataType::STRING, DataType::STRING))); |
239 | 3.00k | CHECK_OK(builder.AddColumn(kIsUnique, QLType::Create(DataType::BOOL))); |
240 | 3.00k | CHECK_OK(builder.AddColumn(kNumTablets, QLType::Create(DataType::INT32))); |
241 | | |
242 | 3.00k | return builder.Build(); |
243 | 3.00k | } |
244 | | |
245 | | } // namespace master |
246 | | } // namespace yb |