@@ -49,6 +49,7 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
49
49
EvResult = EventSpaceBegin (TEvents::ES_PRIVATE),
50
50
EvMakeTempDirResult,
51
51
EvMakeSessionDirResult,
52
+ EvMakeCTASDirResult,
52
53
};
53
54
54
55
struct TEvResult : public TEventLocal <TEvResult, EEv::EvResult> {
@@ -62,6 +63,10 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
62
63
struct TEvMakeSessionDirResult : public TEventLocal <TEvMakeSessionDirResult, EEv::EvMakeSessionDirResult> {
63
64
IKqpGateway::TGenericResult Result;
64
65
};
66
+
67
+ struct TEvMakeCTASDirResult : public TEventLocal <TEvMakeCTASDirResult, EEv::EvMakeCTASDirResult> {
68
+ IKqpGateway::TGenericResult Result;
69
+ };
65
70
};
66
71
public:
67
72
static constexpr NKikimrServices::TActivity::EType ActorActivityType () {
@@ -71,7 +76,7 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
71
76
TKqpSchemeExecuter (
72
77
TKqpPhyTxHolder::TConstPtr phyTx, NKikimrKqp::EQueryType queryType, const TActorId& target, const TMaybe<TString>& requestType,
73
78
const TString& database, TIntrusiveConstPtr<NACLib::TUserToken> userToken, const TString& clientAddress,
74
- bool temporary, TString sessionId, TIntrusivePtr<TUserRequestContext> ctx,
79
+ bool temporary, bool isCreateTableAs, TString sessionId, TIntrusivePtr<TUserRequestContext> ctx,
75
80
const TActorId& kqpTempTablesAgentActor)
76
81
: PhyTx(phyTx)
77
82
, QueryType(queryType)
@@ -80,6 +85,7 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
80
85
, UserToken(userToken)
81
86
, ClientAddress(clientAddress)
82
87
, Temporary(temporary)
88
+ , IsCreateTableAs(isCreateTableAs)
83
89
, SessionId(sessionId)
84
90
, RequestContext(std::move(ctx))
85
91
, RequestType(requestType)
@@ -175,6 +181,128 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
175
181
});
176
182
}
177
183
184
+ void FindWorkingDirForCTAS () {
185
+ const auto & schemeOp = PhyTx->GetSchemeOperation ();
186
+
187
+ AFL_ENSURE (schemeOp.GetOperationCase () == NKqpProto::TKqpSchemeOperation::kAlterTable );
188
+ const auto & alterTableModifyScheme = schemeOp.GetAlterTable ();
189
+ AFL_ENSURE (alterTableModifyScheme.GetOperationType () == NKikimrSchemeOp::ESchemeOpMoveTable);
190
+
191
+ const auto dirPath = SplitPath (alterTableModifyScheme.GetMoveTable ().GetDstPath ());
192
+ AFL_ENSURE (dirPath.size () >= 2 );
193
+
194
+ auto request = MakeHolder<NSchemeCache::TSchemeCacheNavigate>();
195
+ TVector<TString> path;
196
+
197
+ for (const auto & part : dirPath) {
198
+ path.emplace_back (part);
199
+
200
+ NSchemeCache::TSchemeCacheNavigate::TEntry entry;
201
+ entry.Path = path;
202
+ entry.Operation = NSchemeCache::TSchemeCacheNavigate::EOp::OpPath;
203
+ entry.SyncVersion = true ;
204
+ entry.RedirectRequired = false ;
205
+ request->ResultSet .emplace_back (entry);
206
+ }
207
+ request->ResultSet .pop_back ();
208
+
209
+ auto ev = std::make_unique<TEvTxProxySchemeCache::TEvNavigateKeySet>(request);
210
+
211
+ Send (MakeSchemeCacheID (), ev.release ());
212
+ Become (&TKqpSchemeExecuter::ExecuteState);
213
+ }
214
+
215
+ void HandleCTASWorkingDir (TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) {
216
+ const auto & resultSet = ev->Get ()->Request ->ResultSet ;
217
+
218
+ const TVector<TString>* workingDir = nullptr ;
219
+ for (auto it = resultSet.rbegin (); it != resultSet.rend (); ++it) {
220
+ if (it->Status == NSchemeCache::TSchemeCacheNavigate::EStatus::Ok) {
221
+ workingDir = &it->Path ;
222
+ break ;
223
+ }
224
+ }
225
+
226
+ const auto & schemeOp = PhyTx->GetSchemeOperation ();
227
+ AFL_ENSURE (schemeOp.GetOperationCase () == NKqpProto::TKqpSchemeOperation::kAlterTable );
228
+ const auto & alterTableModifyScheme = schemeOp.GetAlterTable ();
229
+ AFL_ENSURE (alterTableModifyScheme.GetOperationType () == NKikimrSchemeOp::ESchemeOpMoveTable);
230
+ const auto dirPath = SplitPath (alterTableModifyScheme.GetMoveTable ().GetDstPath ());
231
+
232
+ if (!workingDir) {
233
+ const auto errText = TStringBuilder ()
234
+ << " Cannot resolve working dir."
235
+ << " path# " << JoinPath (dirPath);
236
+ LOG_D (errText);
237
+
238
+ const auto issue = MakeIssue (NKikimrIssues::TIssuesIds::RESOLVE_LOOKUP_ERROR, errText);
239
+ return ReplyErrorAndDie (Ydb::StatusIds::BAD_REQUEST, issue);
240
+ }
241
+ AFL_ENSURE (!workingDir->empty () && workingDir->size () < dirPath.size ());
242
+ AFL_ENSURE (std::equal (
243
+ workingDir->begin (),
244
+ workingDir->end (),
245
+ dirPath.begin (),
246
+ dirPath.begin () + workingDir->size ()));
247
+
248
+ CreateCTASDirectory (
249
+ TConstArrayRef<TString>(
250
+ workingDir->begin (),
251
+ workingDir->end ()),
252
+ TConstArrayRef<TString>(
253
+ dirPath.begin () + workingDir->size (),
254
+ dirPath.end ()));
255
+ }
256
+
257
+ void CreateCTASDirectory (const TConstArrayRef<TString> workingDir, const TConstArrayRef<TString> dirPath) {
258
+ AFL_ENSURE (!dirPath.empty ());
259
+ AFL_ENSURE (!workingDir.empty ());
260
+
261
+ auto ev = MakeHolder<TEvTxUserProxy::TEvProposeTransaction>();
262
+ auto & record = ev->Record ;
263
+
264
+ auto actorSystem = TActivationContext::ActorSystem ();
265
+ auto selfId = SelfId ();
266
+
267
+ record.SetDatabaseName (Database);
268
+ if (UserToken) {
269
+ record.SetUserToken (UserToken->GetSerializedToken ());
270
+ }
271
+ record.SetPeerName (ClientAddress);
272
+
273
+ const auto & schemeOp = PhyTx->GetSchemeOperation ();
274
+
275
+ AFL_ENSURE (schemeOp.GetOperationCase () == NKqpProto::TKqpSchemeOperation::kAlterTable );
276
+ const auto & alterTableModifyScheme = schemeOp.GetAlterTable ();
277
+ AFL_ENSURE (alterTableModifyScheme.GetOperationType () == NKikimrSchemeOp::ESchemeOpMoveTable);
278
+
279
+ if (dirPath.size () == 1 ) {
280
+ auto ev = MakeHolder<TEvPrivate::TEvMakeCTASDirResult>();
281
+ ev->Result .SetSuccess ();
282
+ actorSystem->Send (selfId, ev.Release ());
283
+ Become (&TKqpSchemeExecuter::ExecuteState);
284
+ return ;
285
+ }
286
+
287
+ auto * modifyScheme = record.MutableTransaction ()->MutableModifyScheme ();
288
+ modifyScheme->SetWorkingDir (CombinePath (workingDir.begin (), workingDir.end ()));
289
+ modifyScheme->SetOperationType (NKikimrSchemeOp::EOperationType::ESchemeOpMkDir);
290
+
291
+ auto * makeDir = modifyScheme->MutableMkDir ();
292
+ makeDir->SetName (CombinePath (dirPath.begin (), std::prev (dirPath.end ()), false ));
293
+
294
+ auto promise = NewPromise<IKqpGateway::TGenericResult>();
295
+ IActor* requestHandler = new TSchemeOpRequestHandler (ev.Release (), promise, false );
296
+ RegisterWithSameMailbox (requestHandler);
297
+
298
+ promise.GetFuture ().Subscribe ([actorSystem, selfId](const TFuture<IKqpGateway::TGenericResult>& future) {
299
+ auto ev = MakeHolder<TEvPrivate::TEvMakeCTASDirResult>();
300
+ ev->Result = future.GetValue ();
301
+ actorSystem->Send (selfId, ev.Release ());
302
+ });
303
+ Become (&TKqpSchemeExecuter::ExecuteState);
304
+ }
305
+
178
306
void MakeSchemeOperationRequest () {
179
307
using TRequest = TEvTxUserProxy::TEvProposeTransaction;
180
308
@@ -604,6 +732,8 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
604
732
const auto & schemeOp = PhyTx->GetSchemeOperation ();
605
733
if (schemeOp.GetObjectType ()) {
606
734
MakeObjectRequest ();
735
+ } else if (IsCreateTableAs && schemeOp.GetOperationCase () == NKqpProto::TKqpSchemeOperation::kAlterTable ) {
736
+ FindWorkingDirForCTAS ();
607
737
} else {
608
738
if (Temporary) {
609
739
CreateTmpDirectory ();
@@ -620,6 +750,7 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
620
750
hFunc (TEvPrivate::TEvResult, HandleExecute);
621
751
hFunc (TEvPrivate::TEvMakeTempDirResult, Handle);
622
752
hFunc (TEvPrivate::TEvMakeSessionDirResult, Handle);
753
+ hFunc (TEvPrivate::TEvMakeCTASDirResult, Handle);
623
754
hFunc (TEvKqp::TEvAbortExecution, HandleAbortExecution);
624
755
hFunc (TEvTxUserProxy::TEvAllocateTxIdResult, Handle);
625
756
hFunc (TEvTxProxySchemeCache::TEvNavigateKeySetResult, Handle);
@@ -669,6 +800,15 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
669
800
MakeSchemeOperationRequest ();
670
801
}
671
802
803
+ void Handle (TEvPrivate::TEvMakeCTASDirResult::TPtr& result) {
804
+ if (!result->Get ()->Result .Success ()) {
805
+ InternalError (TStringBuilder ()
806
+ << " Error creating directory:"
807
+ << result->Get ()->Result .Issues ().ToString (true ));
808
+ }
809
+ MakeSchemeOperationRequest ();
810
+ }
811
+
672
812
void Handle (TEvTxUserProxy::TEvAllocateTxIdResult::TPtr& ev) {
673
813
const auto * msg = ev->Get ();
674
814
TxId = msg->TxId ;
@@ -713,6 +853,14 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
713
853
714
854
NSchemeCache::TSchemeCacheNavigate* resp = ev->Get ()->Request .Get ();
715
855
856
+ if (IsCreateTableAs) {
857
+ AFL_ENSURE (std::all_of (resp->ResultSet .begin (), resp->ResultSet .end (), [](const auto & entry) {
858
+ return entry.Operation == NSchemeCache::TSchemeCacheNavigate::OpPath;
859
+ }));
860
+ HandleCTASWorkingDir (ev);
861
+ return ;
862
+ }
863
+
716
864
if (resp->ErrorCount > 0 || resp->ResultSet .empty ()) {
717
865
TStringBuilder builder;
718
866
builder << " Unable to navigate:" ;
@@ -728,6 +876,8 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
728
876
return ReplyErrorAndDie (Ydb::StatusIds::SCHEME_ERROR, NYql::TIssue (error));
729
877
}
730
878
879
+ AFL_ENSURE (resp->ResultSet .size () <= 2 );
880
+
731
881
if (UserToken && !UserToken->GetSerializedToken ().empty () && !CheckAlterAccess (*UserToken, resp)) {
732
882
LOG_E (" Access check failed" );
733
883
return ReplyErrorAndDie (Ydb::StatusIds::UNAUTHORIZED, NYql::TIssue (" Unauthorized" ));
@@ -941,6 +1091,7 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
941
1091
const TString ClientAddress;
942
1092
std::unique_ptr<TEvKqpExecuter::TEvTxResponse> ResponseEv;
943
1093
bool Temporary;
1094
+ bool IsCreateTableAs;
944
1095
TString SessionId;
945
1096
ui64 TxId = 0 ;
946
1097
TActorId SchemePipeActorId_;
@@ -955,12 +1106,13 @@ class TKqpSchemeExecuter : public TActorBootstrapped<TKqpSchemeExecuter> {
955
1106
IActor* CreateKqpSchemeExecuter (
956
1107
TKqpPhyTxHolder::TConstPtr phyTx, NKikimrKqp::EQueryType queryType, const TActorId& target,
957
1108
const TMaybe<TString>& requestType, const TString& database,
958
- TIntrusiveConstPtr<NACLib::TUserToken> userToken, const TString& clientAddress, bool temporary, TString sessionId,
959
- TIntrusivePtr<TUserRequestContext> ctx, const TActorId& kqpTempTablesAgentActor)
1109
+ TIntrusiveConstPtr<NACLib::TUserToken> userToken, const TString& clientAddress,
1110
+ bool temporary, bool isCreateTableAs,
1111
+ TString sessionId, TIntrusivePtr<TUserRequestContext> ctx, const TActorId& kqpTempTablesAgentActor)
960
1112
{
961
1113
return new TKqpSchemeExecuter (
962
1114
phyTx, queryType, target, requestType, database, userToken, clientAddress,
963
- temporary, sessionId, std::move (ctx), kqpTempTablesAgentActor);
1115
+ temporary, isCreateTableAs, sessionId, std::move (ctx), kqpTempTablesAgentActor);
964
1116
}
965
1117
966
1118
} // namespace NKikimr::NKqp
0 commit comments