403Webshell
Server IP : 172.67.216.182  /  Your IP : 172.68.164.11
Web Server : Apache
System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64
User : www ( 1000)
PHP Version : 7.4.33
Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /www/server/mysql/src/sql/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /www/server/mysql/src/sql/sql_resolver.cc
/* Copyright (c) 2000, 2023, Oracle and/or its affiliates.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License, version 2.0,
   as published by the Free Software Foundation.

   This program is also distributed with certain software (including
   but not limited to OpenSSL) that is licensed under separate terms,
   as designated in a particular file or component or in included license
   documentation.  The authors of MySQL hereby grant you an additional
   permission to link the program and your derivative works with the
   separately licensed software that they have included with MySQL.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License, version 2.0, for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */

/**
  @file

  @brief
  Implementation of name resolution stage


  @defgroup Query_Resolver  Query Resolver
  @{
*/

#include "sql_select.h"
#include "sql_resolver.h"
#include "sql_optimizer.h"
#include "opt_trace.h"
#include "sql_base.h"
#include "auth_common.h"
#include "opt_explain_format.h"
#include "sql_test.h"            // print_where
#include "aggregate_check.h"
#include "template_utils.h"

static void propagate_nullability(List<TABLE_LIST> *tables, bool nullable);

static const Item::enum_walk walk_subquery=
  Item::enum_walk(Item::WALK_POSTFIX | Item::WALK_SUBQUERY);

uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
                                   uint first_unused);


/**
  Prepare query block for optimization.

  Resolve table and column information.
  Resolve all expressions (item trees), ie WHERE clause, join conditions,
  GROUP BY clause, HAVING clause, ORDER BY clause, LIMIT clause.
  Prepare all subqueries recursively as part of resolving the expressions.
  Apply permanent transformations to the abstract syntax tree, such as
  semi-join transformation, derived table transformation, elimination of
  constant values and redundant clauses (e.g ORDER BY, GROUP BY).

  @param thd    thread handler

  @returns false if success, true if error

  @note on privilege checking for SELECT query that possibly contains view
        or derived table references:

   - When this function is called, it is assumed that the precheck() function
     has been called. precheck() ensures that the user has some SELECT
     privileges to the tables involved in the query. When resolving views
     it has also been established that the user has some privileges for them.
     To prepare a view for privilege checking, it is also needed to call
     check_view_privileges() after views have been merged into the query.
     This is not necessary for unnamed derived tables since it has already
     been established that we have SELECT privileges for the underlying tables
     by the precheck functions. (precheck() checks a query without resolved
     views, ie. before tables are opened, so underlying tables of views
     are not yet available).

   - When a query block is resolved, always ensure that the user has SELECT
     privileges to the columns referenced in the WHERE clause, the join
     conditions, the GROUP BY clause, the HAVING clause and the ORDER BY clause.

   - When resolving the outer-most query block, ensure that the user also has
     SELECT privileges to the columns in the selected expressions.

   - When setting up a derived table or view for materialization, ensure that
     the user has SELECT privileges to the columns in the selected expressions

   - Column privileges are normally checked by Item_field::fix_fields().
     Exceptions are select list of derived tables/views which are checked
     in TABLE_LIST::setup_materialized_derived(), and natural/using join
     conditions that are checked in mark_common_columns().

   - As far as INSERT, UPDATE and DELETE statements have the same expressions
     as a SELECT statement, this note applies to those statements as well.
*/
bool SELECT_LEX::prepare(THD *thd)
{
  DBUG_ENTER("SELECT_LEX::prepare");

  // We may do subquery transformation, or Item substitution:
  Prepare_error_tracker tracker(thd);

  assert(this == thd->lex->current_select());
  assert(join == NULL);

  SELECT_LEX_UNIT *const unit= master_unit();

  if (top_join_list.elements > 0)
    propagate_nullability(&top_join_list, false);

  is_item_list_lookup= true;

  /*
    Determine whether immediate derived tables can be merged:
      - DTs belonging to outermost query block: always
      - DTs belonging to first level subqueries: Yes if inside SELECT statement,
        no otherwise (including UPDATE and DELETE).
        This is required to support a workaround for allowing subqueries
        containing the same table as is target for delete or update,
        by forcing a materialization of the subquery.
      - All other cases inherit status of parent query block.
  */
  allow_merge_derived=
    outer_select() == NULL ||
    master_unit()->item == NULL ||
    (outer_select()->outer_select() == NULL ?
      parent_lex->sql_command == SQLCOM_SELECT :
      outer_select()->allow_merge_derived);

  Opt_trace_context * const trace= &thd->opt_trace;
  Opt_trace_object trace_wrapper(trace);
  Opt_trace_object trace_prepare(trace, "join_preparation");
  trace_prepare.add_select_number(select_number);
  Opt_trace_array trace_steps(trace, "steps");
 
  // Initially, "all_fields" is the select list
  all_fields= fields_list;

  /* Check that all tables, fields, conds and order are ok */

  if (!(active_options() & OPTION_SETUP_TABLES_DONE))
  {
    if (setup_tables(thd, get_table_list(), false))
      DBUG_RETURN(true);

    if (derived_table_count && resolve_derived(thd, true))
      DBUG_RETURN(true);

    // Wait with privilege checking until all derived tables are resolved.
    if (!thd->derived_tables_processing &&
        check_view_privileges(thd, SELECT_ACL, SELECT_ACL))
      DBUG_RETURN(true);
  }

  // Precompute and store the row types of NATURAL/USING joins.
  if (leaf_table_count >= 2 &&
      setup_natural_join_row_types(thd, join_list, &context))
    DBUG_RETURN(true);

  Mem_root_array<Item_exists_subselect *, true>
    sj_candidates_local(thd->mem_root);
  sj_candidates= &sj_candidates_local;

  /*
    Item and Item_field CTORs will both increment some counters
    in current_select(), based on the current parsing context.
    We are not parsing anymore: any new Items created now are due to
    query rewriting, so stop incrementing counters.
   */
  assert(parsing_place == CTX_NONE);
  parsing_place= CTX_NONE;

  resolve_place= RESOLVE_SELECT_LIST;

  /*
    Setup the expressions in the SELECT list. Wait with privilege checking
    until all derived tables are resolved, except do privilege checking for
    subqueries inside a derived table.
  */
  const bool check_privs= !thd->derived_tables_processing ||
                          master_unit()->item != NULL;
  thd->mark_used_columns= check_privs ? MARK_COLUMNS_READ : MARK_COLUMNS_NONE;
  ulonglong want_privilege_saved= thd->want_privilege;
  thd->want_privilege= check_privs ? SELECT_ACL : 0;

  if (with_wild && setup_wild(thd))
    DBUG_RETURN(true);
  if (setup_ref_array(thd))
    DBUG_RETURN(true); /* purecov: inspected */
  
  if (setup_fields(thd, ref_ptrs, fields_list, thd->want_privilege,
                   &all_fields, true, false))
    DBUG_RETURN(true);

  resolve_place= RESOLVE_NONE;

  const nesting_map save_allow_sum_func= thd->lex->allow_sum_func;

  // Do not allow local set functions for join conditions, WHERE and GROUP BY
  thd->lex->allow_sum_func&= ~((nesting_map)1 << nest_level);

  thd->mark_used_columns= MARK_COLUMNS_READ;
  thd->want_privilege= SELECT_ACL;

  // Set up join conditions and WHERE clause
  if (setup_conds(thd))
    DBUG_RETURN(true);

  // Set up the GROUP BY clause
  int all_fields_count= all_fields.elements;
  if (group_list.elements && setup_group(thd))
    DBUG_RETURN(true);
  hidden_group_field_count= all_fields.elements - all_fields_count;

  // Allow local set functions in HAVING and ORDER BY
  thd->lex->allow_sum_func|= (nesting_map)1 << nest_level;

  // Setup the HAVING clause
  if (m_having_cond)
  {
    thd->where="having clause";
    having_fix_field= true;
    resolve_place= RESOLVE_HAVING;
    if (!m_having_cond->fixed &&
        (m_having_cond->fix_fields(thd, &m_having_cond) ||
         m_having_cond->check_cols(1)))
      DBUG_RETURN(true);

    having_fix_field= false;
    resolve_place= RESOLVE_NONE;
  }

  // Set up the ORDER BY clause
  all_fields_count= all_fields.elements;
  if (order_list.elements)
  {
    if (setup_order(thd, ref_ptrs, get_table_list(), fields_list, all_fields,
                    order_list.first))
      DBUG_RETURN(true);
    hidden_order_field_count= all_fields.elements - all_fields_count;
   }

  // Query block is completely resolved, restore set function allowance
  thd->lex->allow_sum_func= save_allow_sum_func;

  thd->want_privilege= want_privilege_saved;
  /*
    Permanently remove redundant parts from the query if
      1) This is a subquery
      2) This is the first time this query is prepared (since the
         transformation is permanent)
      3) Not normalizing a view. Removal should take place when a
         query involving a view is optimized, not when the view
         is created
  */
  if (unit->item &&                                        // 1)
      first_execution &&                                   // 2)
      !(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)) // 3)
  {
    remove_redundant_subquery_clauses(thd, hidden_group_field_count);
  }

  if (order_list.elements &&
      setup_order_final(thd))
    DBUG_RETURN(true);     /* purecov: inspected */

  if (is_distinct() &&
      is_grouped() &&
      hidden_group_field_count == 0 &&
      olap == UNSPECIFIED_OLAP_TYPE)
  {
    /*
      All GROUP expressions are in SELECT list, so resulting rows are distinct.
      ROLLUP is not specified, so adds no row. So all rows in the result set
      are distinct, DISTINCT is useless.
      @todo could remove DISTINCT if ROLLUP were specified and all GROUP
      expressions were non-nullable, because ROLLUP adds only NULL values.
      Currently, ROLLUP+DISTINCT is rejected because executor cannot handle
      it in all cases.
    */
    remove_base_options(SELECT_DISTINCT);
  }

  /*
    Printing the expanded query should happen here and not elsewhere, because
    when a view is merged (when the view is opened in open_tables()), the
    parent query's select_lex does not yet contain a correct WHERE clause (it
    misses the view's merged WHERE clause). This is corrected only just above,
    in TABLE_LIST::prep_where(), called by
    setup_without_group()->setup_conds().
    We also have to wait for fix_fields() on HAVING, above.
    At this stage, we also have properly set up Item_ref-s.
  */
  {
    Opt_trace_object trace_wrapper(trace);
    opt_trace_print_expanded_query(thd, this, &trace_wrapper);
  }

  /*
    When normalizing a view (like when writing a view's body to the FRM),
    subquery transformations don't apply (if they did, IN->EXISTS could not be
    undone in favour of materialization, when optimizing a later statement
    using the view)
  */
  if (unit->item &&                      // This is a subquery
      this != unit->fake_select_lex &&   // A real query block
                                         // Not normalizing a view
      !(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW))
  {
    // Query block represents a subquery within an IN/ANY/ALL/EXISTS predicate
    if (resolve_subquery(thd))
      DBUG_RETURN(true);
  }

  if (m_having_cond && m_having_cond->with_sum_func)
    m_having_cond->split_sum_func2(thd, ref_ptrs, all_fields, &m_having_cond,
                                   true);
  if (inner_sum_func_list)
  {
    Item_sum *end=inner_sum_func_list;
    Item_sum *item_sum= end;  
    do
    { 
      item_sum= item_sum->next;
      item_sum->split_sum_func2(thd, ref_ptrs,
                                all_fields, item_sum->ref_by, false);
    } while (item_sum != end);
  }

  if (inner_refs_list.elements && fix_inner_refs(thd))
    DBUG_RETURN(true);  /* purecov: inspected */

  if (group_list.elements)
  {
    /*
      Because HEAP tables can't index BIT fields we need to use an
      additional hidden field for grouping because later it will be
      converted to a LONG field. Original field will remain of the
      BIT type and will be returned to a client.
    */
    for (ORDER *ord= group_list.first; ord; ord= ord->next)
    {
      if ((*ord->item)->type() == Item::FIELD_ITEM &&
          (*ord->item)->field_type() == MYSQL_TYPE_BIT)
      {
        Item_field *field= new Item_field(thd, *(Item_field**)ord->item);
        ord->item= add_hidden_item(field);
      }
    }
  }

  if (setup_ftfuncs(this)) /* should be after having->fix_fields */
    DBUG_RETURN(true);

  if (query_result() && query_result()->prepare(fields_list, unit))
    DBUG_RETURN(true);

  if (olap == ROLLUP_TYPE && resolve_rollup(thd))
    DBUG_RETURN(true); /* purecov: inspected */

  if (flatten_subqueries())
    DBUG_RETURN(true);

  sj_candidates= NULL;

  /*
    When reaching the top-most query block, or the next-to-top query block for
    the SQL command SET and for SP instructions (indicated with SQLCOM_END),
    apply local transformations to this query block and all underlying query
    blocks.
  */
  if (outer_select() == NULL ||
      ((parent_lex->sql_command == SQLCOM_SET_OPTION ||
       parent_lex->sql_command == SQLCOM_END) &&
       outer_select()->outer_select() == NULL))
  {
    /*
      This code is invoked in the following cases:
      - if this is an outer-most query block of a SELECT or multi-table
        UPDATE/DELETE statement. Notice that for a UNION, this applies to
        all query blocks. It also applies to a fake_select_lex object.
      - if this is one of highest-level subqueries, if the statement is
        something else; like subq-i in:
          UPDATE t1 SET col1=(subq-1), col2=(subq-2);
      - If this is a subquery in a SET command
        @todo: Refactor SET so that this is not needed.

      Local transforms are applied after query block merging.
      This means that we avoid unnecessary invocations, as local transforms
      would otherwise have been performed first before query block merging and
      then another time after query block merging.
      Thus, apply_local_transforms() may run only after the top query
      is finished with query block merging. That's why
      apply_local_transforms() is initiated only by the top query, and then
      recurses into subqueries.
    */
    if (apply_local_transforms(thd, true))
      DBUG_RETURN(true);
  }

  assert(!thd->is_error());
  DBUG_RETURN(false);
}


/**
  Apply local transformations, such as query block merging.
  Also perform partition pruning, which is most effective after transformations
  have been done.

  @param thd      thread handler
  @param prune    if true, then prune partitions based on const conditions

  @returns false if success, true if error

  Since this is called after flattening of query blocks, call this function
  while traversing the query block hierarchy top-down. 
*/

bool SELECT_LEX::apply_local_transforms(THD *thd, bool prune)
{
  DBUG_ENTER("SELECT_LEX::apply_local_transforms");

  /*
    If query block contains one or more merged derived tables/views,
    walk through lists of columns in select lists and remove unused columns.
  */
  if (derived_table_count &&
      first_execution &&
      !(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW))
    delete_unused_merged_columns(&top_join_list);

  for (SELECT_LEX_UNIT *unit= first_inner_unit();
       unit;
       unit= unit->next_unit())
  {
    for (SELECT_LEX *sl= unit->first_select();
         sl;
         sl= sl->next_select())
    {
      // Prune all subqueries, regardless of passed argument
      if (sl->apply_local_transforms(thd, true))
        DBUG_RETURN(true);
    }
    if (unit->fake_select_lex &&
        unit->fake_select_lex->apply_local_transforms(thd, false))
      DBUG_RETURN(true);
  }

  if (first_execution &&
      !(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW))
  {
    /*
      The following code will allocate the new items in a permanent
      MEMROOT for prepared statements and stored procedures.
    */
    Prepared_stmt_arena_holder ps_arena_holder(thd);
    // Convert all outer joins to inner joins if possible
    if (simplify_joins(thd, &top_join_list, true, false, &m_where_cond))
      DBUG_RETURN(true);
    if (record_join_nest_info(&top_join_list))
      DBUG_RETURN(true);
    build_bitmap_for_nested_joins(&top_join_list, 0);

    /*
      Here are the reasons why we do the following check here (i.e. late).
      * setup_fields () may have done split_sum_func () on aggregate items of
      the SELECT list, so for reliable comparison of the ORDER BY list with
      the SELECT list, we need to wait until split_sum_func() is done with
      the ORDER BY list.
      * we get resolved expressions "most of the time", which is always a good
      thing. Some outer references may not be resolved, though.
      * we need nested_join::used_tables, and this member is set in
      simplify_joins()
      * simplify_joins() does outer-join-to-inner conversion, which increases
      opportunities for functional dependencies (weak-to-strong, which is
      unusable, becomes strong-to-strong).
      * check_only_full_group_by() is dependent on processing done by
      simplify_joins() (for example it uses the value of
      SELECT_LEX::outer_join).

      The drawback is that the checks are after resolve_subquery(), so can
      meet strange "internally added" items.

      Note that when we are creating a view, simplify_joins() doesn't run so
      check_only_full_group_by() cannot run, any error will be raised only
      when the view is later used (SELECTed...)
    */
    if ((is_distinct() || is_grouped()) &&
        (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
        check_only_full_group_by(thd))
      DBUG_RETURN(true);
  }

  fix_prepare_information(thd);

  /*
    Prune partitions for all query blocks after query block merging, if
    pruning is wanted.
  */
  if (partitioned_table_count && prune)
  {
    for (TABLE_LIST *tbl= leaf_tables; tbl; tbl= tbl->next_leaf)
    {
      /* 
        This will only prune constant conditions, which will be used for
        lock pruning.
      */
      if (prune_partitions(thd, tbl->table,
                           tbl->join_cond() ? tbl->join_cond() :
                                              m_where_cond))
        DBUG_RETURN(true); /* purecov: inspected */
    }
  }

  DBUG_RETURN(false);
}


/**
  Check if the subquery predicate can be executed via materialization.

  @param predicate IN subquery predicate
  @param thd       THD
  @param select_lex SELECT_LEX of the subquery
  @param outer      Parent SELECT_LEX (outer to subquery)

  @return TRUE if subquery allows materialization, FALSE otherwise.
*/

bool subquery_allows_materialization(Item_in_subselect *predicate,
                                     THD *thd,
                                     SELECT_LEX *select_lex,
                                     const SELECT_LEX *outer)
{
  const uint elements= predicate->unit->first_select()->item_list.elements;
  DBUG_ENTER("subquery_allows_materialization");
  assert(elements >= 1);
  assert(predicate->left_expr->cols() == elements);

  OPT_TRACE_TRANSFORM(&thd->opt_trace, trace_wrapper, trace_mat,
                      select_lex->select_number,
                      "IN (SELECT)", "materialization");

  const char *cause= NULL;
  if (predicate->substype() != Item_subselect::IN_SUBS)
  {
    // Subq-mat cannot handle 'outer_expr > {ANY|ALL}(subq)'...
    cause= "not an IN predicate";
  }
  else if (select_lex->is_part_of_union())
  {
    // Subquery must be a single query specification clause (not a UNION)
    cause= "in UNION";
  }
  else if (!select_lex->master_unit()->first_select()->leaf_tables)
  {
    // Subquery has no tables, hence no point in materializing.
    cause= "no inner tables";
  }
  else if (!outer->join)
  {
    /*
      Maybe this is a subquery of a single table UPDATE/DELETE (TODO:
      handle this by switching to multi-table UPDATE/DELETE).
    */
    cause= "parent query has no JOIN";
  }
  else if (!outer->leaf_tables)
  {
    // The upper query is SELECT ... FROM DUAL. No gain in materializing.
    cause= "no tables in outer query";
  }
  else if (predicate->dependent_before_in2exists())
  {
    /*
      Subquery should not be correlated; the correlation due to predicates
      injected by IN->EXISTS does not count as we will remove them if we
      choose materialization.

      TODO:
      This is an overly restrictive condition. It can be extended to:
         (Subquery is non-correlated ||
          Subquery is correlated to any query outer to IN predicate ||
          (Subquery is correlated to the immediate outer query &&
           Subquery !contains {GROUP BY, ORDER BY [LIMIT],
           aggregate functions}) && subquery predicate is not under "NOT IN"))
    */
    cause= "correlated";
  }
  else
  {
    /*
      Check that involved expression types allow materialization.
      This is a temporary fix for BUG#36752; see bug report for
      description of restrictions we need to put on the compared expressions.
    */
    assert(predicate->left_expr->fixed);
    // @see comment in Item_subselect::element_index()
    bool has_nullables= predicate->left_expr->maybe_null;

    List_iterator<Item> it(predicate->unit->first_select()->item_list);
    for (uint i= 0; i < elements; i++)
    {
      Item * const inner= it++;
      Item * const outer= predicate->left_expr->element_index(i);
      if (!types_allow_materialization(outer, inner))
      {
        cause= "type mismatch";
        break;
      }
      if (inner->is_blob_field())                 // 6
      {
        cause= "inner blob";
        break;
      }
      has_nullables|= inner->maybe_null;
    }

    if (!cause)
    {
      trace_mat.add("has_nullable_expressions", has_nullables);
      /*
        Subquery materialization cannot handle NULLs partial matching
        properly, yet. If the outer or inner values are NULL, the
        subselect_hash_sj_engine may reply FALSE when it should reply UNKNOWN.
        So, we must limit it to those three cases:
        - when FALSE and UNKNOWN are equivalent answers. I.e. this is a a
        top-level predicate (this implies it is not negated).
        - when outer and inner values cannot be NULL.
        - when there is a single inner column (because for this we have a
        limited implementation of NULLs partial matching).
      */
      const bool is_top_level= predicate->is_top_level_item();
      trace_mat.add("treat_UNKNOWN_as_FALSE", is_top_level);

      if (!is_top_level && has_nullables && (elements > 1))
        cause= "cannot_handle_partial_matches";
      else
      {
        trace_mat.add("possible", true);
        DBUG_RETURN(TRUE);
      }
    }
  }
  assert(cause != NULL);
  trace_mat.add("possible", false).add_alnum("cause", cause);
  DBUG_RETURN(false);
}


/**
  Make list of leaf tables of join table tree

  @param list    pointer to pointer on list first element
  @param tables  table list

  @returns pointer on pointer to next_leaf of last element
*/

static TABLE_LIST **make_leaf_tables(TABLE_LIST **list, TABLE_LIST *tables)
{
  for (TABLE_LIST *table= tables; table; table= table->next_local)
  {
    // A mergable view is not allowed to have a table pointer.
    assert(!(table->is_view() && table->is_merged() && table->table));
    if (table->merge_underlying_list)
    {
      assert(table->is_merged());

      list= make_leaf_tables(list, table->merge_underlying_list);
    }
    else
    {
      *list= table;
      list= &table->next_leaf;
    }
  }
  return list;
}


/**
  Check privileges for the view tables merged into a query block.

  @param thd                   Thread context.
  @param want_privilege_first  Privileges requested for the first leaf.
  @param want_privilege_next   Privileges requested for the remaining leaves.

  @note Beware that it can't properly check privileges in cases when
        table being changed is not the first table in the list of leaf
        tables (for example, for multi-UPDATE).

  @note The inner loop is slightly inefficient. A view will have its privileges
        checked once for every base table that it refers to.

  @returns false if success, true if error.
*/

bool st_select_lex::check_view_privileges(THD *thd,
                                          ulong want_privilege_first,
                                          ulong want_privilege_next)
{
  ulong want_privilege= want_privilege_first;
  Internal_error_handler_holder<View_error_handler, TABLE_LIST>
    view_handler(thd, true, leaf_tables);

  for (TABLE_LIST *tl= leaf_tables; tl; tl= tl->next_leaf)
  {
    for (TABLE_LIST *ref= tl; ref->referencing_view; ref= ref->referencing_view)
    {
      if (check_single_table_access(thd, want_privilege, ref, false))
        return true;
    }
    want_privilege= want_privilege_next;
  }
  return false;
}


/**
  Set up table leaves in the query block based on list of tables.

  @param thd           Thread handler
  @param tables        List of tables to handle
  @param select_insert It is SELECT ... INSERT command

  @note
    Check also that the 'used keys' and 'ignored keys' exists and set up the
    table structure accordingly.
    Create a list of leaf tables.

    This function has to be called for all tables that are used by items,
    as otherwise table->map is not set and all Item_field will be regarded
    as const items.

  @returns False on success, true on error
*/

bool st_select_lex::setup_tables(THD *thd, TABLE_LIST *tables,
                                 bool select_insert)
{
  DBUG_ENTER("st_select_lex::setup_tables");

  assert ((select_insert && !tables->next_name_resolution_table) ||
          !tables || 
          (context.table_list && context.first_name_resolution_table));

  make_leaf_tables(&leaf_tables, tables);

  TABLE_LIST *first_select_table= NULL;
  if (select_insert)
  {
    // "insert_table" is needed for remap_tables().
    thd->lex->insert_table= leaf_tables->top_table();

    // Get first table in SELECT part
    first_select_table= thd->lex->insert_table->next_local;

    // Then, find the first leaf table
    if (first_select_table)
      first_select_table= first_select_table->first_leaf_table();
  }
  uint tableno= 0;
  leaf_table_count= 0;
  partitioned_table_count= 0;

  for (TABLE_LIST *tr= leaf_tables; tr; tr= tr->next_leaf, tableno++)
  {
    TABLE *const table= tr->table;
    if (tr == first_select_table)
    {
      /*
        For INSERT ... SELECT command, restart numbering from zero for first
        leaf table from SELECT part of query.
      */
      first_select_table= 0;
      tableno= 0;
    }
    if (tableno >= MAX_TABLES)
    {
      my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES));
      DBUG_RETURN(true);
    }
    tr->set_tableno(tableno);
    leaf_table_count++;       // Count the input tables of the query
    if (table == NULL)
      continue;
    table->pos_in_table_list= tr;
    tr->reset();

    /*
      Only set hints on first execution.  Otherwise, hints will refer to
      wrong query block after semijoin transformation
    */
    if (first_execution &&                 
        opt_hints_qb &&                      // QB hints initialized
        !tr->opt_hints_table)                // Table hints are not adjusted yet
    {
      tr->opt_hints_table= opt_hints_qb->adjust_table_hints(table, tr->alias);
    }

    if (tr->process_index_hints(table))
      DBUG_RETURN(true);
    if (table->part_info)     // Count number of partitioned tables
      partitioned_table_count++;
  }

  if (opt_hints_qb)
    opt_hints_qb->check_unresolved(thd);
 
  DBUG_RETURN(false);
}


/**
  Re-map table numbers for all tables in a query block.

  @param thd           Thread handler

  @note
    This function needs to be called after setup_tables() has been called,
    and after a query block for a subquery has been merged into a parent
    quary block.
*/

void st_select_lex::remap_tables(THD *thd)
{
  LEX *const lex= thd->lex;
  TABLE_LIST *first_select_table= NULL;
  if (lex->insert_table &&
      lex->insert_table == leaf_tables->top_table())
  {
    /*
      For INSERT ... SELECT command, restart numbering from zero for first
      leaf table from SELECT part of query.
    */
    // Get first table in SELECT part
    first_select_table= lex->insert_table->next_local;

    // Then, recurse down to get first leaf table
    if (first_select_table)
      first_select_table= first_select_table->first_leaf_table();
  }

  uint tableno= 0;
  for (TABLE_LIST *tl= leaf_tables; tl; tl= tl->next_leaf)
  {
    // Reset table number after having reached first table after insert table
    if (first_select_table == tl)
      tableno= 0;
    tl->set_tableno(tableno++);
  }
}

/**
  @brief Resolve derived table and view references in query block

  @param thd            Pointer to THD.
  @param apply_semijoin if true, apply semi-join transform when possible

  @return false if success, true if error
*/

bool st_select_lex::resolve_derived(THD *thd, bool apply_semijoin)
{
  DBUG_ENTER("st_select_lex::resolve_derived");

  assert(derived_table_count);

  // Prepare derived tables and views that belong to this query block.
  for (TABLE_LIST *tl= get_table_list(); tl; tl= tl->next_local)
  {
    if (!tl->is_view_or_derived() || tl->is_merged())
      continue;
    if (tl->resolve_derived(thd, apply_semijoin))
      DBUG_RETURN(true);
  }

  /*
    Merge the derived tables that do not require materialization into
    the current query block, if possible.
    Merging is only done once and must not be repeated for prepared execs.
  */
  if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) &&
      first_execution)
  {
    for (TABLE_LIST *tl= get_table_list(); tl; tl= tl->next_local)
    {
      if (!tl->is_view_or_derived() ||
          tl->is_merged() ||
          !tl->is_mergeable())
      continue;
      if (merge_derived(thd, tl))
        DBUG_RETURN(true);        /* purecov: inspected */
    }
  }

  // Prepare remaining derived tables for materialization
  for (TABLE_LIST *tl= get_table_list(); tl; tl= tl->next_local)
  {
    // Ensure that any derived table is merged or materialized after prepare:
    assert(first_execution || !tl->is_view_or_derived() ||
           tl->is_merged() || tl->uses_materialization());
    if (!tl->is_view_or_derived() || tl->is_merged())
      continue;
    if (tl->setup_materialized_derived(thd))
      DBUG_RETURN(true);
    materialized_derived_table_count++;
  }

  /*
    The loops above will not reach derived tables that are contained within
    other derived tables that have been merged into the enclosing query block.
    To reach them, traverse the list of leaf tables and resolve and
    setup for materialization those derived tables that have no TABLE
    object (they have not been set up yet).
  */
  if (!first_execution)
  {
    for (TABLE_LIST *tl= leaf_tables; tl; tl= tl->next_leaf)
    {
      if (!tl->is_view_or_derived() || tl->table != NULL)
        continue;
      assert(!tl->is_merged());
      if (tl->resolve_derived(thd, apply_semijoin))
        DBUG_RETURN(true);        /* purecov: inspected */
      if (tl->setup_materialized_derived(thd))
        DBUG_RETURN(true);        /* purecov: inspected */
      /*
        materialized_derived_table_count was incremented during preparation,
        so do not do it once more.
      */
    }
  }

  DBUG_RETURN(false);
}


/**
  @brief Resolve predicate involving subquery

  @param thd     Pointer to THD.

  @retval FALSE  Success.
  @retval TRUE   Error.

  @details
  Perform early unconditional subquery transformations:
   - Convert subquery predicate into semi-join, or
   - Mark the subquery for execution using materialization, or
   - Perform IN->EXISTS transformation, or
   - Perform more/less ALL/ANY -> MIN/MAX rewrite
   - Substitute trivial scalar-context subquery with its value

  @todo for PS, make the whole block execute only on the first execution

*/

bool SELECT_LEX::resolve_subquery(THD *thd)
{
  DBUG_ENTER("resolve_subquery");

  bool chose_semijoin= false;
  SELECT_LEX *const outer= outer_select();

  /*
    @todo for PS, make the whole block execute only on the first execution.
    resolve_subquery() is only invoked in the first execution for subqueries
    that are transformed to semijoin, but for other subqueries, this function
    is called for every execution. One solution is perhaps to define
    exec_method in class Item_subselect and exit immediately if unequal to
    EXEC_UNSPECIFIED.
  */
  Item_subselect *subq_predicate= master_unit()->item;
  assert(subq_predicate);
  /**
    @note
    In this case: IN (SELECT ... UNION SELECT ...), SELECT_LEX::prepare() is
    called for each of the two UNION members, and in those two calls,
    subq_predicate is the same, not sure this is desired (double work?).
  */

  Item_in_subselect * const in_predicate=
    (subq_predicate->substype() == Item_subselect::IN_SUBS) ?
    static_cast<Item_in_subselect *>(subq_predicate) : NULL;

  if (in_predicate)
  {
    thd->lex->set_current_select(outer);
    char const *save_where= thd->where;
    thd->where= "IN/ALL/ANY subquery";
    Disable_semijoin_flattening DSF(outer, true);

    bool result= !in_predicate->left_expr->fixed &&
                  in_predicate->left_expr->fix_fields(thd,
                                                     &in_predicate->left_expr);
    thd->lex->set_current_select(this);
    thd->where= save_where;
    if (result)
      DBUG_RETURN(true);

    /*
      Check if the left and right expressions have the same # of
      columns, i.e. we don't have a case like 
        (oe1, oe2) IN (SELECT ie1, ie2, ie3 ...)

      TODO why do we have this duplicated in IN->EXISTS transformers?
      psergey-todo: fix these: grep for duplicated_subselect_card_check
    */
    if (item_list.elements != in_predicate->left_expr->cols())
    {
      my_error(ER_OPERAND_COLUMNS, MYF(0), in_predicate->left_expr->cols());
      DBUG_RETURN(true);
    }
  }

  DBUG_PRINT("info", ("Checking if subq can be converted to semi-join"));
  /*
    Check if we're in subquery that is a candidate for flattening into a
    semi-join (which is done in flatten_subqueries()). The requirements are:
      1. Subquery predicate is an IN/=ANY subquery predicate
      2. Subquery is a single SELECT (not a UNION)
      3. Subquery does not have GROUP BY
      4. Subquery does not use aggregate functions or HAVING
      5. Subquery predicate is (a) in an ON/WHERE clause, and (b) at
      the AND-top-level of that clause.
      6. Parent query block accepts semijoins (i.e we are not in a subquery of
      a single table UPDATE/DELETE (TODO: We should handle this at some
      point by switching to multi-table UPDATE/DELETE)
      7. We're not in a confluent table-less subquery, like "SELECT 1".
      8. No execution method was already chosen (by a prepared statement).
      9. Parent query block is not a confluent table-less query block.
      10. Neither parent nor child query block has straight join.
      11. Parent query block does not prohibit semi-join.
  */
  if (semijoin_enabled(thd) &&
      in_predicate &&                                                   // 1
      !is_part_of_union() &&                                            // 2
      !group_list.elements &&                                           // 3
      !m_having_cond && !with_sum_func &&                               // 4
      (outer->resolve_place == st_select_lex::RESOLVE_CONDITION ||      // 5a
       outer->resolve_place == st_select_lex::RESOLVE_JOIN_NEST) &&     // 5a
      !outer->semijoin_disallowed &&                                    // 5b
      outer->sj_candidates &&                                           // 6
      leaf_table_count > 0 &&                                           // 7
      in_predicate->exec_method ==
                           Item_exists_subselect::EXEC_UNSPECIFIED &&   // 8
      outer->leaf_table_count &&                                        // 9
      !((active_options() | outer->active_options()) &
        SELECT_STRAIGHT_JOIN) &&                                        //10
      !(outer->active_options() & SELECT_NO_SEMI_JOIN))                 //11
  {
    DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));

    /* Notify in the subquery predicate where it belongs in the query graph */
    in_predicate->embedding_join_nest= outer->resolve_nest;

    /* Register the subquery for further processing in flatten_subqueries() */
    outer->sj_candidates->push_back(in_predicate);
    chose_semijoin= true;
  }

  if (in_predicate)
  {
    Opt_trace_context * const trace= &thd->opt_trace;
    OPT_TRACE_TRANSFORM(trace, oto0, oto1,
                        select_number, "IN (SELECT)", "semijoin");
    oto1.add("chosen", chose_semijoin);
  }

  if (!chose_semijoin &&
      subq_predicate->select_transformer(this) ==
      Item_subselect::RES_ERROR)
    DBUG_RETURN(true);

  DBUG_RETURN(false);
}


/**
  Expand all '*' in list of expressions with the matching column references

  Function should not be called with no wild cards in select list

  @param  thd     thread handler

  @returns false if OK, true if error
*/

bool SELECT_LEX::setup_wild(THD *thd)
{
  DBUG_ENTER("SELECT_LEX::setup_wild");

  assert(with_wild);

  // PS/SP uses arena so that changes are made permanently.
  Prepared_stmt_arena_holder ps_arena_holder(thd);

  Item *item;
  List_iterator<Item> it(fields_list);

  while (with_wild && (item= it++))
  {
    Item_field *item_field;
    if (item->type() == Item::FIELD_ITEM &&
        (item_field= down_cast<Item_field *>(item)) &&
        item_field->is_asterisk())
    {
      assert(item_field->field == NULL);
      const uint elem= fields_list.elements;
      const bool any_privileges= item_field->any_privileges;
      Item_subselect *subsel= master_unit()->item;

      /*
        In case of EXISTS(SELECT * ... HAVING ...), don't use this
        transformation. The columns in HAVING will need to resolve to the
        select list. Replacing * with 1 effectively eliminates this
        possibility.
      */
      if (subsel && subsel->substype() == Item_subselect::EXISTS_SUBS &&
          !having_cond())
      {
        /*
          It is EXISTS(SELECT * ...) and we can replace * by any constant.

          Item_int do not need fix_fields() because it is basic constant.
        */
        it.replace(new Item_int(NAME_STRING("Not_used"), (longlong) 1,
                                MY_INT64_NUM_DECIMAL_DIGITS));
      }
      else
      {
        if (insert_fields(thd, item_field->context,
                          item_field->db_name, item_field->table_name,
                          &it, any_privileges))
          DBUG_RETURN(true);
      }
      /*
        all_fields is a list that has the fields list as a tail.
        Because of this we have to update the element count also for this
        list after expanding the '*' entry.
      */
      all_fields.elements+= fields_list.elements - elem;

      with_wild--;
    }
  }

  DBUG_RETURN(false);
}

/**
  Resolve WHERE condition and join conditions

  @param  thd     thread handler

  @returns false if success, true if error
*/
bool SELECT_LEX::setup_conds(THD *thd)
{
  DBUG_ENTER("SELECT_LEX::setup_conds");

  /*
    it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX
    which belong to LEX, i.e. most up SELECT) will be updated by
    INSERT/UPDATE/LOAD
    NOTE: using this condition helps to prevent call of prepare_check_option()
    from subquery of VIEW, because tables of subquery belongs to VIEW
    (see condition before prepare_check_option() call)
  */
  const bool it_is_update= (this == thd->lex->select_lex) &&
                           thd->lex->which_check_option_applicable();
  const bool save_is_item_list_lookup= is_item_list_lookup;
  is_item_list_lookup= false;

  DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));

  if (m_where_cond)
  {
    resolve_place= st_select_lex::RESOLVE_CONDITION;
    thd->where="where clause";
    if ((!m_where_cond->fixed &&
         m_where_cond->fix_fields(thd, &m_where_cond)) ||
	m_where_cond->check_cols(1))
      DBUG_RETURN(true);
    resolve_place= st_select_lex::RESOLVE_NONE;
  }

  /*
    Apply fix_fields() to all ON clauses at all levels of nesting,
    including the ones inside view definitions.
  */
  for (TABLE_LIST *table= leaf_tables; table; table= table->next_leaf)
  {
    TABLE_LIST *embedded; /* The table at the current level of nesting. */
    TABLE_LIST *embedding= table; /* The parent nested table reference. */
    do
    {
      embedded= embedding;
      if (embedded->join_cond())
      {
        resolve_place= st_select_lex::RESOLVE_JOIN_NEST;
        resolve_nest= embedded;
        thd->where="on clause";
        if ((!embedded->join_cond()->fixed &&
           embedded->join_cond()->fix_fields(thd, embedded->join_cond_ref())) ||
	   embedded->join_cond()->check_cols(1))
          DBUG_RETURN(true);
        cond_count++;
        resolve_place= st_select_lex::RESOLVE_NONE;
        resolve_nest= NULL;
      }
      embedding= embedded->embedding;
    }
    while (embedding &&
           embedding->nested_join->join_list.head() == embedded);

    /* process CHECK OPTION */
    if (it_is_update)
    {
      TABLE_LIST *view= table->top_table();
      if (view->is_view() && view->is_merged())
      {
        if (view->prepare_check_option(thd))
          DBUG_RETURN(true);        /* purecov: inspected */
        table->check_option= view->check_option;
      }
    }
  }

  is_item_list_lookup= save_is_item_list_lookup;

  assert(thd->lex->current_select() == this);
  assert(!thd->is_error());
  DBUG_RETURN(false);
}


/**
  Set NESTED_JOIN::counter=0 in all nested joins in passed list.

  @param join_list  Pass NULL. Non-NULL is reserved for recursive inner calls,
  then it is a list of nested joins to process, and may also contain base
  tables which will be ignored.
*/

void SELECT_LEX::reset_nj_counters(List<TABLE_LIST> *join_list)
{
  if (join_list == NULL)
    join_list= &top_join_list;
  List_iterator<TABLE_LIST> li(*join_list);
  TABLE_LIST *table;
  DBUG_ENTER("reset_nj_counters");
  while ((table= li++))
  {
    NESTED_JOIN *nested_join;
    if ((nested_join= table->nested_join))
    {
      nested_join->nj_counter= 0;
      reset_nj_counters(&nested_join->join_list);
    }
  }
  DBUG_VOID_RETURN;
}


/**
  Simplify joins replacing outer joins by inner joins whenever it's
  possible.

    The function, during a retrieval of join_list,  eliminates those
    outer joins that can be converted into inner join, possibly nested.
    It also moves the join conditions for the converted outer joins
    and from inner joins to conds.
    The function also calculates some attributes for nested joins:

    -# used_tables
    -# not_null_tables
    -# dep_tables.
    -# on_expr_dep_tables

    The first two attributes are used to test whether an outer join can
    be substituted by an inner join. The third attribute represents the
    relation 'to be dependent on' for tables. If table t2 is dependent
    on table t1, then in any evaluated execution plan table access to
    table t2 must precede access to table t2. This relation is used also
    to check whether the query contains  invalid cross-references.
    The fourth attribute is an auxiliary one and is used to calculate
    dep_tables.
    As the attribute dep_tables qualifies possibles orders of tables in the
    execution plan, the dependencies required by the straight join
    modifiers are reflected in this attribute as well.
    The function also removes all parentheses that can be removed from the join
    expression without changing its meaning.

  @note
    An outer join can be replaced by an inner join if the where condition
    or the join condition for an embedding nested join contains a conjunctive
    predicate rejecting null values for some attribute of the inner tables.

    E.g. in the query:    
    @code
      SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a WHERE t2.b < 5
    @endcode
    the predicate t2.b < 5 rejects nulls.
    The query is converted first to:
    @code
      SELECT * FROM t1 INNER JOIN t2 ON t2.a=t1.a WHERE t2.b < 5
    @endcode
    then to the equivalent form:
    @code
      SELECT * FROM t1, t2 ON t2.a=t1.a WHERE t2.b < 5 AND t2.a=t1.a
    @endcode


    Similarly the following query:
    @code
      SELECT * from t1 LEFT JOIN (t2, t3) ON t2.a=t1.a t3.b=t1.b
        WHERE t2.c < 5  
    @endcode
    is converted to:
    @code
      SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b 

    @endcode

    One conversion might trigger another:
    @code
      SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a
                       LEFT JOIN t3 ON t3.b=t2.b
        WHERE t3 IS NOT NULL =>
      SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a, t3
        WHERE t3 IS NOT NULL AND t3.b=t2.b => 
      SELECT * FROM t1, t2, t3
        WHERE t3 IS NOT NULL AND t3.b=t2.b AND t2.a=t1.a
  @endcode

    The function removes all unnecessary parentheses from the expression
    produced by the conversions.
    E.g.
    @code
      SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b
    @endcode
    finally is converted to: 
    @code
      SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b

    @endcode


    It also will remove parentheses from the following queries:
    @code
      SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b
      SELECT * from (t1, (t2,t3)) WHERE t1.a=t2.a AND t2.b=t3.b.
    @endcode

    The benefit of this simplification procedure is that it might return 
    a query for which the optimizer can evaluate execution plans with more
    join orders. With a left join operation the optimizer does not
    consider any plan where one of the inner tables is before some of outer
    tables.

  IMPLEMENTATION
    The function is implemented by a recursive procedure.  On the recursive
    ascent all attributes are calculated, all outer joins that can be
    converted are replaced and then all unnecessary parentheses are removed.
    As join list contains join tables in the reverse order sequential
    elimination of outer joins does not require extra recursive calls.

  SEMI-JOIN NOTES
    Remove all semi-joins that have are within another semi-join (i.e. have
    an "ancestor" semi-join nest)

  EXAMPLES
    Here is an example of a join query with invalid cross references:
    @code
      SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN t3 ON t3.b=t1.b 
    @endcode

  @param thd         thread handler
  @param join_list   list representation of the join to be converted
  @param top         true <=> cond is the where condition
  @param in_sj       TRUE <=> processing semi-join nest's children
  @param[in,out] cond In: condition to which the join condition for converted
                          outer joins is to be added;
                      Out: new condition
  @param changelog   Don't specify this parameter, it is reserved for
                     recursive calls inside this function

  @returns true for error, false for success
*/
bool
SELECT_LEX::simplify_joins(THD *thd,
                           List<TABLE_LIST> *join_list, bool top,
                           bool in_sj, Item **cond, uint *changelog)
{
  /*
    Each type of change done by this function, or its recursive calls, is
    tracked in a bitmap:
  */
  enum change
  {
    NONE= 0,
    OUTER_JOIN_TO_INNER= 1 << 0,
    JOIN_COND_TO_WHERE= 1 << 1,
    PAREN_REMOVAL= 1 << 2,
    SEMIJOIN= 1 << 3
  };
  uint changes= 0; // To keep track of changes.
  if (changelog == NULL) // This is the top call.
    changelog= &changes;

  TABLE_LIST *table;
  NESTED_JOIN *nested_join;
  TABLE_LIST *prev_table= 0;
  List_iterator<TABLE_LIST> li(*join_list);
  const bool straight_join= active_options() & SELECT_STRAIGHT_JOIN;
  DBUG_ENTER("simplify_joins");

  /* 
    Try to simplify join operations from join_list.
    The most outer join operation is checked for conversion first. 
  */
  while ((table= li++))
  {
    table_map used_tables;
    table_map not_null_tables= (table_map) 0;

    if ((nested_join= table->nested_join))
    {
      /* 
         If the element of join_list is a nested join apply
         the procedure to its nested join list first.
      */
      if (table->join_cond())
      {
        Item *join_cond= table->join_cond();
        /* 
           If a join condition JC is attached to the table, 
           check all null rejected predicates in this condition.
           If such a predicate over an attribute belonging to
           an inner table of an embedded outer join is found,
           the outer join is converted to an inner join and
           the corresponding join condition is added to JC. 
	*/ 
        if (simplify_joins(thd, &nested_join->join_list,
                           false, in_sj || table->sj_cond(),
                           &join_cond, changelog))
          DBUG_RETURN(true);

        if (join_cond != table->join_cond())
        {
          assert(join_cond);
          table->set_join_cond(join_cond);
        }
      }
      nested_join->used_tables= (table_map) 0;
      nested_join->not_null_tables=(table_map) 0;
      if (simplify_joins(thd, &nested_join->join_list, top,
                         in_sj || table->sj_cond(), cond, changelog))
        DBUG_RETURN(true);
      used_tables= nested_join->used_tables;
      not_null_tables= nested_join->not_null_tables;  
    }
    else
    {
      used_tables= table->map();
      if (*cond)
        not_null_tables= (*cond)->not_null_tables();
    }
      
    if (table->embedding)
    {
      table->embedding->nested_join->used_tables|= used_tables;
      table->embedding->nested_join->not_null_tables|= not_null_tables;
    }

    if (!table->outer_join || (used_tables & not_null_tables))
    {
      /* 
        For some of the inner tables there are conjunctive predicates
        that reject nulls => the outer join can be replaced by an inner join.
      */
      if (table->outer_join)
      {
        *changelog|= OUTER_JOIN_TO_INNER;
        table->outer_join= 0;
      }
      if (table->join_cond())
      {
        *changelog|= JOIN_COND_TO_WHERE;
        /* Add join condition to the WHERE or upper-level join condition. */
        if (*cond)
        {
          Item_cond_and *new_cond=
            static_cast<Item_cond_and*>(and_conds(*cond, table->join_cond()));
          if (!new_cond)
            DBUG_RETURN(true);
          new_cond->top_level_item();
          /*
            It is always a new item as both the upper-level condition and a
            join condition existed
          */
          assert(!new_cond->fixed);
          if (new_cond->fix_fields(thd, NULL))
            DBUG_RETURN(true);

          /* If join condition has a pending rollback in THD::change_list */
          List_iterator<Item> lit(*new_cond->argument_list());
          Item *arg;
          while ((arg= lit++))
          {
            /*
              Check whether the arguments to AND need substitution
              of rollback location.
            */
            thd->replace_rollback_place(lit.ref());
          }
          *cond= new_cond;
        }
        else
        {
          *cond= table->join_cond();
          /* If join condition has a pending rollback in THD::change_list */
          thd->replace_rollback_place(cond);
        }
        table->set_join_cond(NULL);
      }
    }

    if (!top)
      continue;

    /* 
      Only inner tables of non-convertible outer joins remain with
      the join condition.
    */ 
    if (table->join_cond())
    {
      table->dep_tables|= table->join_cond()->used_tables();

      // At this point the joined tables always have an embedding join nest:
      assert(table->embedding);

      table->dep_tables&= ~table->embedding->nested_join->used_tables;

      // Embedding table depends on tables used in embedded join conditions. 
      table->embedding->on_expr_dep_tables|= table->join_cond()->used_tables();
    }

    if (prev_table)
    {
      /* The order of tables is reverse: prev_table follows table */
      if (prev_table->straight || straight_join)
        prev_table->dep_tables|= used_tables;
      if (prev_table->join_cond())
      {
        prev_table->dep_tables|= table->on_expr_dep_tables;
        table_map prev_used_tables= prev_table->nested_join ?
	                            prev_table->nested_join->used_tables :
	                            prev_table->map();
        /* 
          If join condition contains only references to inner tables
          we still make the inner tables dependent on the outer tables.
          It would be enough to set dependency only on one outer table
          for them. Yet this is really a rare case.
          Note:
          PSEUDO_TABLE_BITS mask should not be counted as it
          prevents update of inner table dependencies.
          For example it might happen if RAND()/COUNT(*) function
          is used in JOIN ON clause.
	*/  
        if (!((prev_table->join_cond()->used_tables() & ~PSEUDO_TABLE_BITS) &
              ~prev_used_tables))
          prev_table->dep_tables|= used_tables;
      }
    }
    prev_table= table;
  }

  /*
    Flatten nested joins that can be flattened.
    no join condition and not a semi-join => can be flattened.
  */
  li.rewind();
  while ((table= li++))
  {
    nested_join= table->nested_join;
    if (table->sj_cond() && !in_sj)
    {
       /*
         If this is a semi-join that is not contained within another semi-join, 
         leave it intact (otherwise it is flattened)
       */
      *changelog|= SEMIJOIN;
    }
    else if (nested_join && !table->join_cond())
    {
      *changelog|= PAREN_REMOVAL;
      TABLE_LIST *tbl;
      List_iterator<TABLE_LIST> it(nested_join->join_list);
      while ((tbl= it++))
      {
        tbl->embedding= table->embedding;
        tbl->join_list= table->join_list;
        tbl->dep_tables|= table->dep_tables;
      }
      li.replace(nested_join->join_list);
    }
  }

  if (changes)
  {
    Opt_trace_context * trace= &thd->opt_trace;
    if (unlikely(trace->is_started()))
    {
      Opt_trace_object trace_wrapper(trace);
      Opt_trace_object trace_object(trace, "transformations_to_nested_joins");
      {
        Opt_trace_array trace_changes(trace, "transformations");
        if (changes & SEMIJOIN)
          trace_changes.add_alnum("semijoin");
        if (changes & OUTER_JOIN_TO_INNER)
          trace_changes.add_alnum("outer_join_to_inner_join");
        if (changes & JOIN_COND_TO_WHERE)
          trace_changes.add_alnum("JOIN_condition_to_WHERE");
        if (changes & PAREN_REMOVAL)
          trace_changes.add_alnum("parenthesis_removal");
      }
      // the newly transformed query is worth printing
      opt_trace_print_expanded_query(thd, this, &trace_object);
    }
  }
  DBUG_RETURN(false);
}


/**
  Record join nest info in the select block.

  After simplification of inner join, outer join and semi-join structures:
   - record the remaining semi-join structures in the enclosing query block.
   - record transformed join conditions in TABLE_LIST objects.

  This function is called recursively for each join nest and/or table
  in the query block.

  @param select The query block
  @param tables List of tables and join nests

  @return False if successful, True if failure
*/
bool SELECT_LEX::record_join_nest_info(List<TABLE_LIST> *tables)
{
  TABLE_LIST *table;
  List_iterator<TABLE_LIST> li(*tables);
  DBUG_ENTER("record_join_nest_info");

  while ((table= li++))
  {
    if (table->nested_join == NULL)
    {
      if (table->join_cond())
        outer_join|= table->map();
      continue;
    }

    if (record_join_nest_info(&table->nested_join->join_list))
      DBUG_RETURN(true);
    /*
      sj_inner_tables is set properly later in pull_out_semijoin_tables().
      This assignment is required in case pull_out_semijoin_tables()
      is not called.
    */
    if (table->sj_cond())
      table->sj_inner_tables= table->nested_join->used_tables;

    if (table->sj_cond() && sj_nests.push_back(table))
      DBUG_RETURN(true);

    if (table->join_cond())
      outer_join|= table->nested_join->used_tables;
  }
  DBUG_RETURN(false);
}


static int subq_sj_candidate_cmp(Item_exists_subselect* const *el1, 
                                 Item_exists_subselect* const *el2)
{
  /*
    Remove this assert when we support semijoin on non-IN subqueries.
  */
  assert((*el1)->substype() == Item_subselect::IN_SUBS &&
         (*el2)->substype() == Item_subselect::IN_SUBS);
  return ((*el1)->sj_convert_priority < (*el2)->sj_convert_priority) ? 1 : 
         ( ((*el1)->sj_convert_priority == (*el2)->sj_convert_priority)? 0 : -1);
}


/**
  Update table reference information for conditions and expressions due to
  query blocks having been merged in from derived tables/views and due to
  semi-join transformation.

  This is needed for two reasons:

  1. Since table numbers are changed, we need to update used_tables
     information for all conditions and expressions that are possibly touched.

  2. For semi-join, some column references are changed from outer references
     to local references.

  The function needs to recursively walk down into join nests,
  in order to cover all conditions and expressions.

  For a semi-join, tables from the subquery are added last in the query block.
  This means that conditions and expressions from the outer query block
  are unaffected. But all conditions inside the semi-join nest, including
  join conditions, must have their table numbers changed.

  For a derived table/view, tables from the subquery are merged into the
  outer query, and this function is called for every derived table that is
  merged in. This algorithm only works when derived tables are merged in
  the order of their original table numbers.

  A hypothetical example with a triple self-join over a mergeable view:

    CREATE VIEW v AS SELECT t1.a, t2.b FROM t1 JOIN t2 USING (a);
    SELECT v1.a, v1.b, v2.b, v3.b
    FROM v AS v1 JOIN v AS v2 ON ... JOIN v AS v3 ON ...;

  The analysis starts with three tables v1, v2 and v3 having numbers 0, 1, 2.
  First we merge in v1, so we get (t1, t2, v2, v3). v2 and v3 are shifted up.
  Tables from v1 need to have their table numbers altered (actually they do not
  since both old and new numbers are 0 and 1, but this is a special case).
  v2 and v3 are not merged in yet, so we delay pullout on them until they
  are merged. Conditions and expressions from the outer query are not resolved
  yet, so regular resolving will take of them later. 
  Then we merge in v2, so we get (t1, t2, t1, t2, v3). The tables from this
  view gets numbers 2 and 3, and v3 gets number 4.
  Because v2 had a higher number than the tables from v1, the join nest
  representing v1 is unaffected. And v3 is still not merged, so the only
  join nest we need to consider is v2.
  Finally we merge in v3, and then we have tables (t1, t2, t1, t2, t1, t2),
  with numbers 0 through 5.
  Again, since v3 has higher number than any of the already merged in views,
  only this join nest needs the pullout.

  @param parent_select  Query block being merged into
  @param removed_select Query block that is removed (subquery)
  @param tr             Table object this pullout is applied to
  @param table_adjust   Number of positions that a derived table nest is
                        adjusted, used to fix up semi-join related fields.
                        Tables are adjusted from position N to N+table_adjust
*/

static void fix_tables_after_pullout(st_select_lex *parent_select,
                                     st_select_lex *removed_select,
                                     TABLE_LIST *tr,
                                     uint table_adjust)
{
  if (tr->is_merged())
  {
    // Update select list of merged derived tables:
    for (Field_translator *transl= tr->field_translation;
         transl < tr->field_translation_end;
         transl++)
    {
      assert(transl->item->fixed);
      transl->item->fix_after_pullout(parent_select, removed_select);
    }
    // Update used table info for the WHERE clause of the derived table
    assert(!tr->derived_where_cond ||
           tr->derived_where_cond->fixed);
    if (tr->derived_where_cond)
      tr->derived_where_cond->fix_after_pullout(parent_select,
                                                removed_select);
  }

  /*
    If join_cond() is fixed, it contains a join condition from a subquery
    that has already been resolved. Call fix_after_pullout() to update
    used table information since table numbers may have changed.
    If join_cond() is not fixed, it contains a condition that was generated
    in the derived table merge operation, which will be fixed later.
    This condition may also contain a fixed part, but this is saved as
    derived_where_cond and is pulled out explicitly.
  */
  if (tr->join_cond() && tr->join_cond()->fixed)
      tr->join_cond()->fix_after_pullout(parent_select, removed_select);

  if (tr->nested_join)
  {
    // In case a derived table is merged-in, these fields need adjustment:
    tr->nested_join->sj_corr_tables<<= table_adjust;
    tr->nested_join->sj_depends_on<<= table_adjust;

    List_iterator<TABLE_LIST> it(tr->nested_join->join_list);
    TABLE_LIST *child;
    while ((child= it++))
      fix_tables_after_pullout(parent_select, removed_select, child,
                               table_adjust);
  }
}


/**
  Convert a subquery predicate of this query block into a TABLE_LIST semi-join
  nest.

  @param subq_pred   Subquery predicate to be converted.
                     This is either an IN, =ANY or EXISTS predicate.

  @retval FALSE OK
  @retval TRUE  Error

  @details

  The following transformations are performed:

  1. IN/=ANY predicates on the form:

  SELECT ...
  FROM ot1 ... otN
  WHERE (oe1, ... oeM) IN (SELECT ie1, ..., ieM)
                           FROM it1 ... itK
                          [WHERE inner-cond])
   [AND outer-cond]
  [GROUP BY ...] [HAVING ...] [ORDER BY ...]

  are transformed into:

  SELECT ...
  FROM (ot1 ... otN) SJ (it1 ... itK)
                     ON (oe1, ... oeM) = (ie1, ..., ieM)
                        [AND inner-cond]
  [WHERE outer-cond]
  [GROUP BY ...] [HAVING ...] [ORDER BY ...]

  Notice that the inner-cond may contain correlated and non-correlated
  expressions. Further transformations will analyze and break up such
  expressions.

  Prepared Statements: the transformation is permanent:
   - Changes in TABLE_LIST structures are naturally permanent
   - Item tree changes are performed on statement MEM_ROOT:
      = we activate statement MEM_ROOT
      = this function is called before the first fix_prepare_information call.

  This is intended because the criteria for subquery-to-sj conversion remain
  constant for the lifetime of the Prepared Statement.
*/
bool
SELECT_LEX::convert_subquery_to_semijoin(Item_exists_subselect *subq_pred)
{
  TABLE_LIST *emb_tbl_nest= NULL;
  List<TABLE_LIST> *emb_join_list= &top_join_list;
  THD *const thd= subq_pred->unit->thd;
  DBUG_ENTER("convert_subquery_to_semijoin");

  assert(subq_pred->substype() == Item_subselect::IN_SUBS);

  bool outer_join= false;  // True if predicate is inner to an outer join

  /*
    Find out where to insert the semi-join nest and the generated condition.

    For t1 LEFT JOIN t2, embedding_join_nest will be t2.
    Note that t2 may be a simple table or may itself be a join nest
    (e.g. in the case t1 LEFT JOIN (t2 JOIN t3))
  */
  if (subq_pred->embedding_join_nest != NULL)
  {
    // Is this on inner side of an outer join?
    outer_join= subq_pred->embedding_join_nest->is_inner_table_of_outer_join();

    if (subq_pred->embedding_join_nest->nested_join)
    {
      /*
        We're dealing with

          ... [LEFT] JOIN  ( ... ) ON (subquery AND condition) ...

        The sj-nest will be inserted into the brackets nest.
      */
      emb_tbl_nest=  subq_pred->embedding_join_nest;
      emb_join_list= &emb_tbl_nest->nested_join->join_list;
    }
    else if (!subq_pred->embedding_join_nest->outer_join)
    {
      /*
        We're dealing with

          ... INNER JOIN tblX ON (subquery AND condition) ...

        The sj-nest will be tblX's "sibling", i.e. another child of its
        parent. This is ok because tblX is joined as an inner join.
      */
      emb_tbl_nest= subq_pred->embedding_join_nest->embedding;
      if (emb_tbl_nest)
        emb_join_list= &emb_tbl_nest->nested_join->join_list;
    }
    else if (!subq_pred->embedding_join_nest->nested_join)
    {
      TABLE_LIST *outer_tbl= subq_pred->embedding_join_nest;      
      /*
        We're dealing with

          ... LEFT JOIN tbl ON (on_expr AND subq_pred) ...

        we'll need to convert it into:

          ... LEFT JOIN ( tbl SJ (subq_tables) ) ON (on_expr AND subq_pred) ...
                        |                      |
                        |<----- wrap_nest ---->|
        
        Q:  other subqueries may be pointing to this element. What to do?
        A1: simple solution: copy *subq_pred->embedding_join_nest= *parent_nest.
            But we'll need to fix other pointers.
        A2: Another way: have TABLE_LIST::next_ptr so the following
            subqueries know the table has been nested.
        A3: changes in the TABLE_LIST::outer_join will make everything work
            automatically.
      */
      TABLE_LIST *const wrap_nest=
        TABLE_LIST::new_nested_join(thd->mem_root, "(sj-wrap)",
                                    outer_tbl->embedding, outer_tbl->join_list,
                                    this);
      if (wrap_nest == NULL)
        DBUG_RETURN(true);

      wrap_nest->nested_join->join_list.push_back(outer_tbl);

      outer_tbl->embedding= wrap_nest;
      outer_tbl->join_list= &wrap_nest->nested_join->join_list;

      /*
        An important note, if this 'PREPARE stmt'.
        The FROM clause of the outer query now looks like
        CONCAT(original FROM clause of outer query, sj-nest).
        Given that the original FROM clause is reversed, this list is
        interpreted as "sj-nest is first".
        Thus, at a next execution, setup_natural_join_types() will decide that
        the name resolution context of the FROM clause should start at the
        first inner table in sj-nest.
        However, note that in the present function we do not change
        first_name_resolution_table (and friends) of sj-inner tables.
        So, at the next execution, name resolution for columns of
        outer-table columns is bound to fail (the first inner table does
        not have outer tables in its chain of resolution).
        Fortunately, Item_field::cached_table, which is set during resolution
        of 'PREPARE stmt', gives us the answer and avoids a failing search.
      */

      /*
        wrap_nest will take place of outer_tbl, so move the outer join flag
        and join condition.
      */
      wrap_nest->outer_join= outer_tbl->outer_join;
      outer_tbl->outer_join= 0;

      // There are item-rollback problems in this function: see bug#16926177
      wrap_nest->set_join_cond(outer_tbl->join_cond()->real_item());
      outer_tbl->set_join_cond(NULL);

      List_iterator<TABLE_LIST> li(*wrap_nest->join_list);
      TABLE_LIST *tbl;
      while ((tbl= li++))
      {
        if (tbl == outer_tbl)
        {
          li.replace(wrap_nest);
          break;
        }
      }

      /*
        outer_tbl is replaced by wrap_nest.
        For subselects, update embedding_join_nest to point to wrap_nest
        instead of outer_tbl
      */
      for (Item_exists_subselect **subquery= sj_candidates->begin();
           subquery < sj_candidates->end();
           subquery++)
      {
        if ((*subquery)->embedding_join_nest == outer_tbl)
          (*subquery)->embedding_join_nest= wrap_nest;
      }

      /*
        Ok now wrap_nest 'contains' outer_tbl and we're ready to add the 
        semi-join nest into it
      */
      emb_join_list= &wrap_nest->nested_join->join_list;
      emb_tbl_nest=  wrap_nest;
    }
  }

  TABLE_LIST *const sj_nest=
    TABLE_LIST::new_nested_join(thd->mem_root, "(sj-nest)",
                                emb_tbl_nest, emb_join_list, this);
  if (sj_nest == NULL)
    DBUG_RETURN(true);       /* purecov: inspected */

  NESTED_JOIN *const nested_join= sj_nest->nested_join;

  /* Nests do not participate in those 'chains', so: */
  /* sj_nest->next_leaf= sj_nest->next_local= sj_nest->next_global == NULL*/
  emb_join_list->push_back(sj_nest);

  /*
    Natural joins inside a semi-join nest were already processed when the
    subquery went through initial preparation.
  */
  sj_nest->nested_join->natural_join_processed= true;
  /* 
    nested_join->used_tables and nested_join->not_null_tables are
    initialized in simplify_joins().
  */
  
  st_select_lex *const subq_select= subq_pred->unit->first_select();

  nested_join->query_block_id= subq_select->select_number;

  // Merge tables from underlying query block into this join nest
  if (sj_nest->merge_underlying_tables(subq_select))
    DBUG_RETURN(true);       /* purecov: inspected */
  
  /*
    Add tables from subquery at end of leaf table chain.
    (This also means that table map for parent query block tables are unchanged)
  */
  TABLE_LIST *tl;
  for (tl= leaf_tables; tl->next_leaf; tl= tl->next_leaf)
  {}
  tl->next_leaf= subq_select->leaf_tables;

  // Add tables from subquery at end of next_local chain.
  for (tl= get_table_list(); tl->next_local; tl= tl->next_local)
  {}
  tl->next_local= subq_select->get_table_list();

  // Note that subquery's tables are already in the next_global chain

  // Remove the original subquery predicate from the WHERE/ON
  // The subqueries were replaced for Item_int(1) earlier
  // @todo also reset the 'with_subselect' there.

  // Walk through child's tables and adjust table map
  uint table_no= leaf_table_count;
  for (tl= subq_select->leaf_tables; tl; tl= tl->next_leaf, table_no++)
    tl->set_tableno(table_no);

  // Adjust table and expression counts in parent query block:
  derived_table_count+= subq_select->derived_table_count;
  materialized_derived_table_count+=
    subq_select->materialized_derived_table_count;
  has_sj_nests|= subq_select->has_sj_nests;
  partitioned_table_count+= subq_select->partitioned_table_count;
  leaf_table_count+= subq_select->leaf_table_count;
  cond_count+= subq_select->cond_count;
  between_count+= subq_select->between_count;

  if (outer_join)
    propagate_nullability(&sj_nest->nested_join->join_list, true);

  nested_join->sj_outer_exprs.empty();
  nested_join->sj_inner_exprs.empty();

  /*
    @todo: Add similar conversion for subqueries other than IN.
  */
  if (subq_pred->substype() == Item_subselect::IN_SUBS)
  {
    Item_in_subselect *in_subq_pred= (Item_in_subselect *)subq_pred;

    assert(is_fixed_or_outer_ref(in_subq_pred->left_expr));

    in_subq_pred->exec_method= Item_exists_subselect::EXEC_SEMI_JOIN;
    /*
      sj_corr_tables is supposed to contain non-trivially correlated tables,
      but here it is set to contain all correlated tables.
      @todo: Add analysis step that assigns only the set of non-trivially
      correlated tables to sj_corr_tables.
    */
    nested_join->sj_corr_tables= subq_pred->used_tables();

    /*
      sj_depends_on contains the set of outer tables referred in the
      subquery's WHERE clause as well as tables referred in the IN predicate's
      left-hand side.
    */
    nested_join->sj_depends_on=  subq_pred->used_tables() |
                                 in_subq_pred->left_expr->used_tables();

    // Put the subquery's WHERE into semi-join's condition.
    Item *sj_cond= subq_select->where_cond();

    /*
    Create the IN-equalities and inject them into semi-join's ON condition.
    Additionally, for LooseScan strategy
     - Record the number of IN-equalities.
     - Create list of pointers to (oe1, ..., ieN). We'll need the list to
       see which of the expressions are bound and which are not (for those
       we'll produce a distinct stream of (ie_i1,...ie_ik).

       (TODO: can we just create a list of pointers and hope the expressions
       will not substitute themselves on fix_fields()? or we need to wrap
       them into Item_direct_view_refs and store pointers to those. The
       pointers to Item_direct_view_refs are guaranteed to be stable as 
       Item_direct_view_refs doesn't substitute itself with anything in 
       Item_direct_view_ref::fix_fields.

    We have a special case for IN predicates with a scalar subquery or a
    row subquery in the predicand (left operand), such as this:
       (SELECT 1,2 FROM t1) IN (SELECT x,y FROM t2)
    We cannot make the join condition 1=x AND 2=y, since that might evaluate
    to TRUE even if t1 is empty. Instead make the join condition
    (SELECT 1,2 FROM t1) = (x,y) in this case.

    */

    Item_subselect *left_subquery=
      (in_subq_pred->left_expr->type() == Item::SUBSELECT_ITEM) ?
      static_cast<Item_subselect *>(in_subq_pred->left_expr) : NULL;

    if (left_subquery &&
        (left_subquery->substype() == Item_subselect::SINGLEROW_SUBS))
    {
      List<Item> ref_list;
      Item *header= subq_select->ref_pointer_array[0];
      for (uint i= 1; i < in_subq_pred->left_expr->cols(); i++)
      {
        ref_list.push_back(subq_select->ref_pointer_array[i]);
      }

      Item_row *right_expr= new Item_row(header, ref_list);
      if (!right_expr)
        DBUG_RETURN(true);      /* purecov: inspected */

      nested_join->sj_outer_exprs.push_back(in_subq_pred->left_expr);
      nested_join->sj_inner_exprs.push_back(right_expr);
      Item_func_eq *item_eq=
        new Item_func_eq(in_subq_pred->left_expr,
                         right_expr);
      if (item_eq == NULL)
        DBUG_RETURN(true);      /* purecov: inspected */

      sj_cond= and_items(sj_cond, item_eq);
      if (sj_cond == NULL)
        DBUG_RETURN(true);      /* purecov: inspected */
    }
    else
    {
      for (uint i= 0; i < in_subq_pred->left_expr->cols(); i++)
      {
        Item *const li= in_subq_pred->left_expr->element_index(i);
        nested_join->sj_outer_exprs.push_back(li);
        nested_join->sj_inner_exprs.push_back(subq_select->ref_pointer_array[i]);

        Item_func_eq *item_eq= 
          new Item_func_eq(li, subq_select->ref_pointer_array[i]);

        if (item_eq == NULL)
          DBUG_RETURN(true);      /* purecov: inspected */

        /*
          li [left_expr->element_index(i)] can be a transient Item_outer_ref,
          whose usage has already been marked for rollback, but we need to roll
          back this location (inside Item_func_eq) in stead, since this is the
          place that matters after this semijoin transformation. arguments()
          gets the address of li as stored in item_eq ("place").
        */
        thd->replace_rollback_place(item_eq->arguments());

        sj_cond= and_items(sj_cond, item_eq);
        if (sj_cond == NULL)
          DBUG_RETURN(true);      /* purecov: inspected */
      }
    }
    // Fix the created equality and AND

    Opt_trace_array sj_on_trace(&thd->opt_trace,
                                "evaluating_constant_semijoin_conditions");
    sj_cond->top_level_item();
    if (sj_cond->fix_fields(thd, &sj_cond))
      DBUG_RETURN(true);          /* purecov: inspected */

    // Attach semi-join condition to semi-join nest
    sj_nest->set_sj_cond(sj_cond);
  }

  // Unlink the subquery's query expression:
  subq_select->master_unit()->exclude_level();

  // Merge subquery's name resolution contexts into parent's
  merge_contexts(subq_select);

  repoint_contexts_of_join_nests(subq_select->top_join_list);

  // Update table map for the semi-join condition
  sj_nest->sj_cond()->fix_after_pullout(this, subq_select);

  // Update table map for semi-join nest's WHERE condition and join conditions
  fix_tables_after_pullout(this, subq_select, sj_nest, 0);

  //TODO fix QT_
  DBUG_EXECUTE("where",
               print_where(sj_nest->sj_cond(),"SJ-COND", QT_ORDINARY););

  if (emb_tbl_nest)
  {
    // Inject semi-join condition into parent's join condition
    emb_tbl_nest->set_join_cond(and_items(emb_tbl_nest->join_cond(),
                                          sj_nest->sj_cond()));
    if (emb_tbl_nest->join_cond() == NULL)
      DBUG_RETURN(true);
    emb_tbl_nest->join_cond()->top_level_item();
    if (!emb_tbl_nest->join_cond()->fixed &&
        emb_tbl_nest->join_cond()->fix_fields(thd,
                                              emb_tbl_nest->join_cond_ref()))
      DBUG_RETURN(true);
  }
  else
  {
    // Inject semi-join condition into parent's WHERE condition
    m_where_cond= and_items(m_where_cond, sj_nest->sj_cond());
    if (m_where_cond == NULL)
      DBUG_RETURN(true);
    m_where_cond->top_level_item();
    if (m_where_cond->fix_fields(thd, &m_where_cond))
      DBUG_RETURN(true);
  }

  if (subq_select->ftfunc_list->elements &&
      add_ftfunc_list(subq_select->ftfunc_list))
    DBUG_RETURN(true);        /* purecov: inspected */

  // This query block has semi-join nests
  has_sj_nests= true;

  DBUG_RETURN(false);
}


/**
  Merge a derived table or view into a query block.
  If some constraint prevents the derived table from being merged then do
  nothing, which means the table will be prepared for materialization later.

  After this call, check is_merged() to see if the table was really merged.

  @param thd           Thread handler
  @param derived_table Derived table which is to be merged.

  @return false if successful, true if error
*/

bool SELECT_LEX::merge_derived(THD *thd, TABLE_LIST *derived_table)
{
  DBUG_ENTER("SELECT_LEX::merge_derived");

  if (!derived_table->is_view_or_derived() || derived_table->is_merged())
    DBUG_RETURN(false);

  SELECT_LEX_UNIT *const derived_unit= derived_table->derived_unit();

  // A derived table must be prepared before we can merge it
  assert(derived_unit->is_prepared());

  LEX *const lex= parent_lex;

  // Check whether the outer query allows merged views
  if ((master_unit() == lex->unit &&
       !lex->can_use_merged()) ||
      lex->can_not_use_merged())
    DBUG_RETURN(false);

  /*
    @todo: The implementation of LEX::can_use_merged() currently avoids
           merging of views that are contained in other views if
           can_use_merged() returns false.
  */
  // Check whether derived table is mergeable, and directives allow merging
  if (!derived_unit->is_mergeable() ||
      derived_table->algorithm == VIEW_ALGORITHM_TEMPTABLE ||
      (!thd->optimizer_switch_flag(OPTIMIZER_SWITCH_DERIVED_MERGE) &&
       derived_table->algorithm != VIEW_ALGORITHM_MERGE))
    DBUG_RETURN(false);

  SELECT_LEX *const derived_select= derived_unit->first_select();
  /*
    If STRAIGHT_JOIN is specified, it is not valid to merge in a query block
    that contains semi-join nests
  */
  if ((active_options() & SELECT_STRAIGHT_JOIN) && derived_select->has_sj_nests)
    DBUG_RETURN(false);

  // Check that we have room for the merged tables in the table map:
  if (leaf_table_count + derived_select->leaf_table_count - 1 > MAX_TABLES)
    DBUG_RETURN(false);

  derived_table->set_merged();

  DBUG_PRINT("info", ("algorithm: MERGE"));

  Opt_trace_context *const trace= &thd->opt_trace;
  Opt_trace_object trace_wrapper(trace);
  Opt_trace_object trace_derived(trace,
                                 derived_table->is_view() ? "view" : "derived");
  trace_derived.add_utf8_table(derived_table).
    add("select#", derived_select->select_number).
    add("merged", true);

  Prepared_stmt_arena_holder ps_arena_holder(thd);

  // Save offset for table number adjustment
  uint table_adjust= derived_table->tableno();

  // Set up permanent list of underlying tables of a merged view
  derived_table->merge_underlying_list= derived_select->get_table_list();

  /**
    A view is updatable if any underlying table is updatable.
    A view is insertable-into if all underlying tables are insertable.
    A view is not updatable nor insertable if it contains an outer join
    @see mysql_register_view()
  */
  if (derived_table->is_view())
  {
    bool updatable= false;
    bool insertable= true;
    bool outer_joined= false;
    for (TABLE_LIST *tr= derived_table->merge_underlying_list;
         tr;
         tr= tr->next_local)
    {
      updatable|= tr->is_updatable();
      insertable&= tr->is_insertable();
      outer_joined|= tr->is_inner_table_of_outer_join();
    }
    updatable&= !outer_joined;
    insertable&= !outer_joined;
    if (updatable)
      derived_table->set_updatable();
    if (insertable)
      derived_table->set_insertable();
  }
  // Add a nested join object to the derived table object
  if (!(derived_table->nested_join=
       (NESTED_JOIN *) thd->mem_calloc(sizeof(NESTED_JOIN))))
    DBUG_RETURN(true);        /* purecov: inspected */
  derived_table->nested_join->join_list.empty();//Should be done by constructor!

  // Merge tables from underlying query block into this join nest
  if (derived_table->merge_underlying_tables(derived_select))
    DBUG_RETURN(true);       /* purecov: inspected */

  // Replace derived table in leaf table list with underlying tables:
  for (TABLE_LIST **tl= &leaf_tables; *tl; tl= &(*tl)->next_leaf)
  {
    if (*tl == derived_table)
    {
      for (TABLE_LIST *leaf= derived_select->leaf_tables; leaf;
           leaf= leaf->next_leaf)
      {
        if (leaf->next_leaf == NULL)
        {
          leaf->next_leaf= (*tl)->next_leaf;
          break;
        }
      }
      *tl= derived_select->leaf_tables;
      break;
    }
  }

  leaf_table_count+= (derived_select->leaf_table_count - 1);
  derived_table_count+= derived_select->derived_table_count;
  materialized_derived_table_count+=
    derived_select->materialized_derived_table_count;
  has_sj_nests|= derived_select->has_sj_nests;
  partitioned_table_count+= derived_select->partitioned_table_count;
  cond_count+= derived_select->cond_count;
  between_count+= derived_select->between_count;

  // Propagate schema table indication:
  // @todo: Add to BASE options instead
  if (derived_select->active_options() & OPTION_SCHEMA_TABLE)
    add_base_options(OPTION_SCHEMA_TABLE);

  // Propagate nullability for derived tables within outer joins:
  if (derived_table->is_inner_table_of_outer_join())
    propagate_nullability(&derived_table->nested_join->join_list, true);

  select_n_having_items+= derived_select->select_n_having_items;

  // Merge the WHERE clause into the outer query block
  if (derived_table->merge_where(thd))
    DBUG_RETURN(true);        /* purecov: inspected */

  if (derived_table->create_field_translation(thd))
    DBUG_RETURN(true);        /* purecov: inspected */

  // Exclude the derived table query expression from query graph.
  derived_unit->exclude_level();

  // Don't try to access it:
  derived_table->set_derived_unit((SELECT_LEX_UNIT *)1);

  // Merge subquery's name resolution contexts into parent's
  merge_contexts(derived_select);

  repoint_contexts_of_join_nests(derived_select->top_join_list);

  // Leaf tables have been shuffled, so update table numbers for them
  remap_tables(thd);

  // Update table info of referenced expressions after query block is merged
  fix_tables_after_pullout(this, derived_select, derived_table, table_adjust);

  if (derived_select->is_ordered())
  {
    /*
      An ORDER BY clause is moved to an outer query block
      - if the outer query block allows ordering, and
      - that refers to this view/derived table only, and
      - is not part of a UNION, and
      - may have a WHERE clause but is not grouped or aggregated and is not
        itself ordered.
     Otherwise the ORDER BY clause is ignored.

     Only SELECT statements and single-table UPDATE and DELETE statements
     allow ordering.

     Up to version 5.6 included, ORDER BY was unconditionally merged.
     Currently we only merge in the simple case above, which ensures
     backward compatibility for most reasonable use cases.

     Note that table numbers in order_list do not need updating, since
     the outer query contains only one table reference.
    */
    // LIMIT currently blocks derived table merge
    assert(!derived_select->has_limit());

    if ((lex->sql_command == SQLCOM_SELECT ||
         lex->sql_command == SQLCOM_UPDATE ||
         lex->sql_command == SQLCOM_DELETE) &&
        !(master_unit()->is_union() ||
          is_grouped() ||
          is_distinct() ||
          is_ordered() ||
          get_table_list()->next_local != NULL))
    {
      order_list.push_back(&derived_select->order_list);
      /*
        If at outer-most level (not within another derived table), ensure
        the ordering columns are marked in read_set, since columns selected
        from derived tables are not marked in initial resolving.
      */
      if (!thd->derived_tables_processing)
      {
        Mark_field mf(thd->mark_used_columns);
        for (ORDER *o = derived_select->order_list.first; o != NULL;
             o = o->next) {
          o->item[0]->walk(&Item::mark_field_in_map, Item::WALK_POSTFIX,
                           pointer_cast<uchar *>(&mf));
          /*
            If the expression in order by was part of the select list
            of the merged derived query block and if it is unused in the
            outer query block, delete_unused_merged_columns() could
            delete the select expression. So, we set that the merged
            order by expression is used and therefore should not be deleted.
          */
          o->item[0]->walk(&Item::propagate_set_derived_used,
                           Item::WALK_POSTFIX, NULL);
        }
      }
    }
    else
    {
      derived_select->empty_order_list(this);
      trace_derived.add_alnum("transformations_to_derived_table",
                              "removed_ordering");
    }
  }

  // Add any full-text functions from derived table into outer query
  if (derived_select->ftfunc_list->elements &&
      add_ftfunc_list(derived_select->ftfunc_list))
    DBUG_RETURN(true);        /* purecov: inspected */

  DBUG_RETURN(false);
}


/**
   Destructively replaces a sub-condition inside a condition tree. The
   parse tree is also altered.

   @note Because of current requirements for semijoin flattening, we do not
   need to recurse here, hence this function will only examine the top-level
   AND conditions. (see SELECT_LEX::prepare, comment starting with "Check if
   the subquery predicate can be executed via materialization".)
   
   @param thd  thread handler

   @param tree Must be the handle to the top level condition. This is needed
   when the top-level condition changes.

   @param old_cond The condition to be replaced.

   @param new_cond The condition to be substituted.

   @param do_fix_fields If true, Item::fix_fields(THD*, Item**) is called for
   the new condition.

   @return error status

   @retval true If there was an error.
   @retval false If successful.
*/

static bool replace_subcondition(THD *thd, Item **tree,
                                 Item *old_cond, Item *new_cond,
                                 bool do_fix_fields)
{
  if (*tree == old_cond)
  {
    *tree= new_cond;
    if (do_fix_fields && new_cond->fix_fields(thd, tree))
      return TRUE;
    return FALSE;
  }
  else if ((*tree)->type() == Item::COND_ITEM) 
  {
    List_iterator<Item> li(*((Item_cond*)(*tree))->argument_list());
    Item *item;
    while ((item= li++))
    {
      if (item == old_cond) 
      {
        li.replace(new_cond);
        if (do_fix_fields && new_cond->fix_fields(thd, li.ref()))
          return TRUE;
        return FALSE;
      }
    }
  }
  else
    // If we came here it means there were an error during prerequisites check.
    assert(FALSE);

  return TRUE;
}


/*
  Convert semi-join subquery predicates into semi-join join nests
 
  DESCRIPTION

    Convert candidate subquery predicates into semi-join join nests. This 
    transformation is performed once in query lifetime and is irreversible.
    
    Conversion of one subquery predicate
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    We start with a join that has a semi-join subquery:

      SELECT ...
      FROM ot, ...
      WHERE oe IN (SELECT ie FROM it1 ... itN WHERE subq_where) AND outer_where

    and convert it into a semi-join nest:

      SELECT ...
      FROM ot SEMI JOIN (it1 ... itN), ...
      WHERE outer_where AND subq_where AND oe=ie

    that is, in order to do the conversion, we need to 

     * Create the "SEMI JOIN (it1 .. itN)" part and add it into the parent
       query's FROM structure.
     * Add "AND subq_where AND oe=ie" into parent query's WHERE (or ON if
       the subquery predicate was in an ON expression)
     * Remove the subquery predicate from the parent query's WHERE

    Considerations when converting many predicates
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    A join may have at most MAX_TABLES tables. This may prevent us from
    flattening all subqueries when the total number of tables in parent and
    child selects exceeds MAX_TABLES. In addition, one slot is reserved per
    semi-join nest, in case the subquery needs to be materialized in a
    temporary table.
    We deal with this problem by flattening children's subqueries first and
    then using a heuristic rule to determine each subquery predicate's
    "priority".

  RETURN 
    FALSE  OK
    TRUE   Error
*/
bool SELECT_LEX::flatten_subqueries()
{
  DBUG_ENTER("flatten_subqueries");

  if (sj_candidates->empty())
    DBUG_RETURN(FALSE);

  Item_exists_subselect **subq,
    **subq_begin= sj_candidates->begin(),
    **subq_end= sj_candidates->end();

  THD *const thd= (*subq_begin)->unit->thd;
  Opt_trace_context *const trace= &thd->opt_trace;

  /*
    Semijoin flattening is bottom-up. Indeed, we have this execution flow,
    for SELECT#1 WHERE X IN (SELECT #2 WHERE Y IN (SELECT#3)) :

    SELECT_LEX::prepare() (select#1)
       -> fix_fields() on IN condition
           -> SELECT_LEX::prepare() on subquery (select#2)
               -> fix_fields() on IN condition
                    -> SELECT_LEX::prepare() on subquery (select#3)
                    <- SELECT_LEX::prepare()
               <- fix_fields()
               -> flatten_subqueries: merge #3 in #2
               <- flatten_subqueries
           <- SELECT_LEX::prepare()
       <- fix_fields()
       -> flatten_subqueries: merge #2 in #1

    Note that flattening of #(N) is done by its parent JOIN#(N-1), because
    there are cases where flattening is not possible and only the parent can
    know.
   */
  for (subq= subq_begin; subq < subq_end; subq++)
  {
    /*
      Currently, we only support transformation of IN subqueries.
    */
    assert((*subq)->substype() == Item_subselect::IN_SUBS);

    st_select_lex *child_select= (*subq)->unit->first_select();

    // Check that we proceeded bottom-up
    assert(child_select->sj_candidates == NULL);

    (*subq)->sj_convert_priority= 
      (((*subq)->unit->uncacheable & UNCACHEABLE_DEPENDENT) ? MAX_TABLES : 0) +
      child_select->leaf_table_count;
  }

  /* 
    2. Pick which subqueries to convert:
      sort the subquery array
      - prefer correlated subqueries over uncorrelated;
      - prefer subqueries that have greater number of outer tables;
  */
  my_qsort(subq_begin,
           sj_candidates->size(), sj_candidates->element_size(),
           reinterpret_cast<qsort_cmp>(subq_sj_candidate_cmp));

  // A permanent transformation is going to start, so:
  Prepared_stmt_arena_holder ps_arena_holder(thd);

  // #tables-in-parent-query + #tables-in-subquery + sj nests <= MAX_TABLES
  /* Replace all subqueries to be flattened with Item_int(1) */

  uint table_count= leaf_table_count;
  for (subq= subq_begin; subq < subq_end; subq++)
  {
    // Add the tables in the subquery nest plus one in case of materialization:
    const uint tables_added=
      (*subq)->unit->first_select()->leaf_table_count + 1;
    (*subq)->sj_chosen= table_count + tables_added <= MAX_TABLES;

    if (!(*subq)->sj_chosen)
      continue;

    table_count+= tables_added;

    // In WHERE/ON of parent query, replace IN(subq) with "1" (<=>TRUE)
    Item **tree= ((*subq)->embedding_join_nest == NULL) ?
                 &m_where_cond :
                (*subq)->embedding_join_nest->join_cond_ref();
    if (replace_subcondition(thd, tree, *subq, new Item_int(1), FALSE))
      DBUG_RETURN(TRUE); /* purecov: inspected */
  }

  for (subq= subq_begin; subq < subq_end; subq++)
  {
    if (!(*subq)->sj_chosen)
      continue;

    OPT_TRACE_TRANSFORM(trace, oto0, oto1,
                        (*subq)->unit->first_select()->select_number,
                        "IN (SELECT)", "semijoin");
    oto1.add("chosen", true);
    if (convert_subquery_to_semijoin(*subq))
      DBUG_RETURN(TRUE);
  }
  /* 
    3. Finalize the subqueries that we did not convert,
       ie. perform IN->EXISTS rewrite.
  */
  for (subq= subq_begin; subq < subq_end; subq++)
  {
    if ((*subq)->sj_chosen)
      continue;
    {
      OPT_TRACE_TRANSFORM(trace, oto0, oto1,
                          (*subq)->unit->first_select()->select_number,
                          "IN (SELECT)", "semijoin");
      oto1.add("chosen", false);
    }
    Item_subselect::trans_res res;
    (*subq)->changed= 0;
    (*subq)->fixed= 0;

    SELECT_LEX *save_select_lex= thd->lex->current_select();
    thd->lex->set_current_select((*subq)->unit->first_select());

    // This is the only part of the function which uses a JOIN.
    res= (*subq)->select_transformer((*subq)->unit->first_select());

    thd->lex->set_current_select(save_select_lex);

    if (res == Item_subselect::RES_ERROR)
      DBUG_RETURN(TRUE);

    (*subq)->changed= 1;
    (*subq)->fixed= 1;

    Item *substitute= (*subq)->substitution;
    const bool do_fix_fields= !(*subq)->substitution->fixed;
    const bool subquery_in_join_clause= (*subq)->embedding_join_nest != NULL;

    Item **tree= subquery_in_join_clause ?
      ((*subq)->embedding_join_nest->join_cond_ref()) : &m_where_cond;
    if (replace_subcondition(thd, tree, *subq, substitute, do_fix_fields))
      DBUG_RETURN(TRUE);
    (*subq)->substitution= NULL;
  }

  sj_candidates->clear();
  DBUG_RETURN(FALSE);
}

bool SELECT_LEX::is_in_select_list(Item *cand) {
  List_iterator<Item> li(fields_list);
  Item *item;
  while ((item = li++)) {
    // Use a walker to detect if cand is present in this select item

    if (item->walk(&Item::find_item_processor, Item::WALK_SUBQUERY_POSTFIX,
                   pointer_cast<uchar *>(cand)))
      return true;
  }
  return false;
}

/**
  Propagate nullability into inner tables of outer join operation

  @param tables: List of tables and join nests, start at top_join_list
  @param nullable: true: Set all underlying tables as nullable
*/
static void propagate_nullability(List<TABLE_LIST> *tables, bool nullable)
{
  List_iterator<TABLE_LIST> li(*tables);
  TABLE_LIST *tr;

  while ((tr= li++))
  {
    if (tr->table && !tr->table->is_nullable() && (nullable || tr->outer_join))
      tr->table->set_nullable();
    if (tr->nested_join == NULL)
      continue;
    propagate_nullability(&tr->nested_join->join_list,
                          nullable || tr->outer_join);
  }
}


/**
  Propagate exclusion from unique table check into all subqueries belonging
  to this query block.

  This function can be applied to all subqueries of a materialized derived
  table or view.
*/

void st_select_lex::propagate_unique_test_exclusion()
{
  for (SELECT_LEX_UNIT *unit= first_inner_unit(); unit; unit= unit->next_unit())
    for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
      sl->propagate_unique_test_exclusion();

  exclude_from_table_unique_test= true;
}


/**
  Add a list of full-text function elements into a query block.

  @param ftfuncs   List of full-text function elements to add.

  @returns false if success, true if error
*/

bool SELECT_LEX::add_ftfunc_list(List<Item_func_match> *ftfuncs)
{
  Item_func_match *ifm;
  List_iterator_fast<Item_func_match> li(*ftfuncs);
  while ((ifm= li++))
  {
    if (ftfunc_list->push_back(ifm))
      return true;        /* purecov: inspected */
  }
  return false;
}


/**
   Go through a list of tables and join nests, recursively, and repoint
   its select_lex pointer.

   @param  join_list  List of tables and join nests
*/
void SELECT_LEX::repoint_contexts_of_join_nests(List<TABLE_LIST> join_list)
{
  List_iterator_fast<TABLE_LIST> ti(join_list);
  TABLE_LIST *tbl;
  while ((tbl= ti++))
  {
    tbl->select_lex= this;
    if (tbl->nested_join)
      repoint_contexts_of_join_nests(tbl->nested_join->join_list);
  }
}


/**
  Merge name resolution context objects belonging to an inner subquery
  to parent query block.
  Update all context objects to have this base query block.
  Used when a subquery's query block is merged into its parent.

  @param inner  Subquery for which context objects are to be merged.
*/
void SELECT_LEX::merge_contexts(SELECT_LEX *inner)
{
  for (Name_resolution_context *ctx= inner->first_context;
       ctx != NULL;
       ctx= ctx->next_context)
  {
    ctx->select_lex= this;
    if (ctx->next_context == NULL)
    {
      ctx->next_context= first_context;
      first_context= inner->first_context;
      inner->first_context= NULL;
      break;
    }
  }
}


/**
  Fix fields referenced from inner query blocks.

  @param thd               Thread handle

  @details
    The function serves 3 purposes

    - adds fields referenced from inner query blocks to the current select list

    - Decides which class to use to reference the items (Item_ref or
      Item_direct_ref)

    - fixes references (Item_ref objects) to these fields.

    If a field isn't already on the select list and the ref_ptrs array
    is provided then it is added to the all_fields list and the pointer to
    it is saved in the ref_ptrs array.

    The class to access the outer field is determined by the following rules:

    -#. If the outer field isn't used under an aggregate function then the
        Item_ref class should be used.

    -#. If the outer field is used under an aggregate function and this
        function is, in turn, aggregated in the query block where the outer
        field was resolved or some query nested therein, then the
        Item_direct_ref class should be used. Also it should be used if we are
        grouping by a subquery containing the outer field.

    The resolution is done here and not at the fix_fields() stage as
    it can be done only after aggregate functions are fixed and pulled up to
    selects where they are to be aggregated.

    When the class is chosen it substitutes the original field in the
    Item_outer_ref object.

    After this we proceed with fixing references (Item_outer_ref objects) to
    this field from inner subqueries.

  @return false if success, true if error
 */

bool SELECT_LEX::fix_inner_refs(THD *thd)
{
  Item_outer_ref *ref;

  List_iterator<Item_outer_ref> ref_it(inner_refs_list);
  while ((ref= ref_it++))
  {
    bool direct_ref= false;
    Item *item= ref->outer_ref;
    Item **item_ref= ref->ref;
    /*
      TODO: this field item already might be present in the select list.
      In this case instead of adding new field item we could use an
      existing one. The change will lead to less operations for copying fields,
      smaller temporary tables and less data passed through filesort.
    */
    if (!ref_ptrs.is_null() && !ref->found_in_select_list)
    {
      /* 
        Add the field item to the select list of the current select.
        If it's needed reset each Item_ref item that refers this field with
        a new reference taken from ref_pointer_array.
      */
      item_ref= add_hidden_item(item);
    }

    if (ref->in_sum_func)
    {
      if (ref->in_sum_func->nest_level > nest_level)
        direct_ref= true;
      else
      {
        for (Item_sum *sum_func= ref->in_sum_func;
             sum_func && sum_func->aggr_level >= nest_level;
             sum_func= sum_func->in_sum_func)
        {
          if (sum_func->aggr_level == nest_level)
          {
            direct_ref= true;
            break;
          }
        }
      }
    }
    else
    {
      /*
        Check if GROUP BY item trees contain the outer ref:
        in this case we have to use Item_direct_ref instead of Item_ref.
      */
      for (ORDER *group= group_list.first; group; group= group->next)
      {
        if ((*group->item)->walk(&Item::find_item_processor, walk_subquery,
                                 (uchar *) ref))
        {
          direct_ref= true;
          break;
        }
      }
    }
    Item_ref *const new_ref= direct_ref ?
              new Item_direct_ref(ref->context, item_ref, ref->table_name,
                                  ref->field_name, ref->is_alias_of_expr()) :
              new Item_ref(ref->context, item_ref, ref->table_name,
                           ref->field_name, ref->is_alias_of_expr());
    if (!new_ref)
      return true;         /* purecov: inspected */
    ref->outer_ref= new_ref;
    ref->ref= &ref->outer_ref;

    if (!ref->fixed && ref->fix_fields(thd, 0))
      return true;         /* purecov: inspected */
    thd->lex->used_tables|= item->used_tables();
    select_list_tables|= item->used_tables();
  }
  return false;
}


/**
   Since LIMIT is not supported for table subquery predicates
   (IN/ALL/EXISTS/etc), the following clauses are redundant for
   subqueries:

   ORDER BY
   DISTINCT
   GROUP BY   if there are no aggregate functions and no HAVING clause

   This removal is permanent. Thus, it only makes sense to call this function
   for regular queries and on first execution of SP/PS

   @param thd               thread handler
   @param hidden_group_field_count Number of hidden group fields added
                            by setup_group().
*/


void SELECT_LEX::remove_redundant_subquery_clauses(THD *thd,
                                                   int hidden_group_field_count)
{
  Item_subselect *subq_predicate= master_unit()->item;
  /*
    The removal should happen for IN, ALL, ANY and EXISTS subqueries,
    which means all but single row subqueries. Example single row
    subqueries: 
       a) SELECT * FROM t1 WHERE t1.a = (<single row subquery>) 
       b) SELECT a, (<single row subquery) FROM t1
   */
  if (subq_predicate->substype() == Item_subselect::SINGLEROW_SUBS)
    return;

  // A subquery that is not single row should be one of IN/ALL/ANY/EXISTS.
  assert (subq_predicate->substype() == Item_subselect::EXISTS_SUBS ||
          subq_predicate->substype() == Item_subselect::IN_SUBS     ||
          subq_predicate->substype() == Item_subselect::ALL_SUBS    ||
          subq_predicate->substype() == Item_subselect::ANY_SUBS);

  enum change
  {
    REMOVE_NONE=0,
    REMOVE_ORDER= 1 << 0,
    REMOVE_DISTINCT= 1 << 1,
    REMOVE_GROUP= 1 << 2
  };

  uint changelog= 0;

  if (order_list.elements)
  {
    changelog|= REMOVE_ORDER;
    empty_order_list(this);
  }

  if (is_distinct())
  {
    changelog|= REMOVE_DISTINCT;
    remove_base_options(SELECT_DISTINCT);
  }

  // Remove GROUP BY if there are no aggregate functions and no HAVING clause

  if (group_list.elements && !agg_func_used() && !having_cond())
  {
    changelog|= REMOVE_GROUP;
    for (ORDER *g= group_list.first; g != NULL; g= g->next)
    {
      if (*g->item == g->item_ptr)
        (*g->item)->walk(&Item::clean_up_after_removal, walk_subquery,
                         reinterpret_cast<uchar*>(this));
    }
    group_list.empty();
    while (hidden_group_field_count-- > 0)
    {
      all_fields.pop();
      ref_ptrs[all_fields.elements]= NULL;
    }
  }

  if (changelog)
  {
    Opt_trace_context * trace= &thd->opt_trace;
    if (unlikely(trace->is_started()))
    {
      Opt_trace_object trace_wrapper(trace);
      Opt_trace_array trace_changes(trace, "transformations_to_subquery");
      if (changelog & REMOVE_ORDER)
        trace_changes.add_alnum("removed_ordering");
      if (changelog & REMOVE_DISTINCT)
        trace_changes.add_alnum("removed_distinct");
      if (changelog & REMOVE_GROUP)
        trace_changes.add_alnum("removed_grouping");
    }
  }
}


/**
  Empty the ORDER list.
  Delete corresponding elements from all_fields and ref_ptrs too.
  If ORDER list contain any subqueries, delete them from the query block list.

  @param sl  Query block that possible subquery blocks in the ORDER BY clause
             are attached to (may be different from "this" when query block has
             been merged into an outer query block).
*/

void SELECT_LEX::empty_order_list(SELECT_LEX *sl)
{
  for (ORDER *o= order_list.first; o != NULL; o= o->next)
  {
    /*
      Do not remove the order by expression if it has a view
      reference. There is possibility that this view reference could
      be used elsewhere in the query
    */
    if (*o->item == o->item_ptr) {
      (*o->item)->walk(&Item::clean_up_after_removal, walk_subquery,
                       pointer_cast<uchar *>(sl));
    }
  }
  order_list.empty();
  while (hidden_order_field_count-- > 0)
  {
    all_fields.pop();
    ref_ptrs[all_fields.elements]= NULL;
  }
}


/*****************************************************************************
  Group and order functions
*****************************************************************************/

/**
  Resolve an ORDER BY or GROUP BY column reference.

  Given a column reference (represented by 'order') from a GROUP BY or ORDER
  BY clause, find the actual column it represents. If the column being
  resolved is from the GROUP BY clause, the procedure searches the SELECT
  list 'fields' and the columns in the FROM list 'tables'. If 'order' is from
  the ORDER BY clause, only the SELECT list is being searched.

  If 'order' is resolved to an Item, then order->item is set to the found
  Item. If there is no item for the found column (that is, it was resolved
  into a table field), order->item is 'fixed' and is added to all_fields and
  ref_pointer_array.

  ref_pointer_array and all_fields are updated.

  @param[in] thd		     Pointer to current thread structure
  @param[in,out] ref_pointer_array  All select, group and order by fields
  @param[in] tables                 List of tables to search in (usually
    FROM clause)
  @param[in] order                  Column reference to be resolved
  @param[in] fields                 List of fields to search in (usually
    SELECT list)
  @param[in,out] all_fields         All select, group and order by fields
  @param[in] is_group_field         True if order is a GROUP field, false if
    ORDER by field

  @retval
    FALSE if OK
  @retval
    TRUE  if error occurred
*/

static bool
find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
                   TABLE_LIST *tables, ORDER *order,
                   List<Item> &fields, List<Item> &all_fields,
                   bool is_group_field)
{
  Item *order_item= *order->item; /* The item from the GROUP/ORDER caluse. */
  Item::Type order_item_type;
  Item **select_item; /* The corresponding item from the SELECT clause. */
  Field *from_field;  /* The corresponding field from the FROM clause. */
  uint counter;
  enum_resolution_type resolution;

  /*
    Local SP variables may be int but are expressions, not positions.
    (And they can't be used before fix_fields is called for them).
  */
  if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item())
  {						/* Order by position */
    uint count= (uint) order_item->val_int();
    if (!count || count > fields.elements)
    {
      my_error(ER_BAD_FIELD_ERROR, MYF(0),
               order_item->full_name(), thd->where);
      return TRUE;
    }
    order->item= &ref_pointer_array[count - 1];
    order->in_field_list= 1;
    order->is_position= true;
    return FALSE;
  }
  /* Lookup the current GROUP/ORDER field in the SELECT clause. */
  select_item= find_item_in_list(order_item, fields, &counter,
                                 REPORT_EXCEPT_NOT_FOUND, &resolution);
  if (!select_item)
    return TRUE; /* The item is not unique, or some other error occured. */


  /* Check whether the resolved field is not ambiguos. */
  if (select_item != not_found_item)
  {
    Item *view_ref= NULL;
    /*
      If we have found field not by its alias in select list but by its
      original field name, we should additionally check if we have conflict
      for this name (in case if we would perform lookup in all tables).
    */
    if (resolution == RESOLVED_BEHIND_ALIAS && !order_item->fixed &&
        order_item->fix_fields(thd, order->item))
      return TRUE;

    /* Lookup the current GROUP field in the FROM clause. */
    order_item_type= order_item->type();
    from_field= not_found_field;
    if ((is_group_field &&
        order_item_type == Item::FIELD_ITEM) ||
        order_item_type == Item::REF_ITEM)
    {
      from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables,
                                       NULL, &view_ref, IGNORE_ERRORS, TRUE,
                                       FALSE);
      if (thd->is_error())
        return true;

      if (!from_field)
        from_field= not_found_field;
    }

    if (from_field == not_found_field ||
        (from_field != view_ref_found ?
         /* it is field of base table => check that fields are same */
         ((*select_item)->type() == Item::FIELD_ITEM &&
          ((Item_field*) (*select_item))->field->eq(from_field)) :
         /*
           in is field of view table => check that references on translation
           table are same
         */
         ((*select_item)->type() == Item::REF_ITEM &&
          view_ref->type() == Item::REF_ITEM &&
          ((Item_ref *) (*select_item))->ref ==
          ((Item_ref *) view_ref)->ref)))
    {
      /*
        If there is no such field in the FROM clause, or it is the same field
        as the one found in the SELECT clause, then use the Item created for
        the SELECT field. As a result if there was a derived field that
        'shadowed' a table field with the same name, the table field will be
        chosen over the derived field.

        If we replace *order->item with one from the select list or
        from a table in the FROM list, we should clean up after
        removing the old *order->item from the query. The item has not
        been fixed (so there are no aggregation functions that need
        cleaning up), but it may contain subqueries that should be
        unlinked.
      */
      if (*order->item != *select_item)
        (*order->item)->walk(&Item::clean_up_after_removal, walk_subquery,
                             NULL);
      order->item= &ref_pointer_array[counter];
      order->in_field_list=1;
      if (resolution == RESOLVED_AGAINST_ALIAS)
        order->used_alias= true;
      return FALSE;
    }
    else
    {
      /*
        There is a field with the same name in the FROM clause. This
        is the field that will be chosen. In this case we issue a
        warning so the user knows that the field from the FROM clause
        overshadows the column reference from the SELECT list.
      */
      push_warning_printf(thd, Sql_condition::SL_WARNING, ER_NON_UNIQ_ERROR,
                          ER(ER_NON_UNIQ_ERROR),
                          ((Item_ident*) order_item)->field_name,
                          current_thd->where);
    }
  }

  order->in_field_list=0;
  /*
    The call to order_item->fix_fields() means that here we resolve
    'order_item' to a column from a table in the list 'tables', or to
    a column in some outer query. Exactly because of the second case
    we come to this point even if (select_item == not_found_item),
    inspite of that fix_fields() calls find_item_in_list() one more
    time.

    We check order_item->fixed because Item_func_group_concat can put
    arguments for which fix_fields already was called.
    
    group_fix_field= TRUE is to resolve aliases from the SELECT list
    without creating of Item_ref-s: JOIN::exec() wraps aliased items
    in SELECT list with Item_copy items. To re-evaluate such a tree
    that includes Item_copy items we have to refresh Item_copy caches,
    but:
      - filesort() never refresh Item_copy items,
      - end_send_group() checks every record for group boundary by the
        test_if_group_changed function that obtain data from these
        Item_copy items, but the copy_fields function that
        refreshes Item copy items is called after group boundaries only -
        that is a vicious circle.
    So we prevent inclusion of Item_copy items.
  */
  bool save_group_fix_field= thd->lex->current_select()->group_fix_field;
  if (is_group_field)
    thd->lex->current_select()->group_fix_field= TRUE;
  bool ret= (!order_item->fixed &&
      (order_item->fix_fields(thd, order->item) ||
       (order_item= *order->item)->check_cols(1)));
  thd->lex->current_select()->group_fix_field= save_group_fix_field;
  if (ret)
    return TRUE; /* Wrong field. */

  uint el= all_fields.elements;
  all_fields.push_front(order_item); /* Add new field to field list. */
  ref_pointer_array[el]= order_item;
  /*
    If the order_item is a SUM_FUNC_ITEM, when fix_fields is called
    ref_by is set to order->item which is the address of order_item.
    But this needs to be address of order_item in the all_fields list.
    As a result, when it gets replaced with Item_aggregate_ref
    object in Item::split_sum_func2, we will be able to retrieve the
    newly created object.
  */
  if (order_item->type() == Item::SUM_FUNC_ITEM)
    ((Item_sum *)order_item)->ref_by= all_fields.head_ref();

  /*
    Currently, we assume that this assertion holds. If it turns out
    that it fails for some query, order->item has changed and the old
    item is removed from the query. In that case, we must call walk()
    with clean_up_after_removal() on the old order->item.
  */
  assert(order_item == *order->item);
  order->item= &ref_pointer_array[el];
  return FALSE;
}


/**
  Resolve and setup list of expressions in ORDER BY clause.

  Change order to point at item in select list.
  If item isn't a number and doesn't exists in the select list, add it to the
  the field list.

  @param thd  Thread handler

  @returns false if success, true if error
*/

bool setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
                 List<Item> &fields, List<Item> &all_fields, ORDER *order)
{
  assert(order);

  SELECT_LEX *const select= thd->lex->current_select();

  thd->where="order clause";

  const bool for_union= select->master_unit()->is_union() &&
                        select == select->master_unit()->fake_select_lex;
  const bool is_aggregated= select->is_grouped();

  for (uint number= 1; order; order=order->next, number++)
  {
    if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
			   all_fields, false))
      return true;
    if ((*order->item)->with_sum_func)
    {
      /*
        Aggregated expressions in ORDER BY are not supported by SQL standard,
        but MySQL has some limited support for them. The limitations are
        checked below:

        1. A UNION query is not aggregated, so ordering by a set function
           is always wrong.
      */
      if (for_union)
      {
        my_error(ER_AGGREGATE_ORDER_FOR_UNION, MYF(0), number);
        return true;
      }

      /*
        2. A non-aggregated query combined with a set function in ORDER BY
           that does not contain an outer reference is illegal, because it
           would cause the query to become aggregated.
           (Since is_aggregated is false, this expression would cause
            agg_func_used() to become true).
      */
      if (!is_aggregated && select->agg_func_used())
      {
        my_error(ER_AGGREGATE_ORDER_NON_AGG_QUERY, MYF(0), number);
        return true;
      }
    }
  }
  return false;
}


/**
   Runs checks mandated by ONLY_FULL_GROUP_BY

   @param  thd                     THD pointer

   @returns true if ONLY_FULL_GROUP_BY is violated.
*/

bool SELECT_LEX::check_only_full_group_by(THD *thd)
{
  bool rc= false;

  if (is_grouped())
  {
    MEM_ROOT root;
    /*
      "root" has very short lifetime, and should not consume much
      => not instrumented.
    */
    init_sql_alloc(PSI_NOT_INSTRUMENTED, &root, MEM_ROOT_BLOCK_SIZE, 0);
    {
      Group_check gc(this, &root);
      rc= gc.check_query(thd);
      gc.to_opt_trace(thd);
    } // scope, to let any destructor run before free_root().
    free_root(&root, MYF(0));
  }

  if (!rc && is_distinct())
  {
    Distinct_check dc(this);
    rc= dc.check_query(thd);
  }

  return rc;
}


/**
  Do final setup of ORDER BY clause, after the query block is fully resolved.

  Check that ORDER BY clause is not redundant.
  Split any aggregate functions.

  @param thd                      Thread handler

  @returns false if success, true if error
*/
bool SELECT_LEX::setup_order_final(THD *thd)
{
  if (is_implicitly_grouped())
  {
    // Result will contain zero or one row - ordering is redundant
    empty_order_list(this);
    return false;
  }

  if ((master_unit()->is_union() || master_unit()->fake_select_lex) &&
      this != master_unit()->fake_select_lex &&
      !(braces && explicit_limit))
  {
    // Part of UNION which requires global ordering may skip local order
    empty_order_list(this);
    return false;
  }

  for (ORDER *ord= order_list.first; ord; ord= ord->next)
  {
    Item *const item= *ord->item;

    if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
    {
      item->split_sum_func(thd, ref_ptrs, all_fields);
      if (thd->is_error())
        return true;       /* purecov: inspected */
    }
  }
  return false;
}


/**
  Resolve and set up the GROUP BY list.

  @param thd			Thread handler

  @todo
    change ER_WRONG_FIELD_WITH_GROUP to more detailed
    ER_NON_GROUPING_FIELD_USED

  @returns false if success, true if error
*/

bool SELECT_LEX::setup_group(THD *thd)
{
  assert(group_list.elements);

  thd->where="group statement";
  for (ORDER *group= group_list.first; group; group= group->next)
  {
    if (find_order_in_list(thd, ref_ptrs, get_table_list(), group, fields_list,
			   all_fields, true))
      return true;
    if ((*group->item)->with_sum_func)
    {
      my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*group->item)->full_name());
      return true;
    }
  }
  return false;
}


/****************************************************************************
  ROLLUP handling
****************************************************************************/

/**
  Replace occurrences of group by fields in an expression by ref items.

  The function replaces occurrences of group by fields in expr
  by ref objects for these fields unless they are under aggregate
  functions.
  The function also corrects value of the the maybe_null attribute
  for the items of all subexpressions containing group by fields.

  @b EXAMPLES
    @code
      SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP
      SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP 
  @endcode

  @b IMPLEMENTATION

    The function recursively traverses the tree of the expr expression,
    looks for occurrences of the group by fields that are not under
    aggregate functions and replaces them for the corresponding ref items.

  @note
    This substitution is needed GROUP BY queries with ROLLUP if
    SELECT list contains expressions over group by attributes.

  @param thd                  reference to the context
  @param expr                 expression to make replacement
  @param changed[out]  returns true if item contains a replaced field item

  @todo
    - TODO: Some functions are not null-preserving. For those functions
    updating of the maybe_null attribute is an overkill. 

  @returns false if success, true if error

*/

bool SELECT_LEX::change_group_ref(THD *thd, Item_func *expr, bool *changed)
{
  bool arg_changed= false;
  for (uint i= 0; i < expr->arg_count; i++)
  {
    Item **arg= expr->arguments() + i;
    Item *const item= *arg;
    if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM)
    {
      for (ORDER *group= group_list.first; group; group= group->next)
      {
        if (item->eq(*group->item, 0))
        {
          Item *new_item;
          if (!(new_item= new Item_ref(&context, group->item, 0,
                                       item->item_name.ptr())))
            return true;              /* purecov: inspected */

          expr->replace_argument(thd, arg, new_item);
          arg_changed= true;
        }
      }
    }
    else if (item->type() == Item::FUNC_ITEM)
    {
      if (change_group_ref(thd, (Item_func *) item, &arg_changed))
        return true;
    }
  }
  if (arg_changed)
  {
    expr->maybe_null= true;
    *changed= true;
  }
  return false;
}


/**
  Resolve items for rollup processing

  @param   thd   Thread handler

  @returns false if success, true if error
*/

bool SELECT_LEX::resolve_rollup(THD *thd)
{
  List_iterator<Item> it(all_fields);
  Item *item;
  while ((item= it++))
  {
    bool found_in_group= false;

    for (ORDER *group= group_list.first; group; group= group->next)
    {
      if (*group->item == item)
      {
        item->maybe_null= true;
        found_in_group= true;
        break;
      }
    }
    if (item->type() == Item::FUNC_ITEM && !found_in_group)
    {
      bool changed= false;
      if (change_group_ref(thd, (Item_func *) item, &changed))
        return true;       /* purecov: inspected */
      /*
        We have to prevent creation of a field in a temporary table for
        an expression that contains GROUP BY attributes.
        Marking the expression item as 'with_sum_func' will ensure this.
      */ 
      if (changed)
        item->with_sum_func= true;
    }
  }
  return false;
}

/**
  @brief  validate_gc_assignment
  Check whether the other values except DEFAULT are assigned
  for generated columns.

  @param thd                        thread handler
  @param fields                     Item_fields list to be filled
  @param values                     values to fill with
  @param table                      table to be checked
  @return Operation status
    @retval false   OK
    @retval true    Error occured

  @Note: This function must be called after table->write_set has been
         filled.
*/
bool
validate_gc_assignment(THD * thd, List<Item> *fields,
                       List<Item> *values, TABLE *table)
{
  Field **fld= NULL;
  MY_BITMAP *bitmap= table->write_set;
  bool use_table_field= false;
  DBUG_ENTER("validate_gc_assignment");

  if (!values || (values->elements == 0))
      DBUG_RETURN(false);

  // If fields has no elements, we use all table fields
  if (fields->elements == 0)
  {
    use_table_field= true;
    fld= table->field;
  }
  List_iterator_fast<Item> f(*fields),v(*values);
  Item *value;
  while ((value= v++))
  {
    Field *rfield;

    if (!use_table_field)
      rfield= (down_cast<Item_field*>((f++)->real_item()))->field;
    else
      rfield= *(fld++);
    if (rfield->table != table)
      continue;
    /* skip non marked fields */
    if (!bitmap_is_set(bitmap, rfield->field_index))
      continue;
    if (rfield->gcol_info && 
        value->type() != Item::DEFAULT_VALUE_ITEM)
    {
      my_error(ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN, MYF(0),
               rfield->field_name, rfield->table->s->table_name.str);
      DBUG_RETURN(true);
    }
  }
  DBUG_RETURN(false);
}


/**
  Delete unused columns from merged tables.

  This function is called recursively for each join nest and/or table
  in the query block. For each merged table that it finds, each column
  that contains a subquery and is not marked as used is removed and
  the translation item is set to NULL.

  @param tables List of tables and join nests
*/

void SELECT_LEX::delete_unused_merged_columns(List<TABLE_LIST> *tables)
{
  DBUG_ENTER("delete_unused_merged_columns");

  TABLE_LIST *tl;
  List_iterator<TABLE_LIST> li(*tables);
  while ((tl= li++))
  {
    if (tl->nested_join == NULL)
      continue;
    if (tl->is_merged())
    {
      for (Field_translator *transl= tl->field_translation;
           transl < tl->field_translation_end;
           transl++)
      {
        Item *const item= transl->item;

        assert(item->fixed);
        if (!item->has_subquery())
          continue;

        /*
          All used columns selected from derived tables are already marked
          as such. But unmarked columns may still refer to other columns
          from underlying derived tables, and in that case we cannot
          delete these columns as they share the same items.
          Thus, dive into the expression and mark such columns as "used".
          (This is a bit incorrect, as only a part of its underlying expression
          is "used", but that has no practical meaning.)
        */
        if (!item->is_derived_used() &&
            item->walk(&Item::propagate_derived_used, Item::WALK_POSTFIX, NULL))
          item->walk(&Item::propagate_set_derived_used,
                     Item::WALK_SUBQUERY_POSTFIX, NULL);

        if (!item->is_derived_used())
        {
          item->walk(&Item::clean_up_after_removal, walk_subquery,
                     pointer_cast<uchar *>(this));
          transl->item= NULL;
        }
      }
    }
    delete_unused_merged_columns(&tl->nested_join->join_list);
  }

  DBUG_VOID_RETURN;
}


/**
  Add item to the hidden part of select list.

  @param item  item to add

  @return Pointer to ref_ptr for the added item
*/

Item **SELECT_LEX::add_hidden_item(Item *item)
{
  uint el= all_fields.elements;
  ref_ptrs[el]= item;
  all_fields.push_front(item);
  return &ref_ptrs[el];
}

/**
  @} (end of group Query_Resolver)
*/

Youez - 2016 - github.com/yon3zu
LinuXploit