← Back to team overview

maria-developers team mailing list archive

Re: Review of MDEV-7112 Split HA_CREATE_INFO

 

Hi Sergei,

Thanks for review. I addressed most of your suggestions.
A fixed version is attached.

See details inline:


On 12/03/2014 01:13 AM, Sergei Golubchik wrote:
Hi.

It think the split is good, I liked it.

I didn't like that you've tried to put the refactoring of sql_db.cc and
sql_lang.h in the same commit, please move it to a separate patch.
MDEV-5359 should not depend on that.

When I had to change the interface for mysql_create_db(),
mysql_rm_db(), mysql_alter_db(), I thought why not to do it in the
right way at once... And it was very easy to do in case of the db
routines.

Anyway, I agree to make a separate task for this,
It's easier to review this way :)


Anyway, see all my comments below:

diff --git a/sql/structs.h b/sql/structs.h
index 99561c5..b38685c 100644
--- a/sql/structs.h
+++ b/sql/structs.h
<skip>
+  DDL_options_st operator|=(DDL_options_st::Options other)
+  {
+    add(other);
+    return *this;
+  }
+};

I don't particularly like this style of C++ing...
It's way too verbose.
but ok


This is to make the code on sql_yacc.yy shorter:


  lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4)


I find "$1 | $4" very clearly readable, and short.



+
+
  #endif /* STRUCTS_INCLUDED */
diff --git a/sql/handler.h b/sql/handler.h
index 0044556..7b6a5f4 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -376,10 +376,7 @@ enum enum_alter_inplace_result {
  #define HA_KEY_BLOB_LENGTH	2

  #define HA_LEX_CREATE_TMP_TABLE	1
-#define HA_LEX_CREATE_IF_NOT_EXISTS 2
-#define HA_LEX_CREATE_TABLE_LIKE 4
  #define HA_CREATE_TMP_ALTER     8
-#define HA_LEX_CREATE_REPLACE   16

One empty line here, please, HA_MAX_REC_LENGTH is not a flag

Done.


  #define HA_MAX_REC_LENGTH	65535

  /* Table caching type */
@@ -1571,9 +1568,9 @@ enum enum_stats_auto_recalc { HA_STATS_AUTO_RECALC_DEFAULT= 0,
                                HA_STATS_AUTO_RECALC_ON,
                                HA_STATS_AUTO_RECALC_OFF };


Could you add structure comments here? Like what you have in MDEV,
"This will be passed to mysql_create_db, mysql_drop_db,
mysqld_show_create_db", etc

To explain what every structure is for, what kind of data it should store,
and expected users (internal DB DDL, internal table DDL, handler, etc)

Done.

<skip>

diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 0bbcca5..0edda65 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1923,7 +1923,9 @@ bool MDL_deadlock_handler::handle_condition(THD *,
  */

  static bool
-open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
+open_table_get_mdl_lock(THD *thd,
+                        const DDL_options_st &options,
+                        Open_table_context *ot_ctx,

What's the point - you don't seem to be using options in this function?

And that recursively means that you don't need 'options' in all other
functions that only pass 'options' argument down to open_table_get_mdl_lock()
but otherwise don't use it.

Thanks for noticing this.

I fixed this function and the callers that do not use options otherwise.


                          MDL_request *mdl_request,
                          uint flags,
                          MDL_ticket **mdl_ticket)
@@ -4176,8 +4182,8 @@ thr_lock_type read_lock_type_for_table(THD *thd,
      DBUG_RETURN(FALSE);

    /* Check if CREATE TABLE without REPLACE was used */
-  create_table= (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
-                 !(thd->lex->create_info.options & HA_LEX_CREATE_REPLACE));
+  create_table= thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
+                !options.or_replace();

why, options are still in thd->lex, aren't they?

Not really always.

sql_parse.cc does the following:


    Table_specification_st create_info(lex->create_info);
    ...
    if (thd->slave_thread &&
        slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT &&
        !lex->create_info.if_not_exists())
    {
      create_info.add(DDL_options_st::OPT_OR_REPLACE);
      create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);
    }

So the "options" parameter can have extra flags comparing to thd->lex->create_info.


Btw, it would be nice to make somehow thd->lex->create_info inaccessible
inside lock_table_names() and some other routines, to avoid this
ambiguity. But I have no idea how to do so in a small change.


<skip>



diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 0541cbc..2536255 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1696,14 +1695,14 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,

    packet->append(STRING_WITH_LEN("CREATE "));
    if (create_info_arg &&
-      (create_info_arg->org_options & HA_LEX_CREATE_REPLACE ||
+      ((create_info_arg->or_replace() &&
+        !create_info_arg->or_replace_slave_generated()) ||

that's a bit strange. Could you explain this?
why org_options & HA_LEX_CREATE_REPLACE is translated to
or_replace() && !or_replace_slave_generated()

Notice, I removed "org_options".

Now everything is passed through a single set of flags:
the DDL_options_st part of *create_info_arg.

And the related flag is set in sql_parse.cc, here:

  create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);

I find this logic to be much easier to understand.


         create_info_arg->table_was_deleted))
      packet->append(STRING_WITH_LEN("OR REPLACE "));
    if (share->tmp_table)
      packet->append(STRING_WITH_LEN("TEMPORARY "));
    packet->append(STRING_WITH_LEN("TABLE "));
-  if (create_info_arg &&
-      (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
+  if (create_info_arg && create_info_arg->if_not_exists())
      packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
    if (table_list->schema_table)
      alias= table_list->schema_table->table_name;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index b991215..7bb293b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4628,7 +4628,8 @@ int create_table_impl(THD *thd,
                         const char *orig_db, const char *orig_table_name,
                         const char *db, const char *table_name,
                         const char *path,
-                       HA_CREATE_INFO *create_info,
+                       const DDL_options_st options,
+                       HA_CREATE_INFO &create_info,

why? I generally prefer pointers over C++ references -
one can immediately see what variables can be modified by the function.
is there a compelling reason to use references here?

Well, I had a hope I'd manage to do it a const:

  const HA_CREATE_INFO &create_info

And in case of "const", I really prefer "const XXX &name",
instead of "const XXX *name". It gives a lot of advantages.


But could not make it a const without more changes
with splitting of the structures into parts.

Reverted back to "HA_CREATE_INFO *create_info".



                         Alter_info *alter_info,
                         int create_table_mode,
                         bool *is_trans,
@@ -5273,9 +5275,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
    */

    /* Copy temporarily the statement flags to thd for lock_table_names() */
+  // QQ: is this really needed???

may be not anymore, as you pass flags separately

I'm not 100% sure. I only pass DDL_options_st separately.
But the handler flags are still in thd->lex->create_info.options.
And I don't know if the callers do not change them..,


    uint save_thd_create_info_options= thd->lex->create_info.options;
-  thd->lex->create_info.options|= create_info->options;
-  res= open_tables(thd, &thd->lex->query_tables, &not_used, 0);
+  thd->lex->create_info.options|= create_info.options;
+  res= open_tables(thd, create_info, &thd->lex->query_tables, &not_used, 0);
    thd->lex->create_info.options= save_thd_create_info_options;

    if (res)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 632bdd2..0f2c0e0 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1621,7 +1623,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
          IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
          NCHAR_STRING opt_component key_cache_name
          sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
-        opt_constraint constraint opt_ident opt_if_not_exists_ident
+        opt_constraint constraint opt_ident
+        opt_if_not_exists_opt_table_element_name

can you please try to come up with shorter identifier names?
40 characters - that's a bit too long :)

I renamed it because it did not reflect what it was used for:

1. I read "opt_if_not_exists_ident" as "IF NOT EXISTS ident, or empty".
But in fact it's more complex.

2. It's used only in key name or constraint name context.
So "ident" was also confusing (too general).


I thought my name was very self explanatory. Can we keep it?

Or, suggest a shorter one :)



  %type <lex_str_ptr>
          opt_table_alias
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index f3b1167..6b1942e 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -11349,7 +11349,7 @@ static __attribute__((nonnull, warn_unused_result))

  	/* Do not use DATA DIRECTORY with TEMPORARY TABLE. */
  	if (create_info->data_file_name
-	    && create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+	    && create_info->tmp_table()) {

nope, you should not change storage engine API here.
tmp_table() was a convenience wrapper, old way should still work


I haven't changed the API at this point, so the old way still works.
But I don't want any newly created engines to copy the old way.


There is a chance that we'll move the table scope part into a separate
structure, and Table_scope_and_contents_source_st will then inherit it.
Now table scope is only responsible for TEMPORARY or not TEMPORARY,
but in the SQL standard it's something more complex:
http://savage.net.au/SQL/sql-2003-2.bnf.html#table%20scope

So if we ever decide to support more table scope options,
the HA_LEX_CREATE_TMP_TABLE flag most likely won't be stored in
create_info->options any more.

In any cases, encapsulation is generally better in many aspects than
direct field access.

tmp_table() was not just a convenience wrapper,
it is indeed a step towards the right direction :)
And I'd like to propagate it, to close direct access eventually.



  		push_warning(
  			thd, Sql_condition::WARN_LEVEL_WARN,
  			ER_ILLEGAL_HA_CREATE_OPTION,

Regards,
Sergei

diff --git a/sql/handler.h b/sql/handler.h
index 0044556..002a22e 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -376,10 +376,8 @@ enum enum_alter_inplace_result {
 #define HA_KEY_BLOB_LENGTH	2
 
 #define HA_LEX_CREATE_TMP_TABLE	1
-#define HA_LEX_CREATE_IF_NOT_EXISTS 2
-#define HA_LEX_CREATE_TABLE_LIKE 4
 #define HA_CREATE_TMP_ALTER     8
-#define HA_LEX_CREATE_REPLACE   16
+
 #define HA_MAX_REC_LENGTH	65535
 
 /* Table caching type */
@@ -1571,9 +1569,41 @@ enum enum_stats_auto_recalc { HA_STATS_AUTO_RECALC_DEFAULT= 0,
                               HA_STATS_AUTO_RECALC_ON,
                               HA_STATS_AUTO_RECALC_OFF };
 
-struct HA_CREATE_INFO
+/**
+  A helper struct for schema DDL statements:
+    CREATE SCHEMA [IF NOT EXISTS] name [ schema_specification... ]
+    ALTER SCHEMA name [ schema_specification... ]
+
+  It stores the "schema_specification" part of the CREATE/ALTER statements and
+  is passed to mysql_create_db() and  mysql_alter_db().
+  Currently consists only of the schema default character set and collation.
+*/
+struct Schema_specification_st
+{
+  CHARSET_INFO *default_table_charset;
+  void init()
+  {
+    bzero(this, sizeof(*this));
+  }
+};
+
+
+/**
+  A helper struct for table DDL statements, e.g.:
+  CREATE [OR REPLACE] [TEMPORARY]
+    TABLE [IF NOT EXISTS] tbl_name table_contents_source;
+
+  Represents a combinations of:
+  1. The scope, i.e. TEMPORARY or not TEMPORARY
+  2. The "table_contents_source" part of the table DDL statements,
+     which can be initialized from either of these:
+     - table_element_list ...      // Explicit definition (column and key list)
+     - LIKE another_table_name ... // Copy structure from another table
+     - [AS] SELECT ...             // Copy structure from a subquery
+*/
+struct Table_scope_and_contents_source_st
 {
-  CHARSET_INFO *table_charset, *default_table_charset;
+  CHARSET_INFO *table_charset;
   LEX_CUSTRING tabledef_version;
   LEX_STRING connect_string;
   const char *password, *tablespace;
@@ -1593,7 +1623,6 @@ struct HA_CREATE_INFO
   uint stats_sample_pages;
   uint null_bits;                       /* NULL bits at start of record */
   uint options;				/* OR of HA_CREATE_ options */
-  uint org_options;                     /* original options from query */
   uint merge_insert_method;
   uint extra_size;                      /* length of extra data segment */
   SQL_I_List<TABLE_LIST> merge_list;
@@ -1626,7 +1655,11 @@ struct HA_CREATE_INFO
   MDL_ticket *mdl_ticket;
   bool table_was_deleted;
 
-  bool tmp_table() { return options & HA_LEX_CREATE_TMP_TABLE; }
+  void init()
+  {
+    bzero(this, sizeof(*this));
+  }
+  bool tmp_table() const { return options & HA_LEX_CREATE_TMP_TABLE; }
   void use_default_db_type(THD *thd)
   {
     db_type= tmp_table() ? ha_default_tmp_handlerton(thd)
@@ -1636,6 +1669,54 @@ struct HA_CREATE_INFO
 
 
 /**
+  This struct is passed to handler table routines, e.g. ha_create().
+  It does not include the "OR REPLACE" and "IF NOT EXISTS" parts, as these
+  parts are handled on the SQL level and are not needed on the handler level.
+*/
+struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
+                       public Schema_specification_st
+{
+  void init()
+  {
+    Table_scope_and_contents_source_st::init();
+    Schema_specification_st::init();
+  }
+};
+
+
+/**
+  This struct is passed to mysql_create_table() and similar creation functions,
+  as well as to show_create_table().
+*/
+struct Table_specification_st: public HA_CREATE_INFO,
+                               public DDL_options_st
+{
+  // Deep initialization
+  void init()
+  {
+    HA_CREATE_INFO::init();
+    DDL_options_st::init();
+  }
+  void init(DDL_options_st::Options options)
+  {
+    HA_CREATE_INFO::init();
+    DDL_options_st::init(options);
+  }
+  /*
+    Quick initialization, for parser.
+    Most of the HA_CREATE_INFO is left uninitialized.
+    It gets fully initialized in sql_yacc.yy, only when the parser
+    scans a related keyword (e.g. CREATE, ALTER).
+  */
+  void lex_start()
+  {
+    HA_CREATE_INFO::options= 0;
+    DDL_options_st::init();
+  }
+};
+
+
+/**
   In-place alter handler context.
 
   This is a superclass intended to be subclassed by individual handlers
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 7617077..57623a7 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -3204,13 +3204,13 @@ bool Query_log_event::write(IO_CACHE* file)
   switch (lex->sql_command)
   {
     case SQLCOM_DROP_TABLE:
-      use_cache= (lex->drop_temporary && thd->in_multi_stmt_transaction_mode());
+      use_cache= (lex->tmp_table() && thd->in_multi_stmt_transaction_mode());
     break;
 
     case SQLCOM_CREATE_TABLE:
       trx_cache= (lex->select_lex.item_list.elements &&
                   thd->is_current_stmt_binlog_format_row());
-      use_cache= (lex->create_info.tmp_table() &&
+      use_cache= (lex->tmp_table() &&
                    thd->in_multi_stmt_transaction_mode()) || trx_cache;
       break;
     case SQLCOM_SET_OPTION:
@@ -4348,7 +4348,8 @@ Query partially completed on the master (error on master: %d) \
       has already been dropped. To ignore such irrelevant "table does
       not exist errors", we silently clear the error if TEMPORARY was used.
     */
-    if (thd->lex->sql_command == SQLCOM_DROP_TABLE && thd->lex->drop_temporary &&
+    if (thd->lex->sql_command == SQLCOM_DROP_TABLE &&
+        thd->lex->tmp_table() &&
         thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_BAD_TABLE_ERROR &&
         !expected_error)
       thd->get_stmt_da()->reset_diagnostics_area();
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 0ef336a..f44421f 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -281,13 +281,13 @@ bool Item_splocal::append_for_log(THD *thd, String *str)
     flags= sp_head::CONTAINS_DYNAMIC_SQL;
     break;
   case SQLCOM_CREATE_TABLE:
-    if (lex->create_info.tmp_table())
+    if (lex->tmp_table())
       flags= 0;
     else
       flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
     break;
   case SQLCOM_DROP_TABLE:
-    if (lex->drop_temporary)
+    if (lex->tmp_table())
       flags= 0;
     else
       flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
@@ -4017,7 +4017,7 @@ uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first)
   SP_TABLE *tab;
 
   if (lex_for_tmp_check->sql_command == SQLCOM_DROP_TABLE &&
-      lex_for_tmp_check->drop_temporary)
+      lex_for_tmp_check->tmp_table())
     return TRUE;
 
   for (uint i= 0 ; i < m_sptabs.records ; i++)
@@ -4082,7 +4082,7 @@ uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first)
           return FALSE;
         if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
             lex_for_tmp_check->query_tables == table &&
-            lex_for_tmp_check->create_info.tmp_table())
+            lex_for_tmp_check->tmp_table())
         {
           tab->temp= TRUE;
           tab->qname.length= temp_table_key_length;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 0bbcca5..7d1f9dc 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3453,7 +3453,8 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
       break;
     case OT_DISCOVER:
       {
-        if ((result= lock_table_names(m_thd, m_failed_table, NULL,
+        if ((result= lock_table_names(m_thd, m_thd->lex->create_info,
+                                      m_failed_table, NULL,
                                       get_timeout(), 0)))
           break;
 
@@ -3484,7 +3485,8 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
       }
     case OT_REPAIR:
       {
-        if ((result= lock_table_names(m_thd, m_failed_table, NULL,
+        if ((result= lock_table_names(m_thd, m_thd->lex->create_info,
+                                      m_failed_table, NULL,
                                       get_timeout(), 0)))
           break;
 
@@ -4132,7 +4134,7 @@ thr_lock_type read_lock_type_for_table(THD *thd,
 */
 
 bool
-lock_table_names(THD *thd,
+lock_table_names(THD *thd, const DDL_options_st &options,
                  TABLE_LIST *tables_start, TABLE_LIST *tables_end,
                  ulong lock_wait_timeout, uint flags)
 {
@@ -4176,8 +4178,8 @@ thr_lock_type read_lock_type_for_table(THD *thd,
     DBUG_RETURN(FALSE);
 
   /* Check if CREATE TABLE without REPLACE was used */
-  create_table= (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
-                 !(thd->lex->create_info.options & HA_LEX_CREATE_REPLACE));
+  create_table= thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
+                !options.or_replace();
 
   if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
   {
@@ -4231,7 +4233,7 @@ thr_lock_type read_lock_type_for_table(THD *thd,
     */
     if (ha_table_exists(thd, tables_start->db, tables_start->table_name))
     {
-      if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
+      if (options.if_not_exists())
       {
         push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                             ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
@@ -4344,8 +4346,9 @@ thr_lock_type read_lock_type_for_table(THD *thd,
   @retval  TRUE   Error, reported.
 */
 
-bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
-                Prelocking_strategy *prelocking_strategy)
+bool open_tables(THD *thd, const DDL_options_st &options,
+                 TABLE_LIST **start, uint *counter, uint flags,
+                 Prelocking_strategy *prelocking_strategy)
 {
   /*
     We use pointers to "next_global" member in the last processed
@@ -4434,7 +4437,8 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
     else
     {
       TABLE_LIST *table;
-      if (lock_table_names(thd, *start, thd->lex->first_not_own_table(),
+      if (lock_table_names(thd, options, *start,
+                           thd->lex->first_not_own_table(),
                            ot_ctx.get_timeout(), flags))
       {
         error= TRUE;
@@ -4971,8 +4975,7 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
   table_l->required_type= FRMTYPE_TABLE;
 
   /* Open the table. */
-  if (open_and_lock_tables(thd, table_l, FALSE, flags,
-                           prelocking_strategy))
+  if (open_and_lock_tables(thd, table_l, FALSE, flags, prelocking_strategy))
     table_l->table= NULL; /* Just to be sure. */
 
   /* Restore list. */
@@ -5117,7 +5120,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
   @retval TRUE   Error
 */
 
-bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+bool open_and_lock_tables(THD *thd, const DDL_options_st &options,
+                          TABLE_LIST *tables,
                           bool derived, uint flags,
                           Prelocking_strategy *prelocking_strategy)
 {
@@ -5126,7 +5130,8 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
   DBUG_ENTER("open_and_lock_tables");
   DBUG_PRINT("enter", ("derived handling: %d", derived));
 
-  if (open_tables(thd, &tables, &counter, flags, prelocking_strategy))
+  if (open_tables(thd, options,
+                  &tables, &counter, flags, prelocking_strategy))
     goto err;
 
   DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
@@ -9314,8 +9319,8 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
   thd->reset_n_backup_open_tables_state(backup);
 
   if (open_and_lock_tables(thd, table_list, FALSE,
-                           MYSQL_OPEN_IGNORE_FLUSH |
-                           MYSQL_LOCK_IGNORE_TIMEOUT))
+                            MYSQL_OPEN_IGNORE_FLUSH |
+                            MYSQL_LOCK_IGNORE_TIMEOUT))
   {
     lex->restore_backup_query_tables_list(&query_tables_list_backup);
     thd->restore_backup_open_tables_state(backup);
diff --git a/sql/sql_base.h b/sql/sql_base.h
index e39ec16..4b680a2 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -119,7 +119,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
 
 bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
                 Open_table_context *ot_ctx);
-
 bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
                   uint db_stat, uint prgflag,
                   uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
@@ -226,15 +225,41 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
 void wrap_ident(THD *thd, Item **conds);
 int setup_ftfuncs(SELECT_LEX* select);
 int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
-bool lock_table_names(THD *thd, TABLE_LIST *table_list,
+bool lock_table_names(THD *thd, const DDL_options_st &options,
+                      TABLE_LIST *table_list,
                       TABLE_LIST *table_list_end, ulong lock_wait_timeout,
                       uint flags);
-bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags,
+static inline bool
+lock_table_names(THD *thd, TABLE_LIST *table_list,
+                 TABLE_LIST *table_list_end, ulong lock_wait_timeout,
+                 uint flags)
+{
+  return lock_table_names(thd, thd->lex->create_info, table_list,
+                          table_list_end, lock_wait_timeout, flags);
+}
+bool open_tables(THD *thd, const DDL_options_st &options,
+                 TABLE_LIST **tables, uint *counter, uint flags,
                  Prelocking_strategy *prelocking_strategy);
+static inline bool
+open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags,
+            Prelocking_strategy *prelocking_strategy)
+{
+  return open_tables(thd, thd->lex->create_info, tables, counter, flags,
+                     prelocking_strategy);
+}
 /* open_and_lock_tables with optional derived handling */
-bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+bool open_and_lock_tables(THD *thd, const DDL_options_st &options,
+                          TABLE_LIST *tables,
                           bool derived, uint flags,
                           Prelocking_strategy *prelocking_strategy);
+static inline bool
+open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+                     bool derived, uint flags,
+                     Prelocking_strategy *prelocking_strategy)
+{
+  return open_and_lock_tables(thd, thd->lex->create_info,
+                              tables, derived, flags, prelocking_strategy);
+}
 /* simple open_and_lock_tables without derived handling for single table */
 TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
                                 thr_lock_type lock_type, uint flags,
@@ -460,13 +485,24 @@ class Alter_table_prelocking_strategy : public Prelocking_strategy
 
 
 inline bool
+open_tables(THD *thd, const DDL_options_st &options,
+            TABLE_LIST **tables, uint *counter, uint flags)
+{
+  DML_prelocking_strategy prelocking_strategy;
+
+  return open_tables(thd, options, tables, counter, flags,
+                     &prelocking_strategy);
+}
+inline bool
 open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags)
 {
   DML_prelocking_strategy prelocking_strategy;
 
-  return open_tables(thd, tables, counter, flags, &prelocking_strategy);
+  return open_tables(thd, thd->lex->create_info, tables, counter, flags,
+                     &prelocking_strategy);
 }
 
+
 inline TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
                                        thr_lock_type lock_type, uint flags)
 {
@@ -478,12 +514,23 @@ inline TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
 
 
 /* open_and_lock_tables with derived handling */
-inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+inline bool open_and_lock_tables(THD *thd,
+                                 const DDL_options_st &options,
+                                 TABLE_LIST *tables,
                                  bool derived, uint flags)
 {
   DML_prelocking_strategy prelocking_strategy;
 
-  return open_and_lock_tables(thd, tables, derived, flags,
+  return open_and_lock_tables(thd, options, tables, derived, flags,
+                              &prelocking_strategy);
+}
+inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+                                  bool derived, uint flags)
+{
+  DML_prelocking_strategy prelocking_strategy;
+
+  return open_and_lock_tables(thd, thd->lex->create_info,
+                              tables, derived, flags,
                               &prelocking_strategy);
 }
 
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a9eec4f..ad4b778 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5460,8 +5460,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
       flags_access_some_set |= flags;
 
       if (lex->sql_command != SQLCOM_CREATE_TABLE ||
-          (lex->sql_command == SQLCOM_CREATE_TABLE &&
-          lex->create_info.tmp_table()))
+          (lex->sql_command == SQLCOM_CREATE_TABLE && lex->tmp_table()))
       {
         my_bool trans= table->table->file->has_transactions();
 
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 51fd1cb..8e20980 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4208,7 +4208,7 @@ class select_insert :public select_result_interceptor {
 class select_create: public select_insert {
   ORDER *group;
   TABLE_LIST *create_table;
-  HA_CREATE_INFO *create_info;
+  Table_specification_st *create_info;
   TABLE_LIST *select_tables;
   Alter_info *alter_info;
   Field **field;
@@ -4220,7 +4220,7 @@ class select_create: public select_insert {
 
 public:
   select_create (TABLE_LIST *table_arg,
-		 HA_CREATE_INFO *create_info_par,
+		 Table_specification_st *create_info_par,
                  Alter_info *alter_info_arg,
 		 List<Item> &select_fields,enum_duplicates duplic, bool ignore,
                  TABLE_LIST *select_tables_arg)
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index a930cb0..846f6e7 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -233,7 +233,7 @@ void my_dbopt_cleanup(void)
     1 on error.
 */
 
-static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
+static my_bool get_dbopt(const char *dbname, Schema_specification_st *create)
 {
   my_dbopt_t *opt;
   uint length;
@@ -264,7 +264,7 @@ static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
     1 on error.
 */
 
-static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
+static my_bool put_dbopt(const char *dbname, Schema_specification_st *create)
 {
   my_dbopt_t *opt;
   uint length;
@@ -333,7 +333,8 @@ static void del_dbopt(const char *path)
   1	Could not create file or write to it.  Error sent through my_error()
 */
 
-static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
+static bool write_db_opt(THD *thd, const char *path,
+                         Schema_specification_st *create)
 {
   register File file;
   char buf[256]; // Should be enough for one option
@@ -379,7 +380,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
 
 */
 
-bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
+bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create)
 {
   File file;
   char buf[256];
@@ -491,7 +492,7 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
 */
 
 bool load_db_opt_by_name(THD *thd, const char *db_name,
-                         HA_CREATE_INFO *db_create_info)
+                         Schema_specification_st *db_create_info)
 {
   char db_opt_path[FN_REFLEN + 1];
 
@@ -518,7 +519,7 @@ bool load_db_opt_by_name(THD *thd, const char *db_name,
 
 CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
 {
-  HA_CREATE_INFO db_info;
+  Schema_specification_st db_info;
 
   if (thd->db != NULL && strcmp(db_name, thd->db) == 0)
     return thd->db_charset;
@@ -545,6 +546,7 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
   thd		Thread handler
   db		Name of database to create
 		Function assumes that this is already validated.
+  options       DDL options, e.g. IF NOT EXISTS
   create_info	Database create options (like character set)
   silent	Used by replication when internally creating a database.
 		In this case the entry should not be logged.
@@ -561,14 +563,15 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
 
 */
 
-int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
-                     bool silent)
+int mysql_create_db(THD *thd, char *db,
+                    const DDL_options_st &options,
+                    Schema_specification_st *create_info,
+                    bool silent)
 {
   char	 path[FN_REFLEN+16];
   long result= 1;
   int error= 0;
   MY_STAT stat_info;
-  uint create_options= create_info ? create_info->options : 0;
   uint path_len;
   DBUG_ENTER("mysql_create_db");
 
@@ -598,7 +601,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
 
   if (mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
   {
-    if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
+    if (!options.if_not_exists())
     {
       my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
       error= -1;
@@ -702,7 +705,8 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
 
 /* db-name is already validated when we come here */
 
-bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
+bool mysql_alter_db(THD *thd, const char *db,
+                    Schema_specification_st *create_info)
 {
   char path[FN_REFLEN+16];
   long result=1;
@@ -773,7 +777,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
   @retval  true   Error
 */
 
-bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
+bool mysql_rm_db(THD *thd,char *db, bool if_exists, bool silent)
 {
   ulong deleted_tables= 0;
   bool error= true;
@@ -1602,7 +1606,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
   int error= 0, change_to_newdb= 0;
   char path[FN_REFLEN+16];
   uint length;
-  HA_CREATE_INFO create_info;
+  Schema_specification_st create_info;
   MY_DIR *dirp;
   TABLE_LIST *table_list;
   SELECT_LEX *sl= thd->lex->current_select;
@@ -1650,7 +1654,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
   }
 
   /* Step1: Create the new database */
-  if ((error= mysql_create_db(thd, new_db.str, &create_info, 1)))
+  if ((error= mysql_create_db(thd, new_db.str, DDL_options(), &create_info, 1)))
     goto exit;
 
   /* Step2: Move tables to the new database */
diff --git a/sql/sql_db.h b/sql/sql_db.h
index 62d379c..bdd5257 100644
--- a/sql/sql_db.h
+++ b/sql/sql_db.h
@@ -20,9 +20,12 @@
 
 class THD;
 
-int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
-bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
-bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
+int mysql_create_db(THD *thd, char *db,
+                    const DDL_options_st &options,
+                    Schema_specification_st *create, bool silent);
+bool mysql_alter_db(THD *thd, const char *db,
+                    Schema_specification_st *create);
+bool mysql_rm_db(THD *thd, char *db, bool if_exists, bool silent);
 bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db);
 bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
                      bool force_switch);
@@ -35,9 +38,9 @@ bool mysql_opt_change_db(THD *thd,
 bool my_dboptions_cache_init(void);
 void my_dboptions_cache_free(void);
 bool check_db_dir_existence(const char *db_name);
-bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
+bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create);
 bool load_db_opt_by_name(THD *thd, const char *db_name,
-                         HA_CREATE_INFO *db_create_info);
+                         Schema_specification_st *db_create_info);
 CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name);
 bool my_dbopt_init(void);
 void my_dbopt_cleanup(void);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 92f5f52..da437af 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -3841,7 +3841,8 @@ void select_insert::abort_result_set() {
   @retval 0         Error
 */
 
-static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
+static TABLE *create_table_from_items(THD *thd,
+                                      Table_specification_st *create_info,
                                       TABLE_LIST *create_table,
                                       Alter_info *alter_info,
                                       List<Item> *items,
@@ -4086,7 +4087,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
     row-based replication for the statement.  If we are creating a
     temporary table, we need to start a statement transaction.
   */
-  if (!thd->lex->create_info.tmp_table() &&
+  if (!thd->lex->tmp_table() &&
       thd->is_current_stmt_binlog_format_row() &&
       mysql_bin_log.is_open())
   {
@@ -4095,7 +4096,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
 
   DEBUG_SYNC(thd,"create_table_select_before_check_if_exists");
 
-  if (!(table= create_table_from_items(thd, create_info, create_table,
+  if (!(table= create_table_from_items(thd, create_info,
+                                       create_table,
                                        alter_info, &values,
                                        &extra_lock, hook_ptr)))
     /* abort() deletes table */
@@ -4178,8 +4180,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
   tmp_table_list.table = *tables;
   query.length(0);      // Have to zero it since constructor doesn't
 
-  result= show_create_table(thd, &tmp_table_list, &query, create_info,
-                            WITH_DB_NAME);
+  result= show_create_table(thd, &tmp_table_list, &query,
+                            create_info, WITH_DB_NAME);
   DBUG_ASSERT(result == 0); /* show_create_table() always return 0 */
 
   if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 4e6c0ef..0e68149 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -513,6 +513,7 @@ void lex_start(THD *thd)
   lex->use_only_table_context= FALSE;
   lex->parse_vcol_expr= FALSE;
   lex->check_exists= FALSE;
+  lex->create_info.lex_start();
   lex->verbose= 0;
 
   lex->name= null_lex_str;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b9546d71..511a5cf 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2430,7 +2430,7 @@ struct LEX: public Query_tables_list
   Item_sum *in_sum_func;
   udf_func udf;
   HA_CHECK_OPT   check_opt;			// check/repair options
-  HA_CREATE_INFO create_info;
+  Table_specification_st create_info;
   KEY_CREATE_INFO key_create_info;
   LEX_MASTER_INFO mi;				// used by CHANGE MASTER
   LEX_SERVER_OPTIONS server_options;
@@ -2511,7 +2511,7 @@ struct LEX: public Query_tables_list
   uint16 create_view_algorithm;
   uint8 create_view_check;
   uint8 context_analysis_only;
-  bool drop_temporary, local_file;
+  bool local_file;
   bool check_exists;
   bool autocommit;
   bool verbose, no_write_to_binlog;
@@ -2780,6 +2780,39 @@ struct LEX: public Query_tables_list
   int print_explain(select_result_sink *output, uint8 explain_flags,
                     bool is_analyze, bool *printed_anything);
   void restore_set_statement_var();
+  void set_command(enum_sql_command command,
+                   DDL_options_st options)
+  {
+    sql_command= command;
+    create_info.set(options);
+  }
+  void set_command(enum_sql_command command,
+                   uint scope,
+                   DDL_options_st options)
+  {
+    set_command(command, options);
+    create_info.options|= scope; // HA_LEX_CREATE_TMP_TABLE or 0
+  }
+  bool set_command_with_check(enum_sql_command command,
+                              uint scope,
+                              DDL_options_st options)
+  {
+    if (options.or_replace() && options.if_not_exists())
+    {
+      my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE", "IF NOT EXISTS");
+      return true;
+    }
+    set_command(command, scope, options);
+    return false;
+  }
+  /*
+    DROP shares lex->create_info to store TEMPORARY and IF EXISTS options
+    to save on extra initialization in lex_start().
+    Add some wrappers, to avoid direct use of lex->create_info in the
+    caller code processing DROP statements (which might look confusing).
+  */
+  bool tmp_table() const { return create_info.tmp_table(); }
+  bool if_exists() const { return create_info.if_exists(); }
 };
 
 
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 09f066b..4ccf586 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -218,12 +218,12 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask)
 
   switch (lex->sql_command) {
   case SQLCOM_DROP_TABLE:
-    skip= (lex->drop_temporary ||
+    skip= (lex->tmp_table() ||
            (thd->variables.option_bits & OPTION_GTID_BEGIN));
     break;
   case SQLCOM_ALTER_TABLE:
     /* If ALTER TABLE of non-temporary table, do implicit commit */
-    skip= (lex->create_info.tmp_table());
+    skip= (lex->tmp_table());
     break;
   case SQLCOM_CREATE_TABLE:
     /*
@@ -232,7 +232,7 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask)
       This ensures that CREATE ... SELECT will in the same GTID group on the
       master and slave.
     */
-    skip= (lex->create_info.tmp_table() ||
+    skip= (lex->tmp_table() ||
            (thd->variables.option_bits & OPTION_GTID_BEGIN));
     break;
   case SQLCOM_SET_OPTION:
@@ -1173,12 +1173,10 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
     DBUG_RETURN(FALSE);
 
   const my_bool create_temp_tables= 
-    (lex->sql_command == SQLCOM_CREATE_TABLE) &&
-    lex->create_info.tmp_table();
+    (lex->sql_command == SQLCOM_CREATE_TABLE) && lex->tmp_table();
 
   const my_bool drop_temp_tables= 
-    (lex->sql_command == SQLCOM_DROP_TABLE) &&
-    lex->drop_temporary;
+    (lex->sql_command == SQLCOM_DROP_TABLE) && lex->tmp_table();
 
   const my_bool update_real_tables=
     some_non_temp_table_to_be_updated(thd, all_tables) &&
@@ -2561,7 +2559,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
     if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
 	!(lex->sql_command == SQLCOM_SET_OPTION) &&
 	!(lex->sql_command == SQLCOM_DROP_TABLE &&
-          lex->drop_temporary && lex->check_exists) &&
+          lex->tmp_table() && lex->if_exists()) &&
         all_tables_not_ok(thd, all_tables))
     {
       /* we warn the slave SQL thread */
@@ -3145,7 +3143,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
       safe. A shallow copy is enough as this code won't modify any memory
       referenced from this structure.
     */
-    HA_CREATE_INFO create_info(lex->create_info);
+    Table_specification_st create_info(lex->create_info);
     /*
       We need to copy alter_info for the same reasons of re-execution
       safety, only in case of Alter_info we have to do (almost) a deep
@@ -3206,11 +3204,13 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
       CREATE TABLE OR EXISTS failures by dropping the table and
       retrying the create.
     */
-    create_info.org_options= create_info.options;
     if (thd->slave_thread &&
         slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT &&
-        !(lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS))
-      create_info.options|= HA_LEX_CREATE_REPLACE;
+        !lex->create_info.if_not_exists())
+    {
+      create_info.add(DDL_options_st::OPT_OR_REPLACE);
+      create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);
+    }
 
 #ifdef WITH_PARTITION_STORAGE_ENGINE
     {
@@ -3296,7 +3296,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
       /* Copy temporarily the statement flags to thd for lock_table_names() */
       uint save_thd_create_info_options= thd->lex->create_info.options;
       thd->lex->create_info.options|= create_info.options;
-      res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0);
+      res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
       thd->lex->create_info.options= save_thd_create_info_options;
       if (res)
       {
@@ -3307,8 +3307,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
       }
 
       /* Ensure we don't try to create something from which we select from */
-      if ((create_info.options & HA_LEX_CREATE_REPLACE) &&
-          !create_info.tmp_table())
+      if (create_info.or_replace() && !create_info.tmp_table())
       {
         TABLE_LIST *duplicate;
         if ((duplicate= unique_table(thd, lex->query_tables,
@@ -3361,7 +3360,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
     else
     {
       /* regular create */
-      if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+      if (create_info.like())
       {
         /* CREATE TABLE ... LIKE ... */
         res= mysql_create_like_table(thd, create_table, select_tables,
@@ -3373,13 +3372,12 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
            tables, like mysql replication does
         */
         if (WSREP(thd) && (!thd->is_current_stmt_binlog_format_row() ||
-            !(create_info.options & HA_LEX_CREATE_TMP_TABLE)))
+            !create_info.tmp_table()))
         {
 	  WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL)
         }
         /* Regular CREATE TABLE */
-        res= mysql_create_table(thd, create_table,
-                                &create_info, &alter_info);
+        res= mysql_create_table(thd, create_table, &create_info, &alter_info);
       }
       if (!res)
       {
@@ -4084,7 +4082,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
   case SQLCOM_DROP_TABLE:
   {
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
-    if (!lex->drop_temporary)
+    if (!lex->tmp_table())
     {
       if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
 	goto error;				/* purecov: inspected */
@@ -4098,7 +4096,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
    {
      for (TABLE_LIST *table= all_tables; table; table= table->next_global)
      {
-       if (!lex->drop_temporary                       &&
+       if (!lex->tmp_table() &&
           (!thd->is_current_stmt_binlog_format_row() ||
 	   !find_temporary_table(thd, table)))
        {
@@ -4115,11 +4113,10 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
     */
     if (thd->slave_thread && !thd->slave_expected_error &&
         slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT)
-      lex->check_exists= 1;
-
+      lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+    
     /* DDL and binlog write order are protected by metadata locks. */
-    res= mysql_rm_table(thd, first_table, lex->check_exists,
-			lex->drop_temporary);
+    res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table());
     break;
   }
   case SQLCOM_SHOW_PROCESSLIST:
@@ -4284,7 +4281,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
       it, we need to use a copy of LEX::create_info to make execution
       prepared statement- safe.
     */
-    HA_CREATE_INFO create_info(lex->create_info);
+    Schema_specification_st create_info(lex->create_info);
     if (check_db_name(&lex->name))
     {
       my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
@@ -4312,7 +4309,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
     if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0))
       break;
     WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
-    res= mysql_create_db(thd, lex->name.str, &create_info, 0);
+    res= mysql_create_db(thd, lex->name.str, lex->create_info, &create_info, 0);
     break;
   }
   case SQLCOM_DROP_DB:
@@ -4344,7 +4341,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
     if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0))
       break;
     WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
-    res= mysql_rm_db(thd, lex->name.str, lex->check_exists, 0);
+    res= mysql_rm_db(thd, lex->name.str, lex->if_exists(), 0);
     break;
   }
   case SQLCOM_ALTER_DB_UPGRADE:
@@ -4430,7 +4427,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
       my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
       break;
     }
-    res= mysqld_show_create_db(thd, &db_name, &lex->name, &lex->create_info);
+    res= mysqld_show_create_db(thd, &db_name, &lex->name, lex->create_info);
     break;
   }
   case SQLCOM_CREATE_EVENT:
@@ -4453,8 +4450,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
     switch (lex->sql_command) {
     case SQLCOM_CREATE_EVENT:
     {
-      bool if_not_exists= (lex->create_info.options &
-                           HA_LEX_CREATE_IF_NOT_EXISTS);
+      bool if_not_exists= lex->create_info.if_not_exists();
       res= Events::create_event(thd, lex->event_parse_data, if_not_exists);
       break;
     }
@@ -4487,7 +4483,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
     WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
     if (!(res= Events::drop_event(thd,
                                   lex->spname->m_db, lex->spname->m_name,
-                                  lex->check_exists)))
+                                  lex->if_exists())))
       my_ok(thd);
     break;
 #else
@@ -5223,7 +5219,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
 
         if (lex->spname->m_db.str == NULL)
         {
-          if (lex->check_exists)
+          if (lex->if_exists())
           {
             push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                                 ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
@@ -5293,7 +5289,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
 	my_ok(thd);
 	break;
       case SP_KEY_NOT_FOUND:
-	if (lex->check_exists)
+	if (lex->if_exists())
 	{
           res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
 	  push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
@@ -5526,7 +5522,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
 
     if ((err_code= drop_server(thd, &lex->server_options)))
     {
-      if (! lex->check_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
+      if (! lex->if_exists() && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
       {
         DBUG_PRINT("info", ("problem dropping server %s",
                             lex->server_options.server_name));
@@ -7145,7 +7141,8 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
                        List<String> *interval_list, CHARSET_INFO *cs,
 		       uint uint_geom_type,
 		       Virtual_column_info *vcol_info,
-                       engine_option_value *create_options)
+                       engine_option_value *create_options,
+                       bool check_exists)
 {
   register Create_field *new_field;
   LEX  *lex= thd->lex;
@@ -7164,7 +7161,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
     lex->col_list.push_back(new Key_part_spec(*field_name, 0));
     key= new Key(Key::PRIMARY, null_lex_str,
                       &default_key_create_info,
-                      0, lex->col_list, NULL, lex->check_exists);
+                      0, lex->col_list, NULL, check_exists);
     lex->alter_info.key_list.push_back(key);
     lex->col_list.empty();
   }
@@ -7174,7 +7171,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
     lex->col_list.push_back(new Key_part_spec(*field_name, 0));
     key= new Key(Key::UNIQUE, null_lex_str,
                  &default_key_create_info, 0,
-                 lex->col_list, NULL, lex->check_exists);
+                 lex->col_list, NULL, check_exists);
     lex->alter_info.key_list.push_back(key);
     lex->col_list.empty();
   }
@@ -7226,7 +7223,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
       new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
                       default_value, on_update_value, comment, change,
                       interval_list, cs, uint_geom_type, vcol_info,
-                      create_options, lex->check_exists))
+                      create_options, check_exists))
     DBUG_RETURN(1);
 
   lex->alter_info.create_list.push_back(new_field);
@@ -8585,7 +8582,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex)
 {
   TABLE_LIST *create_table= lex->query_tables;
 
-  if (lex->create_info.tmp_table())
+  if (lex->tmp_table())
     create_table->open_type= OT_TEMPORARY_ONLY;
   else
     create_table->open_type= OT_BASE_ONLY;
@@ -8631,12 +8628,11 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
     CREATE TABLE ... SELECT, also require INSERT.
   */
 
-  want_priv= lex->create_info.tmp_table() ?  CREATE_TMP_ACL :
+  want_priv= lex->tmp_table() ?  CREATE_TMP_ACL :
              (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0));
 
   /* CREATE OR REPLACE on not temporary tables require DROP_ACL */
-  if ((lex->create_info.options & HA_LEX_CREATE_REPLACE) &&
-      !lex->create_info.tmp_table())
+  if (lex->create_info.or_replace() && !lex->tmp_table())
     want_priv|= DROP_ACL;
                           
   if (check_access(thd, want_priv, create_table->db,
@@ -8700,7 +8696,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                                      UINT_MAX, FALSE))
       goto err;
   }
-  else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+  else if (lex->create_info.like())
   {
     if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
       goto err;
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index da024a5..a419841 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -113,7 +113,8 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum enum_field_types t
 		       CHARSET_INFO *cs,
 		       uint uint_geom_type,
                        Virtual_column_info *vcol_info,
-                       engine_option_value *create_options);
+                       engine_option_value *create_options,
+                       bool check_exists);
 bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *group, bool asc);
 void add_join_on(TABLE_LIST *b,Item *expr);
 void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields,
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 0541cbc..2536255 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1187,7 +1187,7 @@ class Show_create_error_handler : public Internal_error_handler {
 
 bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
                            LEX_STRING *orig_dbname,
-                           HA_CREATE_INFO *create_info)
+                           const DDL_options_st &options)
 {
   char buff[2048];
   String buffer(buff, sizeof(buff), system_charset_info);
@@ -1196,7 +1196,6 @@ bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
   uint db_access;
 #endif
   HA_CREATE_INFO create;
-  uint create_options = create_info ? create_info->options : 0;
   Protocol *protocol=thd->protocol;
   DBUG_ENTER("mysql_show_create_db");
 
@@ -1243,7 +1242,7 @@ bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
   protocol->store(orig_dbname->str, orig_dbname->length, system_charset_info);
   buffer.length(0);
   buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
-  if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
+  if (options.if_not_exists())
     buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
   append_identifier(thd, &buffer, dbname->str, dbname->length);
 
@@ -1654,7 +1653,7 @@ static void append_create_options(THD *thd, String *packet,
  */
 
 int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
-                      HA_CREATE_INFO *create_info_arg,
+                      Table_specification_st *create_info_arg,
                       enum_with_db_name with_db_name)
 {
   List<Item> field_list;
@@ -1696,14 +1695,14 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
 
   packet->append(STRING_WITH_LEN("CREATE "));
   if (create_info_arg &&
-      (create_info_arg->org_options & HA_LEX_CREATE_REPLACE ||
+      ((create_info_arg->or_replace() &&
+        !create_info_arg->or_replace_slave_generated()) ||
        create_info_arg->table_was_deleted))
     packet->append(STRING_WITH_LEN("OR REPLACE "));
   if (share->tmp_table)
     packet->append(STRING_WITH_LEN("TEMPORARY "));
   packet->append(STRING_WITH_LEN("TABLE "));
-  if (create_info_arg &&
-      (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
+  if (create_info_arg && create_info_arg->if_not_exists())
     packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
   if (table_list->schema_table)
     alias= table_list->schema_table->table_name;
diff --git a/sql/sql_show.h b/sql/sql_show.h
index bad2b41..4bdfe95 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -76,7 +76,7 @@
 
 typedef enum { WITHOUT_DB_NAME, WITH_DB_NAME } enum_with_db_name;
 int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
-                      HA_CREATE_INFO  *create_info_arg,
+                      Table_specification_st *create_info_arg,
                       enum_with_db_name with_db_name);
 
 int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
@@ -88,7 +88,7 @@ bool append_identifier(THD *thd, String *packet, const char *name,
 bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
 bool mysqld_show_create_db(THD *thd, LEX_STRING *db_name,
                            LEX_STRING *orig_db_name,
-                           HA_CREATE_INFO *create);
+                           const DDL_options_st &options);
 
 void mysqld_list_processes(THD *thd,const char *user,bool verbose);
 int mysqld_show_status(THD *thd);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index b991215..6ea653d 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4628,6 +4628,7 @@ int create_table_impl(THD *thd,
                        const char *orig_db, const char *orig_table_name,
                        const char *db, const char *table_name,
                        const char *path,
+                       const DDL_options_st options,
                        HA_CREATE_INFO *create_info,
                        Alter_info *alter_info,
                        int create_table_mode,
@@ -4672,7 +4673,7 @@ int create_table_impl(THD *thd,
     if ((tmp_table= find_temporary_table(thd, db, table_name)))
     {
       bool table_creation_was_logged= tmp_table->s->table_creation_was_logged;
-      if (create_info->options & HA_LEX_CREATE_REPLACE)
+      if (options.or_replace())
       {
         bool is_trans;
         /*
@@ -4682,7 +4683,7 @@ int create_table_impl(THD *thd,
         if (drop_temporary_table(thd, tmp_table, &is_trans))
           goto err;
       }
-      else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+      else if (options.if_not_exists())
         goto warn;
       else
       {
@@ -4708,7 +4709,7 @@ int create_table_impl(THD *thd,
   {
     if (!internal_tmp_table && ha_table_exists(thd, db, table_name))
     {
-      if (create_info->options & HA_LEX_CREATE_REPLACE)
+      if (options.or_replace())
       {
         TABLE_LIST table_list;
         table_list.init_one_table(db, strlen(db), table_name,
@@ -4744,7 +4745,7 @@ int create_table_impl(THD *thd,
             restart_trans_for_tables(thd, thd->lex->query_tables))
           goto err;
       }
-      else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+      else if (options.if_not_exists())
         goto warn;
       else
       {
@@ -4900,7 +4901,7 @@ int create_table_impl(THD *thd,
 
 int mysql_create_table_no_lock(THD *thd,
                                 const char *db, const char *table_name,
-                                HA_CREATE_INFO *create_info,
+                                Table_specification_st *create_info,
                                 Alter_info *alter_info, bool *is_trans,
                                 int create_table_mode)
 {
@@ -4927,7 +4928,8 @@ int mysql_create_table_no_lock(THD *thd,
   }
 
   res= create_table_impl(thd, db, table_name, db, table_name, path,
-                         create_info, alter_info, create_table_mode,
+                         *create_info, create_info,
+                         alter_info, create_table_mode,
                          is_trans, &not_used_1, &not_used_2, &frm);
   my_free(const_cast<uchar*>(frm.str));
   return res;
@@ -4944,7 +4946,7 @@ int mysql_create_table_no_lock(THD *thd,
 */
 
 bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
-                        HA_CREATE_INFO *create_info,
+                        Table_specification_st *create_info,
                         Alter_info *alter_info)
 {
   const char *db= create_table->db;
@@ -4963,7 +4965,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
   thd->lex->create_info.options|= create_info->options;
 
   /* Open or obtain an exclusive metadata lock on table being created  */
-  result= open_and_lock_tables(thd, create_table, FALSE, 0);
+  result= open_and_lock_tables(thd, *create_info, create_table, FALSE, 0);
 
   thd->lex->create_info.options= save_thd_create_info_options;
 
@@ -5000,7 +5002,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
     on a non temporary table
   */
   if (thd->locked_tables_mode && pos_in_locked_tables &&
-      (create_info->options & HA_LEX_CREATE_REPLACE))
+      create_info->or_replace())
   {
     /*
       Add back the deleted table and re-created table as a locked table
@@ -5241,9 +5243,9 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
 
 bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
                              TABLE_LIST* src_table,
-                             HA_CREATE_INFO *create_info)
+                             Table_specification_st *create_info)
 {
-  HA_CREATE_INFO local_create_info;
+  Table_specification_st local_create_info;
   TABLE_LIST *pos_in_locked_tables= 0;
   Alter_info local_alter_info;
   Alter_table_ctx local_alter_ctx; // Not used
@@ -5273,6 +5275,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
   */
 
   /* Copy temporarily the statement flags to thd for lock_table_names() */
+  // QQ: is this really needed???
   uint save_thd_create_info_options= thd->lex->create_info.options;
   thd->lex->create_info.options|= create_info->options;
   res= open_tables(thd, &thd->lex->query_tables, &not_used, 0);
@@ -5285,8 +5288,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
     goto err;
   }
   /* Ensure we don't try to create something from which we select from */
-  if ((create_info->options & HA_LEX_CREATE_REPLACE) &&
-      !create_info->tmp_table())
+  if (create_info->or_replace() && !create_info->tmp_table())
   {
     TABLE_LIST *duplicate;
     if ((duplicate= unique_table(thd, table, src_table, 0)))
@@ -5300,8 +5302,12 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
 
   DEBUG_SYNC(thd, "create_table_like_after_open");
 
-  /* Fill HA_CREATE_INFO and Alter_info with description of source table. */
-  bzero((char*) &local_create_info, sizeof(local_create_info));
+  /*
+    Fill Table_specification_st and Alter_info with the source table description.
+    Set OR REPLACE and IF NOT EXISTS option as in the CREATE TABLE LIKE
+    statement.
+  */
+  local_create_info.init(create_info->create_like_options());
   local_create_info.db_type= src_table->table->s->db_type();
   local_create_info.row_type= src_table->table->s->row_type;
   if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
@@ -5322,10 +5328,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
   */
   if (src_table->schema_table)
     local_create_info.max_rows= 0;
-  /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
-  local_create_info.options|= (create_info->options &
-                               (HA_LEX_CREATE_IF_NOT_EXISTS | 
-                                HA_LEX_CREATE_REPLACE));
   /* Replace type of source table with one specified in the statement. */
   local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
   local_create_info.options|= create_info->tmp_table();
@@ -5355,7 +5357,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
     on a non temporary table
   */
   if (thd->locked_tables_mode && pos_in_locked_tables &&
-      (create_info->options & HA_LEX_CREATE_REPLACE))
+      create_info->or_replace())
   {
     /*
       Add back the deleted table and re-created table as a locked table
@@ -5465,7 +5467,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
         if (!table->view)
         {
           int result __attribute__((unused))=
-            show_create_table(thd, table, &query, create_info, WITHOUT_DB_NAME);
+            show_create_table(thd, table, &query,
+                              create_info, WITHOUT_DB_NAME);
 
           DBUG_ASSERT(result == 0); // show_create_table() always return 0
           do_logging= FALSE;
@@ -5918,7 +5921,7 @@ static bool is_candidate_key(KEY *key)
   
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   partition_info *tab_part_info= table->part_info;
-  if (tab_part_info && thd->lex->check_exists)
+  if (tab_part_info && thd->lex->if_exists())
   {
     /* ALTER TABLE ADD PARTITION IF NOT EXISTS */
     if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION)
@@ -8645,7 +8648,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
                            alter_ctx.db, alter_ctx.table_name,
                            alter_ctx.new_db, alter_ctx.tmp_name,
                            alter_ctx.get_tmp_path(),
-                           create_info, alter_info,
+                           thd->lex->create_info, create_info, alter_info,
                            C_ALTER_TABLE_FRM_ONLY, NULL,
                            &key_info, &key_count, &frm);
   reenable_binlog(thd);
diff --git a/sql/sql_table.h b/sql/sql_table.h
index c3e903a..85a3393 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -31,6 +31,7 @@
 class handler;
 typedef struct st_ha_check_opt HA_CHECK_OPT;
 struct HA_CREATE_INFO;
+struct Table_specification_st;
 typedef struct st_key KEY;
 typedef struct st_key_cache KEY_CACHE;
 typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE;
@@ -151,7 +152,7 @@ uint build_table_shadow_filename(char *buff, size_t bufflen,
                                  ALTER_PARTITION_PARAM_TYPE *lpt);
 uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen);
 bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
-                        HA_CREATE_INFO *create_info,
+                        Table_specification_st *create_info,
                         Alter_info *alter_info);
 
 /*
@@ -192,7 +193,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
 
 int mysql_create_table_no_lock(THD *thd, const char *db,
                                const char *table_name,
-                               HA_CREATE_INFO *create_info,
+                               Table_specification_st *create_info,
                                Alter_info *alter_info, bool *is_trans,
                                int create_table_mode);
 
@@ -227,7 +228,7 @@ bool mysql_compare_tables(TABLE *table,
 bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy);
 bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
                              TABLE_LIST *src_table,
-                             HA_CREATE_INFO *create_info);
+                             Table_specification_st *create_info);
 bool mysql_rename_table(handlerton *base, const char *old_db,
                         const char * old_name, const char *new_db,
                         const char * new_name, uint flags);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 443a82a..f404daa 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -444,7 +444,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
 
   if (!create)
   {
-    bool if_exists= thd->lex->check_exists;
+    bool if_exists= thd->lex->if_exists();
 
     /*
       Protect the query table list from the temporary and potentially
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 07169f2..b064546 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1640,7 +1640,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
     {
       char name[FN_REFLEN];
       my_snprintf(name, sizeof(name), "%s.%s", view->db, view->table_name);
-      if (thd->lex->check_exists)
+      if (thd->lex->if_exists())
       {
 	push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
 			    ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b43f433..218651f 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -738,11 +738,12 @@ static bool add_create_index_prepare (LEX *lex, Table_ident *table)
 
 static bool add_create_index (LEX *lex, Key::Keytype type,
                               const LEX_STRING &name,
+                              bool check_exists,
                               KEY_CREATE_INFO *info= NULL, bool generated= 0)
 {
   Key *key;
   key= new Key(type, name, info ? info : &lex->key_create_info, generated, 
-               lex->col_list, lex->option_list, lex->check_exists);
+               lex->col_list, lex->option_list, check_exists);
   if (key == NULL)
     return TRUE;
 
@@ -923,6 +924,7 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
   List<Condition_information_item> *cond_info_list;
   DYNCALL_CREATE_DEF *dyncol_def;
   List<DYNCALL_CREATE_DEF> *dyncol_def_list;
+  DDL_options_st object_ddl_options;
 }
 
 %{
@@ -1624,7 +1626,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
         IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
         NCHAR_STRING opt_component key_cache_name
         sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
-        opt_constraint constraint opt_ident opt_if_not_exists_ident
+        opt_constraint constraint opt_ident
+        opt_if_not_exists_opt_table_element_name
 
 %type <lex_str_ptr>
         opt_table_alias
@@ -1642,8 +1645,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
 
 %type <num>
         type type_with_opt_collate int_type real_type order_dir lock_option
-        udf_type opt_if_exists opt_local opt_table_options table_options
-        table_option opt_if_not_exists create_or_replace opt_no_write_to_binlog
+        udf_type opt_local opt_table_options table_options
+        table_option opt_no_write_to_binlog
         opt_temporary all_or_any opt_distinct
         opt_ignore_leaves fulltext_options spatial_type union_option
         field_def opt_not opt_union_order_or_limit
@@ -1655,6 +1658,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
         opt_time_precision kill_type kill_option int_num
         opt_default_time_precision
         case_stmt_body
+        opt_if_exists_table_element opt_if_not_exists_table_element
+
+%type <object_ddl_options>
+        create_or_replace 
+        opt_if_not_exists
+        opt_if_exists
 
 /*
   Bit field of MYSQL_START_TRANS_OPT_* flags.
@@ -2330,12 +2339,9 @@ create:
           create_or_replace opt_table_options TABLE_SYM opt_if_not_exists table_ident
           {
             LEX *lex= thd->lex;
-            lex->sql_command= SQLCOM_CREATE_TABLE;
-            if ($1 && $4)
-            {
-               my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE", "IF NOT EXISTS");
+            lex->create_info.init();
+            if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
                MYSQL_YYABORT;
-            }
             if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
                                                    TL_OPTION_UPDATING,
                                                    TL_WRITE, MDL_EXCLUSIVE))
@@ -2343,13 +2349,11 @@ create:
             lex->alter_info.reset();
             lex->col_list.empty();
             lex->change=NullS;
-            bzero((char*) &lex->create_info,sizeof(lex->create_info));
             /*
               For CREATE TABLE we should not open the table even if it exists.
               If the table exists, we should either not create it or replace it
             */
             lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
-            lex->create_info.options= ($1 | $2 | $4);
             lex->create_info.default_table_charset= NULL;
             lex->name= null_lex_str;
             lex->create_last_non_select_table= lex->last_table();
@@ -2370,18 +2374,20 @@ create:
             }
             create_table_set_open_action_and_adjust_tables(lex);
           }
-        | CREATE opt_unique INDEX_SYM opt_if_not_exists ident key_alg ON table_ident
+        | CREATE opt_unique INDEX_SYM opt_if_not_exists ident
+          key_alg ON table_ident
           {
             if (add_create_index_prepare(Lex, $8))
               MYSQL_YYABORT;
           }
           '(' key_list ')' normal_key_options
           {
-            if (add_create_index(Lex, $2, $5))
+            if (add_create_index(Lex, $2, $5, $4.if_not_exists()))
               MYSQL_YYABORT;
           }
           opt_index_lock_algorithm { }
-        | CREATE fulltext INDEX_SYM opt_if_not_exists ident init_key_options ON
+        | CREATE fulltext INDEX_SYM opt_if_not_exists ident
+          init_key_options ON
           table_ident
           {
             if (add_create_index_prepare(Lex, $8))
@@ -2389,11 +2395,12 @@ create:
           }
           '(' key_list ')' fulltext_key_options
           {
-            if (add_create_index(Lex, $2, $5))
+            if (add_create_index(Lex, $2, $5, $4.if_not_exists()))
               MYSQL_YYABORT;
           }
           opt_index_lock_algorithm { }
-        | CREATE spatial INDEX_SYM opt_if_not_exists ident init_key_options ON
+        | CREATE spatial INDEX_SYM opt_if_not_exists ident
+          init_key_options ON
           table_ident
           {
             if (add_create_index_prepare(Lex, $8))
@@ -2401,7 +2408,7 @@ create:
           }
           '(' key_list ')' spatial_key_options
           {
-            if (add_create_index(Lex, $2, $5))
+            if (add_create_index(Lex, $2, $5, $4.if_not_exists()))
               MYSQL_YYABORT;
           }
           opt_index_lock_algorithm { }
@@ -2413,20 +2420,19 @@ create:
           opt_create_database_options
           {
             LEX *lex=Lex;
-            lex->sql_command=SQLCOM_CREATE_DB;
+            lex->set_command(SQLCOM_CREATE_DB, $3);
             lex->name= $4;
-            lex->create_info.options=$3;
           }
         | create_or_replace
           {
-            Lex->create_view_mode= ($1 == 0 ? VIEW_CREATE_NEW :
-                                    VIEW_CREATE_OR_REPLACE);
+            Lex->create_view_mode= ($1.or_replace() ? VIEW_CREATE_OR_REPLACE :
+                                                      VIEW_CREATE_NEW);
             Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED;
             Lex->create_view_suid= TRUE;
           }
           view_or_trigger_or_sp_or_event
           {
-            if ($1 && Lex->sql_command != SQLCOM_CREATE_VIEW)
+            if ($1.or_replace() && Lex->sql_command != SQLCOM_CREATE_VIEW)
             {
                my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE",
                        "TRIGGERS / SP / EVENT");
@@ -2510,7 +2516,7 @@ event_tail:
             LEX *lex=Lex;
 
             lex->stmt_definition_begin= $1;
-            lex->create_info.options= $3;
+            lex->create_info.set($3);
             if (!(lex->event_parse_data= Event_parse_data::new_instance(thd)))
               MYSQL_YYABORT;
             lex->event_parse_data->identifier= $4;
@@ -4722,7 +4728,7 @@ create_body:
         | create_like
           {
 
-            Lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
+            Lex->create_info.add(DDL_options_st::OPT_LIKE);
             TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd,
                                         $1, NULL, 0, TL_READ, MDL_SHARED_READ);
             if (! src_table)
@@ -5515,27 +5521,36 @@ table_option:
           TEMPORARY { $$=HA_LEX_CREATE_TMP_TABLE; }
         ;
 
-opt_if_not_exists:
+opt_if_not_exists_table_element:
           /* empty */
           {
             Lex->check_exists= FALSE;
-            $$= 0;
           }
         | IF_SYM not EXISTS
           {
             Lex->check_exists= TRUE;
-            $$=HA_LEX_CREATE_IF_NOT_EXISTS;
+          }
+         ;
+
+opt_if_not_exists:
+          /* empty */
+          {
+            $$.init();
+          }
+        | IF_SYM not EXISTS
+          {
+            $$.set(DDL_options_st::OPT_IF_NOT_EXISTS);
           }
          ;
 
 create_or_replace:
           CREATE /* empty */
           {
-            $$= 0;
+            $$.init();
           }
         | CREATE OR_SYM REPLACE
           {
-            $$= HA_LEX_CREATE_REPLACE;
+            $$.set(DDL_options_st::OPT_OR_REPLACE);
           }
          ;
 
@@ -5920,38 +5935,40 @@ column_def:
         ;
 
 key_def:
-          normal_key_type opt_if_not_exists_ident key_alg '(' key_list ')'
+          normal_key_type opt_if_not_exists_opt_table_element_name
+          key_alg '(' key_list ')'
           { Lex->option_list= NULL; }
           normal_key_options
           {
-            if (add_create_index (Lex, $1, $2))
+            if (add_create_index (Lex, $1, $2, Lex->check_exists))
               MYSQL_YYABORT;
           }
-        | fulltext opt_key_or_index opt_if_not_exists_ident init_key_options 
-            '(' key_list ')'
+        | fulltext opt_key_or_index opt_if_not_exists_opt_table_element_name
+          init_key_options '(' key_list ')'
           { Lex->option_list= NULL; }
             fulltext_key_options
           {
-            if (add_create_index (Lex, $1, $3))
+            if (add_create_index (Lex, $1, $3, Lex->check_exists))
               MYSQL_YYABORT;
           }
-        | spatial opt_key_or_index opt_if_not_exists_ident init_key_options 
-            '(' key_list ')'
+        | spatial opt_key_or_index opt_if_not_exists_opt_table_element_name
+          init_key_options '(' key_list ')'
           { Lex->option_list= NULL; }
             spatial_key_options
           {
-            if (add_create_index (Lex, $1, $3))
+            if (add_create_index (Lex, $1, $3, Lex->check_exists))
               MYSQL_YYABORT;
           }
-        | opt_constraint constraint_key_type opt_if_not_exists_ident key_alg
-          '(' key_list ')'
+        | opt_constraint constraint_key_type
+          opt_if_not_exists_opt_table_element_name key_alg '(' key_list ')'
           { Lex->option_list= NULL; }
           normal_key_options
           {
-            if (add_create_index (Lex, $2, $3.str ? $3 : $1))
+            if (add_create_index (Lex, $2, $3.str ? $3 : $1, Lex->check_exists))
               MYSQL_YYABORT;
           }
-        | opt_constraint FOREIGN KEY_SYM opt_if_not_exists_ident '(' key_list ')' references
+        | opt_constraint FOREIGN KEY_SYM opt_if_not_exists_opt_table_element_name
+          '(' key_list ')' references
           {
             LEX *lex=Lex;
             Key *key= new Foreign_key($4.str ? $4 : $1, lex->col_list,
@@ -5967,6 +5984,7 @@ key_def:
             lex->alter_info.key_list.push_back(key);
             lex->option_list= NULL;
             if (add_create_index (lex, Key::MULTIPLE, $1.str ? $1 : $4,
+                                  Lex->check_exists,
                                   &default_key_create_info, 1))
               MYSQL_YYABORT;
             /* Only used for ALTER TABLE. Ignored otherwise. */
@@ -6017,7 +6035,8 @@ field_spec:
                                   &lex->comment,
                                   lex->change,&lex->interval_list,lex->charset,
                                   lex->uint_geom_type,
-                                  lex->vcol_info, lex->option_list))
+                                  lex->vcol_info, lex->option_list,
+                                  lex->check_exists))
               MYSQL_YYABORT;
           }
         ;
@@ -6993,8 +7012,8 @@ opt_ident:
         | field_ident { $$= $1; }
         ;
 
-opt_if_not_exists_ident:
-        opt_if_not_exists opt_ident
+opt_if_not_exists_opt_table_element_name:
+        opt_if_not_exists_table_element opt_ident
         {
           LEX *lex= Lex;
           if (lex->check_exists && lex->sql_command != SQLCOM_ALTER_TABLE)
@@ -7026,9 +7045,7 @@ alter:
             Lex->duplicates= DUP_ERROR; 
             Lex->col_list.empty();
             Lex->select_lex.init_order();
-            bzero(&Lex->create_info, sizeof(Lex->create_info));
-            Lex->create_info.db_type= 0;
-            Lex->create_info.default_table_charset= NULL;
+            Lex->create_info.init();
             Lex->create_info.row_type= ROW_TYPE_NOT_USED;
             Lex->alter_info.reset();
             Lex->no_write_to_binlog= 0;
@@ -7277,6 +7294,8 @@ alter_commands:
         | DROP PARTITION_SYM opt_if_exists alt_part_name_list
           {
             Lex->alter_info.flags|= Alter_info::ALTER_DROP_PARTITION;
+            DBUG_ASSERT(!Lex->if_exists());
+            Lex->create_info.add(DDL_options_st::OPT_IF_EXISTS);
           }
         | REBUILD_SYM PARTITION_SYM opt_no_write_to_binlog
           all_or_alt_part_name_list
@@ -7394,7 +7413,8 @@ all_or_alt_part_name_list:
         ;
 
 add_partition_rule:
-          ADD PARTITION_SYM opt_if_not_exists opt_no_write_to_binlog
+          ADD PARTITION_SYM opt_if_not_exists_table_element
+          opt_no_write_to_binlog
           {
             LEX *lex= Lex;
             lex->part_info= new partition_info();
@@ -7480,7 +7500,7 @@ alter_list:
         ;
 
 add_column:
-          ADD opt_column opt_if_not_exists
+          ADD opt_column opt_if_not_exists_table_element
           {
             LEX *lex=Lex;
             lex->change=0;
@@ -7503,7 +7523,7 @@ alter_list_item:
             Lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN |
                                     Alter_info::ALTER_ADD_INDEX;
           }
-        | CHANGE opt_column opt_if_exists field_ident
+        | CHANGE opt_column opt_if_exists_table_element field_ident
           {
             LEX *lex=Lex;
             lex->change= $4.str;
@@ -7514,7 +7534,7 @@ alter_list_item:
           {
             Lex->create_last_non_select_table= Lex->last_table();
           }
-        | MODIFY_SYM opt_column opt_if_exists field_ident
+        | MODIFY_SYM opt_column opt_if_exists_table_element field_ident
           {
             LEX *lex=Lex;
             lex->length=lex->dec=0; lex->type=0;
@@ -7535,14 +7555,14 @@ alter_list_item:
                                   &lex->comment,
                                   $4.str, &lex->interval_list, lex->charset,
                                   lex->uint_geom_type,
-                                  lex->vcol_info, lex->option_list))
+                                  lex->vcol_info, lex->option_list, $3))
               MYSQL_YYABORT;
           }
           opt_place
           {
             Lex->create_last_non_select_table= Lex->last_table();
           }
-        | DROP opt_column opt_if_exists field_ident opt_restrict
+        | DROP opt_column opt_if_exists_table_element field_ident opt_restrict
           {
             LEX *lex=Lex;
             Alter_drop *ad= new Alter_drop(Alter_drop::COLUMN, $4.str, $3);
@@ -7551,7 +7571,7 @@ alter_list_item:
             lex->alter_info.drop_list.push_back(ad);
             lex->alter_info.flags|= Alter_info::ALTER_DROP_COLUMN;
           }
-        | DROP FOREIGN KEY_SYM opt_if_exists field_ident
+        | DROP FOREIGN KEY_SYM opt_if_exists_table_element field_ident
           {
             LEX *lex=Lex;
             Alter_drop *ad= new Alter_drop(Alter_drop::FOREIGN_KEY, $5.str, $4);
@@ -7570,7 +7590,7 @@ alter_list_item:
             lex->alter_info.drop_list.push_back(ad);
             lex->alter_info.flags|= Alter_info::ALTER_DROP_INDEX;
           }
-        | DROP key_or_index opt_if_exists field_ident
+        | DROP key_or_index opt_if_exists_table_element field_ident
           {
             LEX *lex=Lex;
             Alter_drop *ad= new Alter_drop(Alter_drop::KEY, $4.str, $3);
@@ -11693,15 +11713,13 @@ drop:
           DROP opt_temporary table_or_tables opt_if_exists
           {
             LEX *lex=Lex;
-            lex->sql_command = SQLCOM_DROP_TABLE;
-            lex->drop_temporary= $2;
-            lex->check_exists= $4;
+            lex->set_command(SQLCOM_DROP_TABLE, $2, $4);
             YYPS->m_lock_type= TL_UNLOCK;
             YYPS->m_mdl_type= MDL_EXCLUSIVE;
           }
           table_list opt_restrict
           {}
-        | DROP INDEX_SYM opt_if_exists ident ON table_ident {}
+        | DROP INDEX_SYM opt_if_exists_table_element ident ON table_ident {}
           {
             LEX *lex=Lex;
             Alter_drop *ad= new Alter_drop(Alter_drop::KEY, $4.str, $3);
@@ -11720,8 +11738,7 @@ drop:
         | DROP DATABASE opt_if_exists ident
           {
             LEX *lex=Lex;
-            lex->sql_command= SQLCOM_DROP_DB;
-            lex->check_exists=$3;
+            lex->set_command(SQLCOM_DROP_DB, $3);
             lex->name= $4;
           }
         | DROP FUNCTION_SYM opt_if_exists ident '.' ident
@@ -11738,8 +11755,7 @@ drop:
               my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
               MYSQL_YYABORT;
             }
-            lex->sql_command = SQLCOM_DROP_FUNCTION;
-            lex->check_exists= $3;
+            lex->set_command(SQLCOM_DROP_FUNCTION, $3);
             spname= new sp_name($4, $6, true);
             if (spname == NULL)
               MYSQL_YYABORT;
@@ -11758,8 +11774,7 @@ drop:
             }
             if (thd->db && lex->copy_db_to(&db.str, &db.length))
               MYSQL_YYABORT;
-            lex->sql_command = SQLCOM_DROP_FUNCTION;
-            lex->check_exists= $3;
+            lex->set_command(SQLCOM_DROP_FUNCTION, $3);
             spname= new sp_name(db, $4, false);
             if (spname == NULL)
               MYSQL_YYABORT;
@@ -11774,8 +11789,7 @@ drop:
               my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
               MYSQL_YYABORT;
             }
-            lex->sql_command = SQLCOM_DROP_PROCEDURE;
-            lex->check_exists= $3;
+            lex->set_command(SQLCOM_DROP_PROCEDURE, $3);
             lex->spname= $4;
           }
         | DROP USER clear_privileges user_list
@@ -11789,8 +11803,7 @@ drop:
         | DROP VIEW_SYM opt_if_exists
           {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_DROP_VIEW;
-            lex->check_exists= $3;
+            lex->set_command(SQLCOM_DROP_VIEW, $3);
             YYPS->m_lock_type= TL_UNLOCK;
             YYPS->m_mdl_type= MDL_EXCLUSIVE;
           }
@@ -11798,15 +11811,13 @@ drop:
           {}
         | DROP EVENT_SYM opt_if_exists sp_name
           {
-            Lex->check_exists= $3;
             Lex->spname= $4;
-            Lex->sql_command = SQLCOM_DROP_EVENT;
+            Lex->set_command(SQLCOM_DROP_EVENT, $3);
           }
         | DROP TRIGGER_SYM opt_if_exists sp_name
           {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_DROP_TRIGGER;
-            lex->check_exists= $3;
+            lex->set_command(SQLCOM_DROP_TRIGGER, $3);
             lex->spname= $4;
           }
         | DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait
@@ -11821,8 +11832,7 @@ drop:
           }
         | DROP SERVER_SYM opt_if_exists ident_or_text
           {
-            Lex->sql_command = SQLCOM_DROP_SERVER;
-            Lex->check_exists= $3;
+            Lex->set_command(SQLCOM_DROP_SERVER, $3);
             Lex->server_options.server_name= $4.str;
             Lex->server_options.server_name_length= $4.length;
           }
@@ -11873,7 +11883,7 @@ table_alias_ref:
           }
         ;
 
-opt_if_exists:
+opt_if_exists_table_element:
           /* empty */
         {
           Lex->check_exists= FALSE;
@@ -11886,9 +11896,20 @@ opt_if_exists:
         }
         ;
 
+opt_if_exists:
+          /* empty */
+        {
+          $$.set(DDL_options_st::OPT_NONE);
+        }
+        | IF_SYM EXISTS
+        {
+          $$.set(DDL_options_st::OPT_IF_EXISTS);
+        }
+        ;
+
 opt_temporary:
           /* empty */ { $$= 0; }
-        | TEMPORARY { $$= 1; }
+        | TEMPORARY { $$= HA_LEX_CREATE_TMP_TABLE;; }
         ;
 /*
 ** Insert : add new data to table
@@ -12357,7 +12378,7 @@ show:
             lex->ident=null_lex_str;
             mysql_init_select(lex);
             lex->current_select->parsing_place= SELECT_LIST;
-            bzero((char*) &lex->create_info,sizeof(lex->create_info));
+            lex->create_info.init();
           }
           show_param
           {
@@ -12559,8 +12580,7 @@ show_param:
           }
         | CREATE DATABASE opt_if_not_exists ident
           {
-            Lex->sql_command=SQLCOM_SHOW_CREATE_DB;
-            Lex->create_info.options=$3;
+            Lex->set_command(SQLCOM_SHOW_CREATE_DB, $3);
             Lex->name= $4;
           }
         | CREATE TABLE_SYM table_ident
diff --git a/sql/structs.h b/sql/structs.h
index 99561c5..9e9d7f9 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -471,4 +471,79 @@ class Discrete_intervals_list {
   Discrete_interval* get_current() const { return current; };
 };
 
+
+/*
+  DDL options:
+  - CREATE IF NOT EXISTS
+  - DROP IF EXISTS
+  - CRESTE LIKE
+  - REPLACE
+*/
+struct DDL_options_st
+{
+public:
+  enum Options
+  {
+    OPT_NONE= 0,
+    OPT_IF_NOT_EXISTS= 2,              // CREATE TABLE IF NOT EXISTS
+    OPT_LIKE= 4,                       // CREATE TABLE LIKE
+    OPT_OR_REPLACE= 16,                // CREATE OR REPLACE TABLE
+    OPT_OR_REPLACE_SLAVE_GENERATED= 32,// REPLACE was added on slave, it was
+                                       // not in the original query on master.
+    OPT_IF_EXISTS= 64
+  };
+
+private:
+  Options m_options;
+
+public:
+  Options create_like_options() const
+  {
+    return (DDL_options_st::Options)
+           (((uint) m_options) & (OPT_IF_NOT_EXISTS | OPT_OR_REPLACE));
+  }
+  void init() { m_options= OPT_NONE; }
+  void init(Options options) { m_options= options; }
+  void set(Options other)
+  {
+    m_options= other;
+  }
+  void set(const DDL_options_st other)
+  {
+    m_options= other.m_options;
+  }
+  bool if_not_exists() const { return m_options & OPT_IF_NOT_EXISTS; }
+  bool or_replace() const { return m_options & OPT_OR_REPLACE; }
+  bool or_replace_slave_generated() const
+  { return m_options & OPT_OR_REPLACE_SLAVE_GENERATED; }
+  bool like() const { return m_options & OPT_LIKE; }
+  bool if_exists() const { return m_options & OPT_IF_EXISTS; }
+  void add(const DDL_options_st::Options other)
+  {
+    m_options= (Options) ((uint) m_options | (uint) other);
+  }
+  void add(const DDL_options_st &other)
+  {
+    add(other.m_options);
+  }
+  DDL_options_st operator|(const DDL_options_st &other)
+  {
+    add(other.m_options);
+    return *this;
+  }
+  DDL_options_st operator|=(DDL_options_st::Options other)
+  {
+    add(other);
+    return *this;
+  }
+};
+
+
+class DDL_options: public DDL_options_st
+{
+public:
+  DDL_options() { init(); }
+};
+
+
 #endif /* STRUCTS_INCLUDED */
diff --git a/sql/table.cc b/sql/table.cc
index 6ac4544..5ed2b3c 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2061,7 +2061,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
   if (lex->sql_command != SQLCOM_CREATE_TABLE)
     return 1;
   // ... create like
-  if (create_info->options & HA_LEX_CREATE_TABLE_LIKE)
+  if (lex->create_info.like())
     return 1;
   // ... create select
   if (lex->select_lex.item_list.elements)
@@ -2070,7 +2070,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
   if (create_info->tmp_table())
     return 1;
   // ... if exists
-  if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+  if (lex->create_info.if_not_exists())
     return 1;
 
   // XXX error out or rather ignore the following:
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index fed3519..c847649 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -2371,7 +2371,7 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
         break;
       }
   }
-  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+  if (create_info->tmp_table())
   {
 
     /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */

Follow ups

References