context.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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 <util/folder/pathsplit.h>
  5. #include <util/string/join.h>
  6. #include <util/stream/null.h>
  7. #ifdef GetMessage
  8. #undef GetMessage
  9. #endif
  10. using namespace NYql;
  11. namespace NSQLTranslationV0 {
  12. namespace {
  13. TNodePtr AddTablePathPrefix(TContext &ctx, TStringBuf prefixPath, const TDeferredAtom& path) {
  14. Y_UNUSED(ctx);
  15. if (prefixPath.empty()) {
  16. return path.Build();
  17. }
  18. YQL_ENSURE(path.GetLiteral(), "TODO support prefix for deferred atoms");
  19. prefixPath.SkipPrefix("//");
  20. TPathSplitUnix prefixPathSplit(prefixPath);
  21. TPathSplitUnix pathSplit(*path.GetLiteral());
  22. if (pathSplit.IsAbsolute) {
  23. return path.Build();
  24. }
  25. return BuildQuotedAtom(path.Build()->GetPos(), prefixPathSplit.AppendMany(pathSplit.begin(), pathSplit.end()).Reconstruct());
  26. }
  27. typedef bool TContext::*TPragmaField;
  28. THashMap<TStringBuf, TPragmaField> CTX_PRAGMA_FIELDS = {
  29. {"PullUpFlatMapOverJoin", &TContext::PragmaPullUpFlatMapOverJoin},
  30. };
  31. } // namespace
  32. TContext::TContext(const NSQLTranslation::TTranslationSettings& settings,
  33. TIssues& issues)
  34. : ClusterMapping(settings.ClusterMapping)
  35. , PathPrefix(settings.PathPrefix)
  36. , ClusterPathPrefixes(settings.ClusterPathPrefixes)
  37. , Settings(settings)
  38. , Pool(new TMemoryPool(4096))
  39. , Issues(issues)
  40. , IncrementMonCounterFunction(settings.IncrementCounter)
  41. , CurrCluster(settings.DefaultCluster)
  42. , HasPendingErrors(false)
  43. , Libraries(settings.Libraries)
  44. {
  45. Position.File = settings.File;
  46. for (auto& flag: settings.Flags) {
  47. bool value = true;
  48. TStringBuf key = flag;
  49. auto ptr = CTX_PRAGMA_FIELDS.FindPtr(key);
  50. if (!ptr && key.SkipPrefix("Disable")) {
  51. value = false;
  52. ptr = CTX_PRAGMA_FIELDS.FindPtr(key);
  53. }
  54. if (ptr) {
  55. this->*(*ptr) = value;
  56. }
  57. }
  58. }
  59. TContext::~TContext()
  60. {
  61. }
  62. const NYql::TPosition& TContext::Pos() const {
  63. return Position;
  64. }
  65. TString TContext::MakeName(const TString& name) {
  66. auto iter = GenIndexes.find(name);
  67. if (iter == GenIndexes.end()) {
  68. iter = GenIndexes.emplace(name, 0).first;
  69. }
  70. TStringBuilder str;
  71. str << name << iter->second;
  72. ++iter->second;
  73. return str;
  74. }
  75. IOutputStream& TContext::Error() {
  76. return Error(Pos());
  77. }
  78. IOutputStream& TContext::Error(NYql::TPosition pos) {
  79. HasPendingErrors = true;
  80. return MakeIssue(TSeverityIds::S_ERROR, TIssuesIds::DEFAULT_ERROR, pos);
  81. }
  82. IOutputStream& TContext::Warning(NYql::TPosition pos, NYql::TIssueCode code) {
  83. return MakeIssue(TSeverityIds::S_WARNING, code, pos);
  84. }
  85. IOutputStream& TContext::Info(NYql::TPosition pos) {
  86. return MakeIssue(TSeverityIds::S_INFO, TIssuesIds::INFO, pos);
  87. }
  88. IOutputStream& TContext::MakeIssue(ESeverity severity, TIssueCode code, NYql::TPosition pos) {
  89. if (severity == TSeverityIds::S_WARNING) {
  90. auto action = WarningPolicy.GetAction(code);
  91. if (action == EWarningAction::ERROR) {
  92. severity = TSeverityIds::S_ERROR;
  93. HasPendingErrors = true;
  94. } else if (action == EWarningAction::DISABLE) {
  95. return Cnull;
  96. }
  97. }
  98. // we have the last cell for issue, let's fill it with our internal error
  99. if (severity >= TSeverityIds::S_WARNING) {
  100. const bool aboveHalf = Issues.Size() > Settings.MaxErrors / 2;
  101. if (aboveHalf) {
  102. return Cnull;
  103. }
  104. } else {
  105. if (Settings.MaxErrors == Issues.Size() + 1) {
  106. Issues.AddIssue(TIssue(NYql::TPosition(), TString(TStringBuf("Too many issues"))));
  107. Issues.back().SetCode(UNEXPECTED_ERROR, TSeverityIds::S_ERROR);
  108. }
  109. if (Settings.MaxErrors <= Issues.Size()) {
  110. ythrow NProtoAST::TTooManyErrors() << "Too many issues";
  111. }
  112. }
  113. Issues.AddIssue(TIssue(pos, TString()));
  114. auto& curIssue = Issues.back();
  115. curIssue.Severity = severity;
  116. curIssue.IssueCode = code;
  117. IssueMsgHolder.Reset(new TStringOutput(*Issues.back().MutableMessage()));
  118. return *IssueMsgHolder;
  119. }
  120. bool TContext::SetPathPrefix(const TString& value, TMaybe<TString> arg) {
  121. if (arg.Defined()) {
  122. if (*arg == YtProviderName
  123. || *arg == KikimrProviderName
  124. || *arg == RtmrProviderName
  125. )
  126. {
  127. ProviderPathPrefixes[*arg] = value;
  128. return true;
  129. }
  130. TString normalizedClusterName;
  131. if (!GetClusterProvider(*arg, normalizedClusterName)) {
  132. Error() << "Unknown cluster or provider: " << *arg;
  133. IncrementMonCounter("sql_errors", "BadPragmaValue");
  134. return false;
  135. }
  136. ClusterPathPrefixes[normalizedClusterName] = value;
  137. } else {
  138. PathPrefix = value;
  139. }
  140. return true;
  141. }
  142. TNodePtr TContext::GetPrefixedPath(const TString& cluster, const TDeferredAtom& path) {
  143. auto* clusterPrefix = ClusterPathPrefixes.FindPtr(cluster);
  144. if (clusterPrefix && !clusterPrefix->empty()) {
  145. return AddTablePathPrefix(*this, *clusterPrefix, path);
  146. } else {
  147. auto provider = GetClusterProvider(cluster);
  148. YQL_ENSURE(provider.Defined());
  149. auto* providerPrefix = ProviderPathPrefixes.FindPtr(*provider);
  150. if (providerPrefix && !providerPrefix->empty()) {
  151. return AddTablePathPrefix(*this, *providerPrefix, path);
  152. } else if (!PathPrefix.empty()) {
  153. return AddTablePathPrefix(*this, PathPrefix, path);
  154. }
  155. return path.Build();
  156. }
  157. }
  158. TNodePtr TContext::UniversalAlias(const TString& baseName, TNodePtr&& node) {
  159. auto alias = MakeName(baseName);
  160. UniversalAliases.emplace(alias, node);
  161. return BuildAtom(node->GetPos(), alias, TNodeFlags::Default);
  162. }
  163. TString TContext::HasBlockShortcut(const TNodePtr& baseNode) {
  164. YQL_ENSURE(ShortcutCurrentLevel, "Push\\Pop shortcuts not balanced");
  165. auto shortIter = Shortcuts.find(ShortcutCurrentLevel);
  166. if (shortIter == Shortcuts.end()) {
  167. return {};
  168. }
  169. const auto& baseMap = shortIter->second.BaseMap;
  170. const auto iter = baseMap.find(baseNode.Get());
  171. if (iter == baseMap.end()) {
  172. return {};
  173. }
  174. return iter->second;
  175. }
  176. TString TContext::RegisterBlockShortcut(const TNodePtr& baseNode, const TNodePtr& node, const TString& baseName) {
  177. YQL_ENSURE(ShortcutCurrentLevel, "Push\\Pop shortcuts not balanced");
  178. YQL_ENSURE(node->HasState(ENodeState::Initialized));
  179. YQL_ENSURE(!HasBlockShortcut(baseNode));
  180. const auto alias = MakeName(baseName);
  181. auto& shortcuts = Shortcuts[ShortcutCurrentLevel];
  182. shortcuts.BaseMap.emplace(baseNode.Get(), alias);
  183. shortcuts.Goal.emplace_back(std::make_pair(alias, node));
  184. return alias;
  185. }
  186. TNodePtr TContext::GetBlockShortcut(const TString& alias) const {
  187. YQL_ENSURE(ShortcutCurrentLevel, "Push\\Pop shortcuts not balanced");
  188. auto shortIter = Shortcuts.find(ShortcutCurrentLevel);
  189. YQL_ENSURE(shortIter != Shortcuts.end(), "Expected block shortcut exist");
  190. for (const auto& shortcutPair: shortIter->second.Goal) {
  191. if (shortcutPair.first == alias) {
  192. return shortcutPair.second;
  193. }
  194. }
  195. Y_ABORT("Expected block shortcut exist");
  196. }
  197. TNodePtr TContext::GroundBlockShortcuts(NYql::TPosition pos, TNodePtr groundList) {
  198. YQL_ENSURE(ShortcutCurrentLevel, "Push\\Pop shortcuts not balanced");
  199. auto shortIter = Shortcuts.find(ShortcutCurrentLevel);
  200. TNodePtr result = groundList;
  201. if (shortIter != Shortcuts.end()) {
  202. if (!result) {
  203. result = new TAstListNodeImpl(pos);
  204. }
  205. for (const auto& shortcutPair: shortIter->second.Goal) {
  206. result = result->L(result, result->Y("let", shortcutPair.first, shortcutPair.second));
  207. }
  208. }
  209. PopBlockShortcuts();
  210. return result;
  211. }
  212. TNodePtr TContext::GroundBlockShortcutsForExpr(const TNodePtr& expr) {
  213. YQL_ENSURE(ShortcutCurrentLevel, "Push\\Pop shortcuts not balanced");
  214. YQL_ENSURE(expr);
  215. auto ground = GroundBlockShortcuts(expr->GetPos());
  216. return GroundWithExpr(ground, expr);
  217. }
  218. void TContext::PushBlockShortcuts() {
  219. ++ShortcutCurrentLevel;
  220. }
  221. void TContext::PopBlockShortcuts() {
  222. YQL_ENSURE(ShortcutCurrentLevel, "Push\\Pop shortcuts not balanced");
  223. auto shortcuts = Shortcuts.find(ShortcutCurrentLevel);
  224. --ShortcutCurrentLevel;
  225. if (shortcuts != Shortcuts.end()) {
  226. Shortcuts.erase(shortcuts);
  227. }
  228. }
  229. bool TContext::DeclareVariable(const TString& varName, const TNodePtr& typeNode) {
  230. Variables.emplace(varName, typeNode);
  231. return true;
  232. }
  233. bool TContext::AddExports(const TVector<TString>& symbols) {
  234. for (const auto& symbol: symbols) {
  235. if (Exports.contains(symbol)) {
  236. Error() << "Duplicate export symbol: " << symbol;
  237. return false;
  238. }
  239. if (NamedNodes.find(symbol) == NamedNodes.end()) {
  240. Error() << "Unknown named node: " << symbol;
  241. return false;
  242. }
  243. Exports.emplace(symbol);
  244. }
  245. return true;
  246. }
  247. TString TContext::AddImport(const TVector<TString>& modulePath) {
  248. YQL_ENSURE(!modulePath.empty());
  249. const TString path = JoinRange("/", modulePath.cbegin(), modulePath.cend());
  250. auto iter = ImportModuleAliases.find(path);
  251. if (iter == ImportModuleAliases.end()) {
  252. const TString alias = MakeName(TStringBuilder() << modulePath.back() << "_module");
  253. iter = ImportModuleAliases.emplace(path, alias).first;
  254. }
  255. return iter->second;
  256. }
  257. TString TContext::AddSimpleUdf(const TString& udf) {
  258. auto& name = SimpleUdfs[udf];
  259. if (name.empty()) {
  260. name = TStringBuilder() << "Udf" << SimpleUdfs.size();
  261. }
  262. return name;
  263. }
  264. TString TContext::GetServiceName(const ISource& source) const {
  265. TTableList tableList;
  266. source.GetInputTables(tableList);
  267. TSet<TString> clusters;
  268. for (auto& it: tableList) {
  269. if (auto provider = GetClusterProvider(it.Cluster)) {
  270. return *provider;
  271. }
  272. }
  273. for (auto& cluster: UsedClusters) {
  274. if (auto provider = GetClusterProvider(cluster)) {
  275. return *provider;
  276. }
  277. }
  278. return CurrCluster.empty() ? TString() : GetClusterProvider(CurrCluster).GetOrElse(TString());
  279. }
  280. bool TContext::UseUnordered(const ISource& source) const {
  281. return YtProviderName == to_lower(GetServiceName(source));
  282. }
  283. bool TContext::UseUnordered(const TTableRef& table) const {
  284. return YtProviderName == to_lower(GetClusterProvider(table.Cluster).GetOrElse(TString()));
  285. }
  286. TTranslation::TTranslation(TContext& ctx)
  287. : Ctx(ctx)
  288. {
  289. }
  290. TContext& TTranslation::Context() {
  291. return Ctx;
  292. }
  293. IOutputStream& TTranslation::Error() {
  294. return Ctx.Error();
  295. }
  296. TNodePtr TTranslation::GetNamedNode(const TString& name) {
  297. auto mapIt = Ctx.NamedNodes.find(name);
  298. if (mapIt == Ctx.NamedNodes.end()) {
  299. Ctx.Error() << "Unknown name: " << name;
  300. return nullptr;
  301. }
  302. Y_DEBUG_ABORT_UNLESS(!mapIt->second.empty());
  303. return mapIt->second.top()->Clone();
  304. }
  305. void TTranslation::PushNamedNode(const TString& name, TNodePtr node) {
  306. Y_DEBUG_ABORT_UNLESS(node);
  307. auto mapIt = Ctx.NamedNodes.find(name);
  308. if (mapIt == Ctx.NamedNodes.end()) {
  309. auto result = Ctx.NamedNodes.insert(std::make_pair(name, TStack<TNodePtr>()));
  310. Y_DEBUG_ABORT_UNLESS(result.second);
  311. mapIt = result.first;
  312. }
  313. mapIt->second.push(node);
  314. }
  315. void TTranslation::PopNamedNode(const TString& name) {
  316. auto mapIt = Ctx.NamedNodes.find(name);
  317. Y_DEBUG_ABORT_UNLESS(mapIt != Ctx.NamedNodes.end());
  318. Y_DEBUG_ABORT_UNLESS(mapIt->second.size() > 0);
  319. mapIt->second.pop();
  320. if (mapIt->second.empty()) {
  321. Ctx.NamedNodes.erase(mapIt);
  322. }
  323. }
  324. TString GetDescription(const google::protobuf::Message& node, const google::protobuf::FieldDescriptor* d) {
  325. const auto& field = node.GetReflection()->GetMessage(node, d);
  326. return field.GetReflection()->GetString(field, d->message_type()->FindFieldByName("Descr"));
  327. }
  328. TString TTranslation::AltDescription(const google::protobuf::Message& node, ui32 altCase, const google::protobuf::Descriptor* descr) const {
  329. return GetDescription(node, descr->FindFieldByNumber(altCase));
  330. }
  331. void TTranslation::AltNotImplemented(const TString& ruleName, ui32 altCase, const google::protobuf::Message& node, const google::protobuf::Descriptor* descr) {
  332. Error() << ruleName << ": alternative is not implemented yet: " << GetDescription(node, descr->FindFieldByNumber(altCase));
  333. }
  334. } // namespace NSQLTranslationV0