| 731 | |
| 732 | |
| 733 | StatementGenerator::FromSourceInfo StatementGenerator::joinedTableOrFunction( |
| 734 | RandomGenerator & rg, const String & rel_name, const uint32_t allowed_clauses, const bool under_remote, TableOrFunction * tof) |
| 735 | { |
| 736 | const SQLTable * t = nullptr; |
| 737 | const SQLView * v = nullptr; |
| 738 | |
| 739 | const auto has_table_lambda = getQueryTableLambda<TableRequirement::NoRequirement>(); |
| 740 | const auto has_mergetree_table_lambda = getQueryTableLambda<TableRequirement::RequireMergeTree>(); |
| 741 | const auto has_replaceable_table_lambda = getQueryTableLambda<TableRequirement::RequireReplaceable>(); |
| 742 | const auto has_view_lambda |
| 743 | = [&](const SQLView & vv) { return vv.isAttached() && (vv.is_deterministic || this->allow_not_deterministic); }; |
| 744 | const auto has_dictionary_lambda |
| 745 | = [&](const SQLDictionary & d) { return d.isAttached() && (d.is_deterministic || this->allow_not_deterministic); }; |
| 746 | |
| 747 | const bool has_table = collectionHas<SQLTable>(has_table_lambda); |
| 748 | const bool has_mergetree_table = collectionHas<SQLTable>(has_mergetree_table_lambda); |
| 749 | const bool has_replaceable_table = collectionHas<SQLTable>(has_replaceable_table_lambda); |
| 750 | const bool has_view = collectionHas<SQLView>(has_view_lambda); |
| 751 | const bool has_dictionary = collectionHas<SQLDictionary>(has_dictionary_lambda); |
| 752 | const bool can_recurse = this->depth < this->fc.max_depth && this->width < this->fc.max_width; |
| 753 | |
| 754 | /// queryMask[static_cast<size_t>(QueryOp::DerivatedTable)] = true; |
| 755 | queryMask[static_cast<size_t>(QueryOp::CTE)] = !under_remote && !this->ctes.empty(); |
| 756 | queryMask[static_cast<size_t>(QueryOp::Table)] = has_table; |
| 757 | queryMask[static_cast<size_t>(QueryOp::View)] = this->peer_query != PeerQuery::ClickHouseOnly && has_view; |
| 758 | queryMask[static_cast<size_t>(QueryOp::RemoteUDF)] = !under_remote && this->allow_engine_udf && can_recurse; |
| 759 | /// queryMask[static_cast<size_t>(QueryOp::NumbersUDF)] = true; |
| 760 | queryMask[static_cast<size_t>(QueryOp::SystemTable)] = this->allow_not_deterministic && !systemTables.empty(); |
| 761 | queryMask[static_cast<size_t>(QueryOp::MergeUDF)] = this->allow_engine_udf; |
| 762 | queryMask[static_cast<size_t>(QueryOp::ClusterUDF)] = !under_remote && this->allow_engine_udf && !fc.clusters.empty() && can_recurse; |
| 763 | queryMask[static_cast<size_t>(QueryOp::LoopUDF)] = fc.allow_infinite_tables && this->allow_engine_udf && can_recurse; |
| 764 | /// queryMask[static_cast<size_t>(QueryOp::ValuesUDF)] = true; |
| 765 | queryMask[static_cast<size_t>(QueryOp::RandomDataUDF)] = this->allow_engine_udf; |
| 766 | queryMask[static_cast<size_t>(QueryOp::Dictionary)] = this->peer_query != PeerQuery::ClickHouseOnly && has_dictionary; |
| 767 | queryMask[static_cast<size_t>(QueryOp::URLEncodedTable)] = this->allow_engine_udf && has_table; |
| 768 | queryMask[static_cast<size_t>(QueryOp::TableEngineUDF)] = has_replaceable_table && this->allow_engine_udf; |
| 769 | queryMask[static_cast<size_t>(QueryOp::RandomTableUDF)] = this->allow_not_deterministic && this->allow_engine_udf; |
| 770 | queryMask[static_cast<size_t>(QueryOp::MergeIndexUDF)] = has_mergetree_table && this->allow_engine_udf; |
| 771 | queryMask[static_cast<size_t>(QueryOp::MergeProjectionUDF)] = has_mergetree_table && this->allow_engine_udf; |
| 772 | queryMask[static_cast<size_t>(QueryOp::MergeTextIndexUDF)] = has_mergetree_table && this->allow_engine_udf; |
| 773 | queryMask[static_cast<size_t>(QueryOp::MergeIndexAnalyzeUDF)] = has_mergetree_table && this->allow_engine_udf; |
| 774 | /// `filesystem([path])` reads local files (metadata + optional content) — non-deterministic |
| 775 | /// and needs FILE access. Don't emit it through `remote()` either. |
| 776 | queryMask[static_cast<size_t>(QueryOp::FilesystemUDF)] = !under_remote && this->allow_not_deterministic && this->allow_engine_udf; |
| 777 | |
| 778 | queryGen.setEnabled(queryMask); |
| 779 | /// If MV chaining is requested, force the next source to be a view (clears flag after use) |
| 780 | const bool chain_views_now = this->chain_views; |
| 781 | this->chain_views = false; |
| 782 | const auto nopt = (chain_views_now && queryMask[static_cast<size_t>(QueryOp::View)] && rg.nextBool()) |
| 783 | ? QueryOp::View |
| 784 | : static_cast<QueryOp>(queryGen.nextOp()); /// drifts over time |
| 785 | |
| 786 | switch (nopt) |
| 787 | { |
| 788 | case QueryOp::DerivatedTable: { |
| 789 | /// A derived query |
| 790 | SQLRelation rel(rel_name); |
nothing calls this directly
no test coverage detected