| 1165 | } |
| 1166 | |
| 1167 | void DatabaseReplicated::checkTableEngine(const ASTCreateQuery & query, ASTStorage & storage, ContextPtr query_context) const |
| 1168 | { |
| 1169 | bool replicated_table = storage.engine && |
| 1170 | (startsWith(storage.engine->name, "Replicated") || startsWith(storage.engine->name, "Shared")); |
| 1171 | if (!replicated_table || !storage.engine->arguments) |
| 1172 | return; |
| 1173 | |
| 1174 | ASTs & args_ref = storage.engine->arguments->children; |
| 1175 | ASTs args = args_ref; |
| 1176 | if (args.size() < 2) |
| 1177 | return; |
| 1178 | |
| 1179 | /// It can be a constant expression. Try to evaluate it, ignore exception if we cannot. |
| 1180 | bool has_expression_argument = args_ref[0]->as<ASTFunction>() || args_ref[1]->as<ASTFunction>(); |
| 1181 | if (has_expression_argument) |
| 1182 | { |
| 1183 | try |
| 1184 | { |
| 1185 | args[0] = evaluateConstantExpressionAsLiteral(args_ref[0]->clone(), query_context); |
| 1186 | args[1] = evaluateConstantExpressionAsLiteral(args_ref[1]->clone(), query_context); |
| 1187 | } |
| 1188 | catch (const Exception &) // NOLINT(bugprone-empty-catch) |
| 1189 | { |
| 1190 | } |
| 1191 | } |
| 1192 | |
| 1193 | ASTLiteral * arg1 = args[0]->as<ASTLiteral>(); |
| 1194 | ASTLiteral * arg2 = args[1]->as<ASTLiteral>(); |
| 1195 | if (!arg1 || !arg2 || arg1->value.getType() != Field::Types::String || arg2->value.getType() != Field::Types::String) |
| 1196 | return; |
| 1197 | |
| 1198 | String maybe_path = arg1->value.safeGet<String>(); |
| 1199 | String maybe_replica = arg2->value.safeGet<String>(); |
| 1200 | |
| 1201 | /// Looks like it's ReplicatedMergeTree with explicit zookeeper_path and replica_name arguments. |
| 1202 | /// Let's ensure that some macros are used. |
| 1203 | /// NOTE: we cannot check here that substituted values will be actually different on shards and replicas. |
| 1204 | |
| 1205 | Macros::MacroExpansionInfo info; |
| 1206 | info.table_id = {getDatabaseName(), query.getTable(), query.uuid}; |
| 1207 | info.shard = getShardName(); |
| 1208 | info.replica = getReplicaName(); |
| 1209 | query_context->getMacros()->expand(maybe_path, info); |
| 1210 | bool maybe_shard_macros = info.expanded_other; |
| 1211 | info.expanded_other = false; |
| 1212 | query_context->getMacros()->expand(maybe_replica, info); |
| 1213 | bool maybe_replica_macros = info.expanded_other; |
| 1214 | bool enable_functional_tests_helper = getContext()->getConfigRef().has("_functional_tests_helper_database_replicated_replace_args_macros"); |
| 1215 | |
| 1216 | if (maybe_shard_macros && maybe_replica_macros) |
| 1217 | return; |
| 1218 | |
| 1219 | if (enable_functional_tests_helper && !has_expression_argument) |
| 1220 | { |
| 1221 | if (maybe_path.empty() || maybe_path.back() != '/') |
| 1222 | maybe_path += '/'; |
| 1223 | args_ref[0]->as<ASTLiteral>()->value = maybe_path + "auto_{shard}"; |
| 1224 | args_ref[1]->as<ASTLiteral>()->value = maybe_replica + "auto_{replica}"; |
nothing calls this directly
no test coverage detected