| 2335 | */ |
| 2336 | |
| 2337 | static void print_join(THD *thd, |
| 2338 | String *str, |
| 2339 | List<TABLE_LIST> *tables, |
| 2340 | enum_query_type query_type) |
| 2341 | { |
| 2342 | /* List is reversed => we should reverse it before using */ |
| 2343 | List_iterator_fast<TABLE_LIST> ti(*tables); |
| 2344 | TABLE_LIST **table; |
| 2345 | uint non_const_tables= 0; |
| 2346 | |
| 2347 | for (TABLE_LIST *t= ti++; t ; t= ti++) |
| 2348 | if (!t->optimized_away) |
| 2349 | non_const_tables++; |
| 2350 | if (!non_const_tables) |
| 2351 | { |
| 2352 | str->append(STRING_WITH_LEN("dual")); |
| 2353 | return; // all tables were optimized away |
| 2354 | } |
| 2355 | ti.rewind(); |
| 2356 | |
| 2357 | if (!(table= (TABLE_LIST **)thd->alloc(sizeof(TABLE_LIST*) * |
| 2358 | non_const_tables))) |
| 2359 | return; // out of memory |
| 2360 | |
| 2361 | TABLE_LIST *tmp, **t= table + (non_const_tables - 1); |
| 2362 | while ((tmp= ti++)) |
| 2363 | { |
| 2364 | if (tmp->optimized_away) |
| 2365 | continue; |
| 2366 | *t--= tmp; |
| 2367 | } |
| 2368 | |
| 2369 | /* |
| 2370 | If the first table is a semi-join nest, swap it with something that is |
| 2371 | not a semi-join nest. This is necessary because "A SEMIJOIN B" is not the |
| 2372 | same as "B SEMIJOIN A". |
| 2373 | */ |
| 2374 | if ((*table)->sj_on_expr) |
| 2375 | { |
| 2376 | TABLE_LIST **end= table + non_const_tables; |
| 2377 | for (TABLE_LIST **t2= table; t2!=end; t2++) |
| 2378 | { |
| 2379 | if (!(*t2)->sj_on_expr) |
| 2380 | { |
| 2381 | TABLE_LIST *tmp= *t2; |
| 2382 | *t2= *table; |
| 2383 | *table= tmp; |
| 2384 | break; |
| 2385 | } |
| 2386 | } |
| 2387 | } |
| 2388 | DBUG_ASSERT(non_const_tables >= 1); |
| 2389 | print_table_array(thd, str, table, table + non_const_tables, query_type); |
| 2390 | } |
| 2391 | |
| 2392 | |
| 2393 | /** |
no test coverage detected