/Users/deen/code/yugabyte-db/src/yb/yql/pggate/pg_ddl.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 | | |
16 | | #include "yb/yql/pggate/pg_ddl.h" |
17 | | |
18 | | #include "yb/client/yb_op.h" |
19 | | #include "yb/client/yb_table_name.h" |
20 | | |
21 | | #include "yb/common/common.pb.h" |
22 | | #include "yb/common/constants.h" |
23 | | #include "yb/common/entity_ids.h" |
24 | | #include "yb/common/pg_system_attr.h" |
25 | | |
26 | | #include "yb/util/flag_tags.h" |
27 | | #include "yb/util/status_format.h" |
28 | | #include "yb/util/status_log.h" |
29 | | #include "yb/util/tsan_util.h" |
30 | | |
31 | | #include "yb/yql/pggate/pg_client.h" |
32 | | |
33 | | DEFINE_test_flag(int32, user_ddl_operation_timeout_sec, 0, |
34 | | "Adjusts the timeout for a DDL operation from the YBClient default, if non-zero."); |
35 | | |
36 | | DECLARE_int32(max_num_tablets_for_table); |
37 | | |
38 | | namespace yb { |
39 | | namespace pggate { |
40 | | |
41 | | using std::make_shared; |
42 | | using std::shared_ptr; |
43 | | using std::string; |
44 | | using namespace std::literals; // NOLINT |
45 | | |
46 | | using client::YBSession; |
47 | | using client::YBMetaDataCache; |
48 | | |
49 | | // TODO(neil) This should be derived from a GFLAGS. |
50 | | static MonoDelta kDdlTimeout = 60s * kTimeMultiplier; |
51 | | |
52 | | namespace { |
53 | | |
54 | 6.43k | CoarseTimePoint DdlDeadline() { |
55 | 6.43k | auto timeout = MonoDelta::FromSeconds(FLAGS_TEST_user_ddl_operation_timeout_sec); |
56 | 6.43k | if (timeout == MonoDelta::kZero) { |
57 | 6.42k | timeout = kDdlTimeout; |
58 | 6.42k | } |
59 | 6.43k | return CoarseMonoClock::now() + timeout; |
60 | 6.43k | } |
61 | | |
62 | | } // namespace |
63 | | |
64 | | //-------------------------------------------------------------------------------------------------- |
65 | | // PgCreateDatabase |
66 | | //-------------------------------------------------------------------------------------------------- |
67 | | |
68 | | PgCreateDatabase::PgCreateDatabase(PgSession::ScopedRefPtr pg_session, |
69 | | const char *database_name, |
70 | | const PgOid database_oid, |
71 | | const PgOid source_database_oid, |
72 | | const PgOid next_oid, |
73 | | const bool colocated) |
74 | 134 | : PgDdl(std::move(pg_session)) { |
75 | 134 | req_.set_database_name(database_name); |
76 | 134 | req_.set_database_oid(database_oid); |
77 | 134 | req_.set_source_database_oid(source_database_oid); |
78 | 134 | req_.set_next_oid(next_oid); |
79 | 134 | req_.set_colocated(colocated); |
80 | 134 | } |
81 | | |
82 | 134 | PgCreateDatabase::~PgCreateDatabase() { |
83 | 134 | } |
84 | | |
85 | 134 | Status PgCreateDatabase::Exec() { |
86 | 134 | return pg_session_->pg_client().CreateDatabase(&req_, DdlDeadline()); |
87 | 134 | } |
88 | | |
89 | | PgDropDatabase::PgDropDatabase(PgSession::ScopedRefPtr pg_session, |
90 | | const char *database_name, |
91 | | PgOid database_oid) |
92 | | : PgDdl(pg_session), |
93 | | database_name_(database_name), |
94 | 72 | database_oid_(database_oid) { |
95 | 72 | } |
96 | | |
97 | 72 | PgDropDatabase::~PgDropDatabase() { |
98 | 72 | } |
99 | | |
100 | 72 | Status PgDropDatabase::Exec() { |
101 | 72 | return pg_session_->DropDatabase(database_name_, database_oid_); |
102 | 72 | } |
103 | | |
104 | | PgAlterDatabase::PgAlterDatabase(PgSession::ScopedRefPtr pg_session, |
105 | | const char *database_name, |
106 | | PgOid database_oid) |
107 | 3 | : PgDdl(pg_session) { |
108 | 3 | req_.set_database_name(database_name); |
109 | 3 | req_.set_database_oid(database_oid); |
110 | 3 | } |
111 | | |
112 | 3 | PgAlterDatabase::~PgAlterDatabase() { |
113 | 3 | } |
114 | | |
115 | 3 | Status PgAlterDatabase::Exec() { |
116 | 3 | return pg_session_->pg_client().AlterDatabase(&req_, DdlDeadline()); |
117 | 3 | } |
118 | | |
119 | 3 | void PgAlterDatabase::RenameDatabase(const char *newname) { |
120 | 3 | req_.set_new_name(newname); |
121 | 3 | } |
122 | | |
123 | | //-------------------------------------------------------------------------------------------------- |
124 | | // PgCreateTablegroup / PgDropTablegroup |
125 | | //-------------------------------------------------------------------------------------------------- |
126 | | |
127 | | PgCreateTablegroup::PgCreateTablegroup(PgSession::ScopedRefPtr pg_session, |
128 | | const char *database_name, |
129 | | const PgOid database_oid, |
130 | | const PgOid tablegroup_oid, |
131 | | const PgOid tablespace_oid) |
132 | 54 | : PgDdl(pg_session) { |
133 | 54 | req_.set_database_name(database_name); |
134 | 54 | PgObjectId(database_oid, tablegroup_oid).ToPB(req_.mutable_tablegroup_id()); |
135 | 54 | PgObjectId(database_oid, tablespace_oid).ToPB(req_.mutable_tablespace_id()); |
136 | 54 | } |
137 | | |
138 | 54 | PgCreateTablegroup::~PgCreateTablegroup() { |
139 | 54 | } |
140 | | |
141 | 54 | Status PgCreateTablegroup::Exec() { |
142 | 54 | return pg_session_->pg_client().CreateTablegroup(&req_, DdlDeadline()); |
143 | 54 | } |
144 | | |
145 | | PgDropTablegroup::PgDropTablegroup(PgSession::ScopedRefPtr pg_session, |
146 | | const PgOid database_oid, |
147 | | const PgOid tablegroup_oid) |
148 | 39 | : PgDdl(pg_session) { |
149 | 39 | PgObjectId(database_oid, tablegroup_oid).ToPB(req_.mutable_tablegroup_id()); |
150 | 39 | } |
151 | | |
152 | 39 | PgDropTablegroup::~PgDropTablegroup() { |
153 | 39 | } |
154 | | |
155 | 39 | Status PgDropTablegroup::Exec() { |
156 | 39 | return pg_session_->pg_client().DropTablegroup(&req_, DdlDeadline()); |
157 | 39 | } |
158 | | |
159 | | //-------------------------------------------------------------------------------------------------- |
160 | | // PgCreateTable |
161 | | //-------------------------------------------------------------------------------------------------- |
162 | | |
163 | | PgCreateTable::PgCreateTable(PgSession::ScopedRefPtr pg_session, |
164 | | const char *database_name, |
165 | | const char *schema_name, |
166 | | const char *table_name, |
167 | | const PgObjectId& table_id, |
168 | | bool is_shared_table, |
169 | | bool if_not_exist, |
170 | | bool add_primary_key, |
171 | | const bool colocated, |
172 | | const PgObjectId& tablegroup_oid, |
173 | | const ColocationId colocation_id, |
174 | | const PgObjectId& tablespace_oid, |
175 | | const PgObjectId& matview_pg_table_oid) |
176 | 5.14k | : PgDdl(pg_session) { |
177 | 5.14k | table_id.ToPB(req_.mutable_table_id()); |
178 | 5.14k | req_.set_database_name(database_name); |
179 | 5.14k | req_.set_table_name(table_name); |
180 | 5.14k | req_.set_num_tablets(-1); |
181 | 5.14k | req_.set_is_pg_catalog_table(strcmp(schema_name, "pg_catalog") == 0 || |
182 | 5.14k | strcmp(schema_name, "information_schema") == 04.85k ); |
183 | 5.14k | req_.set_is_shared_table(is_shared_table); |
184 | 5.14k | req_.set_if_not_exist(if_not_exist); |
185 | 5.14k | req_.set_colocated(colocated); |
186 | 5.14k | req_.set_schema_name(schema_name); |
187 | 5.14k | tablegroup_oid.ToPB(req_.mutable_tablegroup_oid()); |
188 | 5.14k | if (colocation_id != kColocationIdNotSet) { |
189 | 24 | req_.set_colocation_id(colocation_id); |
190 | 24 | } |
191 | 5.14k | tablespace_oid.ToPB(req_.mutable_tablespace_oid()); |
192 | 5.14k | matview_pg_table_oid.ToPB(req_.mutable_matview_pg_table_oid()); |
193 | | |
194 | | // Add internal primary key column to a Postgres table without a user-specified primary key. |
195 | 5.14k | if (add_primary_key) { |
196 | | // For regular user table, ybrowid should be a hash key because ybrowid is a random uuid. |
197 | | // For colocated or sys catalog table, ybrowid should be a range key because they are |
198 | | // unpartitioned tables in a single tablet. |
199 | 2.25k | bool is_hash = !(req_.is_pg_catalog_table() || colocated2.22k || tablegroup_oid.IsValid()2.20k ); |
200 | 2.25k | CHECK_OK(AddColumn("ybrowid", static_cast<int32_t>(PgSystemAttrNum::kYBRowId), |
201 | 2.25k | YB_YQL_DATA_TYPE_BINARY, is_hash, true /* is_range */)); |
202 | 2.25k | } |
203 | 5.14k | } |
204 | | |
205 | | Status PgCreateTable::AddColumnImpl(const char *attr_name, |
206 | | int attr_num, |
207 | | int attr_ybtype, |
208 | | int pg_type_oid, |
209 | | bool is_hash, |
210 | | bool is_range, |
211 | 13.9k | SortingType sorting_type) { |
212 | 13.9k | auto& column = *req_.mutable_create_columns()->Add(); |
213 | 13.9k | column.set_attr_name(attr_name); |
214 | 13.9k | column.set_attr_num(attr_num); |
215 | 13.9k | column.set_attr_ybtype(attr_ybtype); |
216 | 13.9k | column.set_is_hash(is_hash); |
217 | 13.9k | column.set_is_range(is_range); |
218 | 13.9k | column.set_sorting_type(sorting_type); |
219 | 13.9k | column.set_attr_pgoid(pg_type_oid); |
220 | 13.9k | return Status::OK(); |
221 | 13.9k | } |
222 | | |
223 | 353 | Status PgCreateTable::SetNumTablets(int32_t num_tablets) { |
224 | 353 | if (num_tablets < 0) { |
225 | 0 | return STATUS(InvalidArgument, "num_tablets cannot be less than zero"); |
226 | 0 | } |
227 | 353 | if (num_tablets > FLAGS_max_num_tablets_for_table) { |
228 | 1 | return STATUS(InvalidArgument, "num_tablets exceeds system limit"); |
229 | 1 | } |
230 | | |
231 | 352 | req_.set_num_tablets(num_tablets); |
232 | 352 | return Status::OK(); |
233 | 353 | } |
234 | | |
235 | 181 | Status PgCreateTable::AddSplitBoundary(PgExpr **exprs, int expr_count) { |
236 | 181 | auto* values = req_.mutable_split_bounds()->Add()->mutable_values(); |
237 | 459 | for (int i = 0; i < expr_count; ++i278 ) { |
238 | 278 | RETURN_NOT_OK(exprs[i]->Eval(values->Add())); |
239 | 278 | } |
240 | 181 | return Status::OK(); |
241 | 181 | } |
242 | | |
243 | 5.05k | Status PgCreateTable::Exec() { |
244 | 5.05k | RETURN_NOT_OK(pg_session_->pg_client().CreateTable(&req_, DdlDeadline())); |
245 | 5.02k | auto base_table_id = PgObjectId::FromPB(req_.base_table_id()); |
246 | 5.02k | if (base_table_id.IsValid()) { |
247 | 855 | pg_session_->InvalidateTableCache(base_table_id, InvalidateOnPgClient::kFalse); |
248 | 855 | } |
249 | 5.02k | return Status::OK(); |
250 | 5.05k | } |
251 | | |
252 | | void PgCreateTable::SetupIndex( |
253 | 868 | const PgObjectId& base_table_id, bool is_unique_index, bool skip_index_backfill) { |
254 | 868 | base_table_id.ToPB(req_.mutable_base_table_id()); |
255 | 868 | req_.set_is_unique_index(is_unique_index); |
256 | 868 | req_.set_skip_index_backfill(skip_index_backfill); |
257 | 868 | } |
258 | | |
259 | 17.3k | StmtOp PgCreateTable::stmt_op() const { |
260 | 17.3k | return PgObjectId::FromPB(req_.base_table_id()).IsValid() |
261 | 17.3k | ? StmtOp::STMT_CREATE_INDEX2.17k : StmtOp::STMT_CREATE_TABLE15.1k ; |
262 | 17.3k | } |
263 | | |
264 | | //-------------------------------------------------------------------------------------------------- |
265 | | // PgDropTable |
266 | | //-------------------------------------------------------------------------------------------------- |
267 | | |
268 | | PgDropTable::PgDropTable(PgSession::ScopedRefPtr pg_session, |
269 | | const PgObjectId& table_id, |
270 | | bool if_exist) |
271 | | : PgDdl(pg_session), |
272 | | table_id_(table_id), |
273 | 4.16k | if_exist_(if_exist) { |
274 | 4.16k | } |
275 | | |
276 | 4.16k | PgDropTable::~PgDropTable() { |
277 | 4.16k | } |
278 | | |
279 | 3.48k | Status PgDropTable::Exec() { |
280 | 3.48k | Status s = pg_session_->DropTable(table_id_); |
281 | 3.48k | pg_session_->InvalidateTableCache(table_id_, InvalidateOnPgClient::kFalse); |
282 | 3.48k | if (s.ok() || (5 s.IsNotFound()5 && if_exist_2 )) { |
283 | 3.47k | return Status::OK(); |
284 | 3.47k | } |
285 | 5 | return s; |
286 | 3.48k | } |
287 | | |
288 | | //-------------------------------------------------------------------------------------------------- |
289 | | // PgTruncateTable |
290 | | //-------------------------------------------------------------------------------------------------- |
291 | | |
292 | | PgTruncateTable::PgTruncateTable(PgSession::ScopedRefPtr pg_session, |
293 | | const PgObjectId& table_id) |
294 | 624 | : PgDdl(pg_session) { |
295 | 624 | table_id.ToPB(req_.mutable_table_id()); |
296 | 624 | } |
297 | | |
298 | 624 | PgTruncateTable::~PgTruncateTable() { |
299 | 624 | } |
300 | | |
301 | 624 | Status PgTruncateTable::Exec() { |
302 | 624 | return pg_session_->pg_client().TruncateTable(&req_, DdlDeadline()); |
303 | 624 | } |
304 | | |
305 | | //-------------------------------------------------------------------------------------------------- |
306 | | // PgDropIndex |
307 | | //-------------------------------------------------------------------------------------------------- |
308 | | |
309 | | PgDropIndex::PgDropIndex(PgSession::ScopedRefPtr pg_session, |
310 | | const PgObjectId& index_id, |
311 | | bool if_exist) |
312 | 672 | : PgDropTable(pg_session, index_id, if_exist) { |
313 | 672 | } |
314 | | |
315 | 672 | PgDropIndex::~PgDropIndex() { |
316 | 672 | } |
317 | | |
318 | 669 | Status PgDropIndex::Exec() { |
319 | 669 | client::YBTableName indexed_table_name; |
320 | 669 | Status s = pg_session_->DropIndex(table_id_, &indexed_table_name); |
321 | 669 | if (s.ok() || (2 s.IsNotFound()2 && if_exist_0 )) { |
322 | 667 | RSTATUS_DCHECK(!indexed_table_name.empty(), Uninitialized, "indexed_table_name uninitialized"); |
323 | 667 | PgObjectId indexed_table_id(indexed_table_name.table_id()); |
324 | | |
325 | 667 | pg_session_->InvalidateTableCache(table_id_, InvalidateOnPgClient::kFalse); |
326 | 667 | pg_session_->InvalidateTableCache(indexed_table_id, InvalidateOnPgClient::kFalse); |
327 | 667 | return Status::OK(); |
328 | 667 | } |
329 | 2 | return s; |
330 | 669 | } |
331 | | |
332 | | //-------------------------------------------------------------------------------------------------- |
333 | | // PgAlterTable |
334 | | //-------------------------------------------------------------------------------------------------- |
335 | | |
336 | | PgAlterTable::PgAlterTable(PgSession::ScopedRefPtr pg_session, |
337 | | const PgObjectId& table_id) |
338 | 1.71k | : PgDdl(pg_session) { |
339 | 1.71k | table_id.ToPB(req_.mutable_table_id()); |
340 | 1.71k | } |
341 | | |
342 | | Status PgAlterTable::AddColumn(const char *name, |
343 | | const YBCPgTypeEntity *attr_type, |
344 | 238 | int order) { |
345 | 238 | auto& col = *req_.mutable_add_columns()->Add(); |
346 | 238 | col.set_attr_name(name); |
347 | 238 | col.set_attr_ybtype(attr_type->yb_type); |
348 | 238 | col.set_attr_num(order); |
349 | 238 | col.set_attr_pgoid(attr_type->type_oid); |
350 | 238 | return Status::OK(); |
351 | 238 | } |
352 | | |
353 | 17 | Status PgAlterTable::RenameColumn(const char *oldname, const char *newname) { |
354 | 17 | auto& rename = *req_.mutable_rename_columns()->Add(); |
355 | 17 | rename.set_old_name(oldname); |
356 | 17 | rename.set_new_name(newname); |
357 | 17 | return Status::OK(); |
358 | 17 | } |
359 | | |
360 | 408 | Status PgAlterTable::DropColumn(const char *name) { |
361 | 408 | req_.mutable_drop_columns()->Add(name); |
362 | 408 | return Status::OK(); |
363 | 408 | } |
364 | | |
365 | 115 | Status PgAlterTable::RenameTable(const char *db_name, const char *newname) { |
366 | 115 | auto& rename = *req_.mutable_rename_table(); |
367 | 115 | rename.set_database_name(db_name); |
368 | 115 | rename.set_table_name(newname); |
369 | 115 | return Status::OK(); |
370 | 115 | } |
371 | | |
372 | 522 | Status PgAlterTable::Exec() { |
373 | 522 | RETURN_NOT_OK(pg_session_->pg_client().AlterTable(&req_, DdlDeadline())); |
374 | 520 | pg_session_->InvalidateTableCache( |
375 | 520 | PgObjectId::FromPB(req_.table_id()), InvalidateOnPgClient::kFalse); |
376 | 520 | return Status::OK(); |
377 | 522 | } |
378 | | |
379 | 1.71k | PgAlterTable::~PgAlterTable() { |
380 | 1.71k | } |
381 | | |
382 | | } // namespace pggate |
383 | | } // namespace yb |