context.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. #include "context.h"
  2. #include <yql/essentials/providers/common/provider/yql_provider_names.h>
  3. #include <yql/essentials/utils/yql_panic.h>
  4. #include <yql/essentials/utils/yql_paths.h>
  5. #include <util/folder/pathsplit.h>
  6. #include <util/string/join.h>
  7. #include <util/stream/null.h>
  8. #ifdef GetMessage
  9. #undef GetMessage
  10. #endif
  11. using namespace NYql;
  12. namespace NSQLTranslationV1 {
  13. namespace {
  14. TNodePtr AddTablePathPrefix(TContext& ctx, TStringBuf prefixPath, const TDeferredAtom& path) {
  15. if (prefixPath.empty()) {
  16. return path.Build();
  17. }
  18. if (path.GetLiteral()) {
  19. return BuildQuotedAtom(path.Build()->GetPos(), BuildTablePath(prefixPath, *path.GetLiteral()));
  20. }
  21. auto pathNode = path.Build();
  22. pathNode = new TCallNodeImpl(pathNode->GetPos(), "String", { pathNode });
  23. auto prefixNode = BuildLiteralRawString(pathNode->GetPos(), TString(prefixPath));
  24. TNodePtr buildPathNode = new TCallNodeImpl(pathNode->GetPos(), "BuildTablePath", { prefixNode, pathNode });
  25. TDeferredAtom result;
  26. MakeTableFromExpression(ctx.Pos(), ctx, buildPathNode, result);
  27. return result.Build();
  28. }
  29. typedef bool TContext::*TPragmaField;
  30. THashMap<TStringBuf, TPragmaField> CTX_PRAGMA_FIELDS = {
  31. {"AnsiOptionalAs", &TContext::AnsiOptionalAs},
  32. {"WarnOnAnsiAliasShadowing", &TContext::WarnOnAnsiAliasShadowing},
  33. {"PullUpFlatMapOverJoin", &TContext::PragmaPullUpFlatMapOverJoin},
  34. {"FilterPushdownOverJoinOptionalSide", &TContext::FilterPushdownOverJoinOptionalSide},
  35. {"RotateJoinTree", &TContext::RotateJoinTree},
  36. {"DqEngineEnable", &TContext::DqEngineEnable},
  37. {"DqEngineForce", &TContext::DqEngineForce},
  38. {"RegexUseRe2", &TContext::PragmaRegexUseRe2},
  39. {"OrderedColumns", &TContext::OrderedColumns},
  40. {"BogousStarInGroupByOverJoin", &TContext::BogousStarInGroupByOverJoin},
  41. {"CoalesceJoinKeysOnQualifiedAll", &TContext::CoalesceJoinKeysOnQualifiedAll},
  42. {"UnorderedSubqueries", &TContext::UnorderedSubqueries},
  43. {"FlexibleTypes", &TContext::FlexibleTypes},
  44. {"AnsiCurrentRow", &TContext::AnsiCurrentRow},
  45. {"EmitStartsWith", &TContext::EmitStartsWith},
  46. {"AnsiLike", &TContext::AnsiLike},
  47. {"UseBlocks", &TContext::UseBlocks},
  48. {"BlockEngineEnable", &TContext::BlockEngineEnable},
  49. {"BlockEngineForce", &TContext::BlockEngineForce},
  50. {"UnorderedResult", &TContext::UnorderedResult},
  51. {"CompactNamedExprs", &TContext::CompactNamedExprs},
  52. {"ValidateUnusedExprs", &TContext::ValidateUnusedExprs},
  53. {"AnsiImplicitCrossJoin", &TContext::AnsiImplicitCrossJoin},
  54. {"DistinctOverWindow", &TContext::DistinctOverWindow},
  55. {"SeqMode", &TContext::SeqMode},
  56. };
  57. typedef TMaybe<bool> TContext::*TPragmaMaybeField;
  58. THashMap<TStringBuf, TPragmaMaybeField> CTX_PRAGMA_MAYBE_FIELDS = {
  59. {"AnsiRankForNullableKeys", &TContext::AnsiRankForNullableKeys},
  60. {"AnsiInForEmptyOrNullableItemsCollections", &TContext::AnsiInForEmptyOrNullableItemsCollections},
  61. {"EmitAggApply", &TContext::EmitAggApply},
  62. {"CompactGroupBy", &TContext::CompactGroupBy},
  63. };
  64. } // namespace
  65. TContext::TContext(const NSQLTranslation::TTranslationSettings& settings,
  66. const NSQLTranslation::TSQLHints& hints,
  67. TIssues& issues)
  68. : ClusterMapping(settings.ClusterMapping)
  69. , PathPrefix(settings.PathPrefix)
  70. , ClusterPathPrefixes(settings.ClusterPathPrefixes)
  71. , SQLHints(hints)
  72. , Settings(settings)
  73. , Pool(new TMemoryPool(4096))
  74. , Issues(issues)
  75. , IncrementMonCounterFunction(settings.IncrementCounter)
  76. , HasPendingErrors(false)
  77. , DqEngineEnable(Settings.DqDefaultAuto->Allow())
  78. , AnsiQuotedIdentifiers(settings.AnsiLexer)
  79. , BlockEngineEnable(Settings.BlockDefaultAuto->Allow())
  80. {
  81. for (auto lib : settings.Libraries) {
  82. Libraries.emplace(lib, TLibraryStuff());
  83. }
  84. Scoped = MakeIntrusive<TScopedState>();
  85. AllScopes.push_back(Scoped);
  86. Scoped->UnicodeLiterals = settings.UnicodeLiterals;
  87. if (settings.DefaultCluster) {
  88. Scoped->CurrCluster = TDeferredAtom({}, settings.DefaultCluster);
  89. auto provider = GetClusterProvider(settings.DefaultCluster);
  90. YQL_ENSURE(provider);
  91. Scoped->CurrService = *provider;
  92. }
  93. Position.File = settings.File;
  94. for (auto& flag: settings.Flags) {
  95. bool value = true;
  96. TStringBuf key = flag;
  97. auto ptr = CTX_PRAGMA_FIELDS.FindPtr(key);
  98. auto ptrMaybe = CTX_PRAGMA_MAYBE_FIELDS.FindPtr(key);
  99. if (!ptr && !ptrMaybe && key.SkipPrefix("Disable")) {
  100. value = false;
  101. ptr = CTX_PRAGMA_FIELDS.FindPtr(key);
  102. ptrMaybe = CTX_PRAGMA_MAYBE_FIELDS.FindPtr(key);
  103. }
  104. if (ptr) {
  105. this->*(*ptr) = value;
  106. } else if (ptrMaybe) {
  107. this->*(*ptrMaybe) = value;
  108. }
  109. }
  110. DiscoveryMode = (NSQLTranslation::ESqlMode::DISCOVERY == Settings.Mode);
  111. }
  112. TContext::~TContext()
  113. {
  114. for (auto& x: AllScopes) {
  115. x->Clear();
  116. }
  117. }
  118. const NYql::TPosition& TContext::Pos() const {
  119. return Position;
  120. }
  121. TString TContext::MakeName(const TString& name) {
  122. auto iter = GenIndexes.find(name);
  123. if (iter == GenIndexes.end()) {
  124. iter = GenIndexes.emplace(name, 0).first;
  125. }
  126. TStringBuilder str;
  127. str << name << iter->second;
  128. ++iter->second;
  129. return str;
  130. }
  131. void TContext::PushCurrentBlocks(TBlocks* blocks) {
  132. YQL_ENSURE(blocks);
  133. CurrentBlocks.push_back(blocks);
  134. }
  135. void TContext::PopCurrentBlocks() {
  136. YQL_ENSURE(!CurrentBlocks.empty());
  137. CurrentBlocks.pop_back();
  138. }
  139. TBlocks& TContext::GetCurrentBlocks() const {
  140. YQL_ENSURE(!CurrentBlocks.empty());
  141. return *CurrentBlocks.back();
  142. }
  143. IOutputStream& TContext::Error(NYql::TIssueCode code) {
  144. return Error(Pos(), code);
  145. }
  146. IOutputStream& TContext::Error(NYql::TPosition pos, NYql::TIssueCode code) {
  147. HasPendingErrors = true;
  148. return MakeIssue(TSeverityIds::S_ERROR, code, pos);
  149. }
  150. IOutputStream& TContext::Warning(NYql::TPosition pos, NYql::TIssueCode code) {
  151. return MakeIssue(TSeverityIds::S_WARNING, code, pos);
  152. }
  153. IOutputStream& TContext::Info(NYql::TPosition pos) {
  154. return MakeIssue(TSeverityIds::S_INFO, TIssuesIds::INFO, pos);
  155. }
  156. void TContext::SetWarningPolicyFor(NYql::TIssueCode code, NYql::EWarningAction action) {
  157. TString codePattern = ToString(code);
  158. TString actionString = ToString(action);
  159. TWarningRule rule;
  160. TString parseError;
  161. auto parseResult = TWarningRule::ParseFrom(codePattern, actionString, rule, parseError);
  162. YQL_ENSURE(parseResult == TWarningRule::EParseResult::PARSE_OK);
  163. WarningPolicy.AddRule(rule);
  164. }
  165. TVector<NSQLTranslation::TSQLHint> TContext::PullHintForToken(NYql::TPosition tokenPos) {
  166. TVector<NSQLTranslation::TSQLHint> result;
  167. auto it = SQLHints.find(tokenPos);
  168. if (it == SQLHints.end()) {
  169. return result;
  170. }
  171. result = std::move(it->second);
  172. SQLHints.erase(it);
  173. return result;
  174. }
  175. void TContext::WarnUnusedHints() {
  176. if (!SQLHints.empty()) {
  177. // warn about first unused hint
  178. auto firstUnused = SQLHints.begin();
  179. YQL_ENSURE(!firstUnused->second.empty());
  180. const NSQLTranslation::TSQLHint& hint = firstUnused->second.front();
  181. Warning(hint.Pos, TIssuesIds::YQL_UNUSED_HINT) << "Hint " << hint.Name << " will not be used";
  182. }
  183. }
  184. IOutputStream& TContext::MakeIssue(ESeverity severity, TIssueCode code, NYql::TPosition pos) {
  185. if (severity == TSeverityIds::S_WARNING) {
  186. auto action = WarningPolicy.GetAction(code);
  187. if (action == EWarningAction::ERROR) {
  188. severity = TSeverityIds::S_ERROR;
  189. HasPendingErrors = true;
  190. } else if (action == EWarningAction::DISABLE) {
  191. return Cnull;
  192. }
  193. }
  194. // we have the last cell for issue, let's fill it with our internal error
  195. if (severity >= TSeverityIds::S_WARNING) {
  196. const bool aboveHalf = Issues.Size() > Settings.MaxErrors / 2;
  197. if (aboveHalf) {
  198. return Cnull;
  199. }
  200. } else {
  201. if (Settings.MaxErrors == Issues.Size() + 1) {
  202. Issues.AddIssue(TIssue(NYql::TPosition(), TString(TStringBuf("Too many issues"))));
  203. Issues.back().SetCode(UNEXPECTED_ERROR, TSeverityIds::S_ERROR);
  204. }
  205. if (Settings.MaxErrors <= Issues.Size()) {
  206. ythrow NProtoAST::TTooManyErrors() << "Too many issues";
  207. }
  208. }
  209. Issues.AddIssue(TIssue(pos, TString()));
  210. auto& curIssue = Issues.back();
  211. curIssue.Severity = severity;
  212. curIssue.IssueCode = code;
  213. IssueMsgHolder.Reset(new TStringOutput(*Issues.back().MutableMessage()));
  214. return *IssueMsgHolder;
  215. }
  216. bool TContext::IsDynamicCluster(const TDeferredAtom& cluster) const {
  217. const TString* clusterPtr = cluster.GetLiteral();
  218. if (!clusterPtr) {
  219. return false;
  220. }
  221. TString unused;
  222. if (ClusterMapping.GetClusterProvider(*clusterPtr, unused)) {
  223. return false;
  224. }
  225. if (Settings.AssumeYdbOnClusterWithSlash && clusterPtr->StartsWith('/')) {
  226. return false;
  227. }
  228. return !Settings.DynamicClusterProvider.empty();
  229. }
  230. bool TContext::SetPathPrefix(const TString& value, TMaybe<TString> arg) {
  231. if (arg.Defined()) {
  232. if (*arg == YtProviderName
  233. || *arg == KikimrProviderName
  234. || *arg == RtmrProviderName
  235. )
  236. {
  237. ProviderPathPrefixes[*arg] = value;
  238. return true;
  239. }
  240. TString normalizedClusterName;
  241. if (!GetClusterProvider(*arg, normalizedClusterName)) {
  242. Error() << "Unknown cluster or provider: " << *arg;
  243. IncrementMonCounter("sql_errors", "BadPragmaValue");
  244. return false;
  245. }
  246. ClusterPathPrefixes[normalizedClusterName] = value;
  247. } else {
  248. PathPrefix = value;
  249. }
  250. return true;
  251. }
  252. TNodePtr TContext::GetPrefixedPath(const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& path) {
  253. TStringBuf prefixPath = GetPrefixPath(service, cluster);
  254. if (prefixPath) {
  255. return AddTablePathPrefix(*this, prefixPath, path);
  256. }
  257. return path.Build();
  258. }
  259. TStringBuf TContext::GetPrefixPath(const TString& service, const TDeferredAtom& cluster) const {
  260. if (IsDynamicCluster(cluster)) {
  261. return {};
  262. }
  263. auto* clusterPrefix = cluster.GetLiteral()
  264. ? ClusterPathPrefixes.FindPtr(*cluster.GetLiteral())
  265. : nullptr;
  266. if (clusterPrefix && !clusterPrefix->empty()) {
  267. return *clusterPrefix;
  268. } else {
  269. auto* providerPrefix = ProviderPathPrefixes.FindPtr(service);
  270. if (providerPrefix && !providerPrefix->empty()) {
  271. return *providerPrefix;
  272. } else if (!PathPrefix.empty()) {
  273. return PathPrefix;
  274. }
  275. return {};
  276. }
  277. }
  278. TNodePtr TContext::UniversalAlias(const TString& baseName, TNodePtr&& node) {
  279. auto alias = MakeName(baseName);
  280. UniversalAliases.emplace(alias, node);
  281. return BuildAtom(node->GetPos(), alias, TNodeFlags::Default);
  282. }
  283. bool TContext::IsAlreadyDeclared(const TString& varName) const {
  284. return Variables.find(varName) != Variables.end() && !WeakVariables.contains(varName);
  285. }
  286. void TContext::DeclareVariable(const TString& varName, const TPosition& pos, const TNodePtr& typeNode, bool isWeak) {
  287. if (isWeak) {
  288. auto inserted = Variables.emplace(varName, std::make_pair(pos, typeNode));
  289. YQL_ENSURE(inserted.second);
  290. WeakVariables.insert(varName);
  291. } else {
  292. WeakVariables.erase(WeakVariables.find(varName));
  293. Variables[varName] = std::make_pair(pos, typeNode);
  294. }
  295. }
  296. bool TContext::AddExport(TPosition pos, const TString& name) {
  297. if (IsAnonymousName(name)) {
  298. Error(pos) << "Can not export anonymous name " << name;
  299. return false;
  300. }
  301. if (Exports.contains(name)) {
  302. Error(pos) << "Duplicate export symbol: " << name;
  303. return false;
  304. }
  305. if (!Scoped->LookupNode(name)) {
  306. Error(pos) << "Unable to export unknown symbol: " << name;
  307. return false;
  308. }
  309. Exports.emplace(name);
  310. return true;
  311. }
  312. TString TContext::AddImport(const TVector<TString>& modulePath) {
  313. YQL_ENSURE(!modulePath.empty());
  314. TString path = JoinRange("/", modulePath.cbegin(), modulePath.cend());
  315. if (!path.StartsWith('/')) {
  316. path = Settings.FileAliasPrefix + path;
  317. }
  318. auto iter = ImportModuleAliases.find(path);
  319. if (iter == ImportModuleAliases.end()) {
  320. const TString alias = MakeName(TStringBuilder() << modulePath.back() << "_module");
  321. iter = ImportModuleAliases.emplace(path, alias).first;
  322. }
  323. return iter->second;
  324. }
  325. TString TContext::AddSimpleUdf(const TString& udf) {
  326. auto& name = SimpleUdfs[udf];
  327. if (name.empty()) {
  328. name = TStringBuilder() << "Udf" << SimpleUdfs.size();
  329. }
  330. return name;
  331. }
  332. void TContext::SetPackageVersion(const TString& packageName, ui32 version) {
  333. PackageVersions[packageName] = version;
  334. }
  335. void TScopedState::UseCluster(const TString& service, const TDeferredAtom& cluster) {
  336. YQL_ENSURE(!cluster.Empty());
  337. if (cluster.GetLiteral()) {
  338. if (!Local.UsedPlainClusters.insert(*cluster.GetLiteral()).second) {
  339. return;
  340. }
  341. } else {
  342. if (!Local.UsedExprClusters.insert(cluster.Build().Get()).second) {
  343. return;
  344. }
  345. }
  346. Local.UsedClusters.push_back({service, cluster});
  347. }
  348. void TScopedState::AddExprCluster(TNodePtr expr, TContext& ctx) {
  349. auto node = expr.Get();
  350. if (Local.ExprClustersMap.count(node)) {
  351. return;
  352. }
  353. auto name = ctx.MakeName("cluster");
  354. auto wrappedNode = expr->Y("EvaluateAtom", expr);
  355. Local.ExprClustersMap.insert({node, {name, wrappedNode}});
  356. Local.ExprClusters.push_back(expr);
  357. }
  358. const TVector<std::pair<TString, TDeferredAtom>>& TScopedState::GetUsedClusters() {
  359. return Local.UsedClusters;
  360. }
  361. TNodePtr TScopedState::WrapCluster(const TDeferredAtom& cluster, TContext& ctx) {
  362. auto node = cluster.Build();
  363. if (!cluster.GetLiteral()) {
  364. if (ctx.CompactNamedExprs) {
  365. return node->Y("EvaluateAtom", node);
  366. }
  367. AddExprCluster(node, ctx);
  368. auto exprIt = Local.ExprClustersMap.find(node.Get());
  369. YQL_ENSURE(exprIt != Local.ExprClustersMap.end());
  370. return node->AstNode(exprIt->second.first);
  371. }
  372. return node;
  373. }
  374. void TScopedState::Clear() {
  375. *this = TScopedState();
  376. }
  377. TNodePtr TScopedState::LookupNode(const TString& name) {
  378. auto mapIt = NamedNodes.find(name);
  379. if (mapIt == NamedNodes.end()) {
  380. return nullptr;
  381. }
  382. Y_DEBUG_ABORT_UNLESS(!mapIt->second.empty());
  383. mapIt->second.front()->IsUsed = true;
  384. return mapIt->second.front()->Node->Clone();
  385. }
  386. bool TContext::HasNonYtProvider(const ISource& source) const {
  387. TTableList tableList;
  388. source.GetInputTables(tableList);
  389. TSet<TString> clusters;
  390. for (auto& it: tableList) {
  391. if (it.Service != YtProviderName) {
  392. return true;
  393. }
  394. }
  395. for (auto& cl: Scoped->Local.UsedClusters) {
  396. if (cl.first != YtProviderName) {
  397. return true;
  398. }
  399. }
  400. return false;
  401. }
  402. bool TContext::UseUnordered(const ISource& source) const {
  403. return !HasNonYtProvider(source);
  404. }
  405. bool TContext::UseUnordered(const TTableRef& table) const {
  406. return YtProviderName == table.Service;
  407. }
  408. TMaybe<EColumnRefState> GetFunctionArgColumnStatus(TContext& ctx, const TString& module, const TString& func, size_t argIndex) {
  409. static const TSet<TStringBuf> denyForAllArgs = {
  410. "datatype",
  411. "optionaltype",
  412. "listtype",
  413. "streamtype",
  414. "dicttype",
  415. "tupletype",
  416. "resourcetype",
  417. "taggedtype",
  418. "varianttype",
  419. "callabletype",
  420. "optionalitemtype",
  421. "listitemtype",
  422. "streamitemtype",
  423. "dictkeytype",
  424. "dictpayloadtype",
  425. "tupleelementtype",
  426. "structmembertype",
  427. "callableresulttype",
  428. "callableargumenttype",
  429. "variantunderlyingtype",
  430. };
  431. static const TMap<std::pair<TStringBuf, size_t>, EColumnRefState> positionalArgsCustomStatus = {
  432. { {"frombytes", 1}, EColumnRefState::Deny },
  433. { {"enum", 0}, EColumnRefState::Deny },
  434. { {"asenum", 0}, EColumnRefState::Deny },
  435. { {"variant", 1}, EColumnRefState::Deny },
  436. { {"variant", 2}, EColumnRefState::Deny },
  437. { {"asvariant", 1}, EColumnRefState::Deny },
  438. { {"astagged", 1}, EColumnRefState::Deny },
  439. { {"ensuretype", 1}, EColumnRefState::Deny },
  440. { {"ensuretype", 2}, EColumnRefState::Deny },
  441. { {"ensureconvertibleto", 1}, EColumnRefState::Deny },
  442. { {"ensureconvertibleto", 2}, EColumnRefState::Deny },
  443. { {"nothing", 0}, EColumnRefState::Deny },
  444. { {"formattype", 0}, EColumnRefState::Deny },
  445. { {"instanceof", 0}, EColumnRefState::Deny },
  446. { {"pgtype", 0}, EColumnRefState::AsPgType },
  447. { {"pgconst", 0}, EColumnRefState::Deny },
  448. { {"pgconst", 1}, EColumnRefState::AsPgType },
  449. { {"pgcast", 1}, EColumnRefState::AsPgType },
  450. { {"unpickle", 0}, EColumnRefState::Deny },
  451. { {"typehandle", 0}, EColumnRefState::Deny },
  452. { {"listcreate", 0}, EColumnRefState::Deny },
  453. { {"setcreate", 0}, EColumnRefState::Deny },
  454. { {"dictcreate", 0}, EColumnRefState::Deny },
  455. { {"dictcreate", 1}, EColumnRefState::Deny },
  456. { {"weakfield", 1}, EColumnRefState::Deny },
  457. { {"Yson::ConvertTo", 1}, EColumnRefState::Deny },
  458. };
  459. TString normalized;
  460. if (module.empty()) {
  461. normalized = to_lower(func);
  462. } else if (to_upper(module) == "YQL") {
  463. normalized = "YQL::" + func;
  464. } else {
  465. normalized = module + "::" + func;
  466. }
  467. if (normalized == "typeof" && argIndex == 0) {
  468. // TODO: more such cases?
  469. return ctx.GetTopLevelColumnReferenceState();
  470. }
  471. if (denyForAllArgs.contains(normalized)) {
  472. return EColumnRefState::Deny;
  473. }
  474. auto it = positionalArgsCustomStatus.find(std::make_pair(normalized, argIndex));
  475. if (it != positionalArgsCustomStatus.end()) {
  476. return it->second;
  477. }
  478. return {};
  479. }
  480. TTranslation::TTranslation(TContext& ctx)
  481. : Ctx(ctx)
  482. {
  483. }
  484. TContext& TTranslation::Context() {
  485. return Ctx;
  486. }
  487. IOutputStream& TTranslation::Error() {
  488. return Ctx.Error();
  489. }
  490. TNodePtr TTranslation::GetNamedNode(const TString& name) {
  491. if (name == "$_") {
  492. Ctx.Error() << "Unable to reference anonymous name " << name;
  493. return nullptr;
  494. }
  495. auto res = Ctx.Scoped->LookupNode(name);
  496. if (!res) {
  497. Ctx.Error() << "Unknown name: " << name;
  498. }
  499. return SafeClone(res);
  500. }
  501. TString TTranslation::PushNamedNode(TPosition namePos, const TString& name, const TNodeBuilderByName& builder) {
  502. TString resultName = name;
  503. if (IsAnonymousName(name)) {
  504. resultName = "$_yql_anonymous_name_" + ToString(Ctx.AnonymousNameIndex++);
  505. YQL_ENSURE(Ctx.Scoped->NamedNodes.find(resultName) == Ctx.Scoped->NamedNodes.end());
  506. }
  507. auto node = builder(resultName);
  508. Y_DEBUG_ABORT_UNLESS(node);
  509. auto mapIt = Ctx.Scoped->NamedNodes.find(resultName);
  510. if (mapIt == Ctx.Scoped->NamedNodes.end()) {
  511. auto result = Ctx.Scoped->NamedNodes.insert(std::make_pair(resultName, TDeque<TNodeWithUsageInfoPtr>()));
  512. Y_DEBUG_ABORT_UNLESS(result.second);
  513. mapIt = result.first;
  514. }
  515. mapIt->second.push_front(MakeIntrusive<TNodeWithUsageInfo>(node, namePos, Ctx.ScopeLevel));
  516. return resultName;
  517. }
  518. TString TTranslation::PushNamedNode(NYql::TPosition namePos, const TString &name, NSQLTranslationV1::TNodePtr node) {
  519. return PushNamedNode(namePos, name, [node](const TString&) { return node; });
  520. }
  521. TString TTranslation::PushNamedAtom(TPosition namePos, const TString& name) {
  522. auto buildAtom = [namePos](const TString& resultName) {
  523. return BuildAtom(namePos, resultName);
  524. };
  525. return PushNamedNode(namePos, name, buildAtom);
  526. }
  527. void TTranslation::PopNamedNode(const TString& name) {
  528. auto mapIt = Ctx.Scoped->NamedNodes.find(name);
  529. Y_DEBUG_ABORT_UNLESS(mapIt != Ctx.Scoped->NamedNodes.end());
  530. Y_DEBUG_ABORT_UNLESS(mapIt->second.size() > 0);
  531. auto& top = mapIt->second.front();
  532. if (!top->IsUsed && !Ctx.HasPendingErrors && !name.StartsWith("$_")) {
  533. Ctx.Warning(top->NamePos, TIssuesIds::YQL_UNUSED_SYMBOL) << "Symbol " << name << " is not used";
  534. }
  535. mapIt->second.pop_front();
  536. if (mapIt->second.empty()) {
  537. Ctx.Scoped->NamedNodes.erase(mapIt);
  538. }
  539. }
  540. void TTranslation::WarnUnusedNodes() const {
  541. if (Ctx.HasPendingErrors) {
  542. // result is not reliable in this case
  543. return;
  544. }
  545. for (const auto& [name, items]: Ctx.Scoped->NamedNodes) {
  546. if (name.StartsWith("$_")) {
  547. continue;
  548. }
  549. for (const auto& item : items) {
  550. if (!item->IsUsed && item->Level == Ctx.ScopeLevel) {
  551. Ctx.Warning(item->NamePos, TIssuesIds::YQL_UNUSED_SYMBOL) << "Symbol " << name << " is not used";
  552. }
  553. }
  554. }
  555. }
  556. TString GetDescription(const google::protobuf::Message& node, const google::protobuf::FieldDescriptor* d) {
  557. const auto& field = node.GetReflection()->GetMessage(node, d);
  558. return field.GetReflection()->GetString(field, d->message_type()->FindFieldByName("Descr"));
  559. }
  560. TString TTranslation::AltDescription(const google::protobuf::Message& node, ui32 altCase, const google::protobuf::Descriptor* descr) const {
  561. return GetDescription(node, descr->FindFieldByNumber(altCase));
  562. }
  563. void TTranslation::AltNotImplemented(const TString& ruleName, ui32 altCase, const google::protobuf::Message& node, const google::protobuf::Descriptor* descr) {
  564. Error() << ruleName << ": alternative is not implemented yet: " << AltDescription(node, altCase, descr);
  565. }
  566. } // namespace NSQLTranslationV1