· 6 years ago · Jun 11, 2019, 09:24 AM
1diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
2index e37d5471f41..12e3575f742 100644
3--- a/sql/sql_alter.cc
4+++ b/sql/sql_alter.cc
5@@ -193,6 +193,20 @@ bool Sql_cmd_alter_table::execute(THD *thd)
6 SELECT_LEX *select_lex= &lex->select_lex;
7 /* first table of first SELECT_LEX */
8 TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
9+
10+ bool used_engine= lex->create_info.used_fields & HA_CREATE_USED_ENGINE;
11+ DBUG_ASSERT(m_storage_engine_name.length || !used_engine);
12+ if (used_engine &&
13+ thd->resolve_storage_engine(&lex->create_info.db_type,
14+ m_storage_engine_name,
15+ lex->create_info.tmp_table()))
16+ return true;
17+
18+ if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
19+ !lex->create_info.db_type)
20+ lex->create_info.used_fields&= ~HA_CREATE_USED_ENGINE;
21+
22+
23 /*
24 Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
25 so we have to use a copy of this structure to make execution
26@@ -210,6 +224,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
27
28 if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
29 DBUG_RETURN(TRUE);
30+
31 /*
32 We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
33 as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
34diff --git a/sql/sql_alter.h b/sql/sql_alter.h
35index a503837bfee..66c20fcb1a8 100644
36--- a/sql/sql_alter.h
37+++ b/sql/sql_alter.h
38@@ -385,7 +385,8 @@ class Sql_cmd_common_alter_table : public Sql_cmd
39 Sql_cmd_alter_table represents the generic ALTER TABLE statement.
40 @todo move Alter_info and other ALTER specific structures from Lex here.
41 */
42-class Sql_cmd_alter_table : public Sql_cmd_common_alter_table
43+class Sql_cmd_alter_table : public Sql_cmd_common_alter_table,
44+ public Sql_cmd_options_table_dml
45 {
46 public:
47 /**
48@@ -397,6 +398,8 @@ class Sql_cmd_alter_table : public Sql_cmd_common_alter_table
49 ~Sql_cmd_alter_table()
50 {}
51
52+ Sql_cmd_options_table_dml *options_table_dml() { return this; }
53+
54 bool execute(THD *thd);
55 };
56
57@@ -423,4 +426,27 @@ class Sql_cmd_discard_import_tablespace : public Sql_cmd_common_alter_table
58 const enum_tablespace_op_type m_tablespace_op;
59 };
60
61+
62+class Sql_cmd_create_table: public Sql_cmd,
63+ public Sql_cmd_options_table_dml
64+{
65+public:
66+ Sql_cmd_create_table()
67+ {}
68+
69+ ~Sql_cmd_create_table()
70+ { }
71+
72+ enum_sql_command sql_command_code() const
73+ {
74+ return SQLCOM_ALTER_TABLE;
75+ }
76+
77+ Sql_cmd_options_table_dml *options_table_dml() { return this; }
78+
79+ bool execute(THD *thd);
80+
81+};
82+
83+
84 #endif
85diff --git a/sql/sql_class.cc b/sql/sql_class.cc
86index 8fabcd52913..6df87184893 100644
87--- a/sql/sql_class.cc
88+++ b/sql/sql_class.cc
89@@ -6151,6 +6151,32 @@ int THD::decide_logging_format(TABLE_LIST *tables)
90
91 #ifndef MYSQL_CLIENT
92
93+bool THD::resolve_storage_engine(handlerton **ha, const LEX_CSTRING &name,
94+ bool tmp_table)
95+{
96+ LEX_STRING tmp_name= {(char*) name.str, name.length};
97+ plugin_ref plugin= ha_resolve_by_name(this, &tmp_name, tmp_table);
98+
99+ if (plugin)
100+ {
101+ *ha= plugin_hton(plugin);
102+ return false;
103+ }
104+
105+ *ha= NULL;
106+ if (variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
107+ {
108+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str);
109+ return true;
110+ }
111+ push_warning_printf(this, Sql_condition::WARN_LEVEL_WARN,
112+ ER_UNKNOWN_STORAGE_ENGINE,
113+ ER_THD(this, ER_UNKNOWN_STORAGE_ENGINE),
114+ name.str);
115+ return false;
116+}
117+
118+
119 /*
120 Template member function for ensuring that there is an rows log
121 event of the apropriate type before proceeding.
122@@ -7384,4 +7410,5 @@ bool Discrete_intervals_list::append(Discrete_interval *new_interval)
123 DBUG_RETURN(0);
124 }
125
126+
127 #endif /* !defined(MYSQL_CLIENT) */
128diff --git a/sql/sql_class.h b/sql/sql_class.h
129index 1cb516c0656..c7e9e0e9729 100644
130--- a/sql/sql_class.h
131+++ b/sql/sql_class.h
132@@ -2209,6 +2209,9 @@ class THD :public Statement,
133 Ha_data ha_data[MAX_HA];
134
135 #ifndef MYSQL_CLIENT
136+ bool resolve_storage_engine(handlerton **ha, const LEX_CSTRING &name,
137+ bool tmp_table);
138+
139 binlog_cache_mngr * binlog_setup_trx_data();
140
141 /*
142diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h
143index 9583e015499..3f6aa4def68 100644
144--- a/sql/sql_cmd.h
145+++ b/sql/sql_cmd.h
146@@ -102,6 +102,23 @@ enum enum_sql_command {
147 SQLCOM_END
148 };
149
150+
151+// We should eventually move LEX::create_info here
152+class Sql_cmd_options_table_dml
153+{
154+protected:
155+ LEX_CSTRING m_storage_engine_name;
156+public:
157+ Sql_cmd_options_table_dml()
158+ :m_storage_engine_name({0,0})
159+ { }
160+ void set_storage_engine_name(const LEX_CSTRING &name)
161+ {
162+ m_storage_engine_name= name;
163+ }
164+};
165+
166+
167 /**
168 @class Sql_cmd - Representation of an SQL command.
169
170@@ -145,6 +162,8 @@ class Sql_cmd : public Sql_alloc
171 */
172 virtual bool execute(THD *thd) = 0;
173
174+ virtual Sql_cmd_options_table_dml *options_table_dml() { return NULL; }
175+
176 protected:
177 Sql_cmd()
178 {}
179diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
180index 9cb65e82321..c8b9219c280 100644
181--- a/sql/sql_parse.cc
182+++ b/sql/sql_parse.cc
183@@ -3280,274 +3280,6 @@ mysql_execute_command(THD *thd)
184 res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
185 break;
186 }
187- case SQLCOM_CREATE_TABLE:
188- {
189- DBUG_ASSERT(first_table == all_tables && first_table != 0);
190- bool link_to_local;
191- TABLE_LIST *create_table= first_table;
192- TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
193-
194- if (lex->tmp_table())
195- {
196- status_var_decrement(thd->status_var.com_stat[SQLCOM_CREATE_TABLE]);
197- status_var_increment(thd->status_var.com_create_tmp_table);
198- }
199-
200- /*
201- Code below (especially in mysql_create_table() and select_create
202- methods) may modify HA_CREATE_INFO structure in LEX, so we have to
203- use a copy of this structure to make execution prepared statement-
204- safe. A shallow copy is enough as this code won't modify any memory
205- referenced from this structure.
206- */
207- Table_specification_st create_info(lex->create_info);
208- /*
209- We need to copy alter_info for the same reasons of re-execution
210- safety, only in case of Alter_info we have to do (almost) a deep
211- copy.
212- */
213- Alter_info alter_info(lex->alter_info, thd->mem_root);
214-
215- if (thd->is_fatal_error)
216- {
217- /* If out of memory when creating a copy of alter_info. */
218- res= 1;
219- goto end_with_restore_list;
220- }
221-
222- /* Check privileges */
223- if ((res= create_table_precheck(thd, select_tables, create_table)))
224- goto end_with_restore_list;
225-
226- /* Might have been updated in create_table_precheck */
227- create_info.alias= create_table->alias;
228-
229- /* Fix names if symlinked or relocated tables */
230- if (append_file_to_dir(thd, &create_info.data_file_name,
231- create_table->table_name) ||
232- append_file_to_dir(thd, &create_info.index_file_name,
233- create_table->table_name))
234- goto end_with_restore_list;
235-
236- /*
237- If no engine type was given, work out the default now
238- rather than at parse-time.
239- */
240- if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
241- create_info.use_default_db_type(thd);
242- /*
243- If we are using SET CHARSET without DEFAULT, add an implicit
244- DEFAULT to not confuse old users. (This may change).
245- */
246- if ((create_info.used_fields &
247- (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
248- HA_CREATE_USED_CHARSET)
249- {
250- create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
251- create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
252- create_info.default_table_charset= create_info.table_charset;
253- create_info.table_charset= 0;
254- }
255-
256- /*
257- If we are a slave, we should add OR REPLACE if we don't have
258- IF EXISTS. This will help a slave to recover from
259- CREATE TABLE OR EXISTS failures by dropping the table and
260- retrying the create.
261- */
262- if (thd->slave_thread &&
263- slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT &&
264- !lex->create_info.if_not_exists())
265- {
266- create_info.add(DDL_options_st::OPT_OR_REPLACE);
267- create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);
268- }
269-
270-#ifdef WITH_PARTITION_STORAGE_ENGINE
271- {
272- partition_info *part_info= thd->lex->part_info;
273- if (part_info && !(part_info= part_info->get_clone(thd)))
274- {
275- res= -1;
276- goto end_with_restore_list;
277- }
278- thd->work_part_info= part_info;
279- }
280-#endif
281-
282- if (select_lex->item_list.elements) // With select
283- {
284- select_result *result;
285-
286- /*
287- CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless
288- ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore
289- use row based logging if mixed or row based logging is available.
290- TODO: Check if the order of the output of the select statement is
291- deterministic. Waiting for BUG#42415
292- */
293- if(lex->ignore)
294- lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT);
295-
296- if(lex->duplicates == DUP_REPLACE)
297- lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT);
298-
299- /*
300- If:
301- a) we inside an SP and there was NAME_CONST substitution,
302- b) binlogging is on (STMT mode),
303- c) we log the SP as separate statements
304- raise a warning, as it may cause problems
305- (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs')
306- */
307- if (thd->query_name_consts && mysql_bin_log.is_open() &&
308- thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
309- !mysql_bin_log.is_query_in_union(thd, thd->query_id))
310- {
311- List_iterator_fast<Item> it(select_lex->item_list);
312- Item *item;
313- uint splocal_refs= 0;
314- /* Count SP local vars in the top-level SELECT list */
315- while ((item= it++))
316- {
317- if (item->get_item_splocal())
318- splocal_refs++;
319- }
320- /*
321- If it differs from number of NAME_CONST substitution applied,
322- we may have a SOME_FUNC(NAME_CONST()) in the SELECT list,
323- that may cause a problem with binary log (see BUG#35383),
324- raise a warning.
325- */
326- if (splocal_refs != thd->query_name_consts)
327- push_warning(thd,
328- Sql_condition::WARN_LEVEL_WARN,
329- ER_UNKNOWN_ERROR,
330-"Invoked routine ran a statement that may cause problems with "
331-"binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' "
332-"section of the manual.");
333- }
334-
335- select_lex->options|= SELECT_NO_UNLOCK;
336- unit->set_limit(select_lex);
337-
338- /*
339- Disable non-empty MERGE tables with CREATE...SELECT. Too
340- complicated. See Bug #26379. Empty MERGE tables are read-only
341- and don't allow CREATE...SELECT anyway.
342- */
343- if (create_info.used_fields & HA_CREATE_USED_UNION)
344- {
345- my_error(ER_WRONG_OBJECT, MYF(0), create_table->db,
346- create_table->table_name, "BASE TABLE");
347- res= 1;
348- goto end_with_restore_list;
349- }
350-
351- /* Copy temporarily the statement flags to thd for lock_table_names() */
352- uint save_thd_create_info_options= thd->lex->create_info.options;
353- thd->lex->create_info.options|= create_info.options;
354- res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
355- thd->lex->create_info.options= save_thd_create_info_options;
356- if (res)
357- {
358- /* Got error or warning. Set res to 1 if error */
359- if (!(res= thd->is_error()))
360- my_ok(thd); // CREATE ... IF NOT EXISTS
361- goto end_with_restore_list;
362- }
363-
364- /* Ensure we don't try to create something from which we select from */
365- if (create_info.or_replace() && !create_info.tmp_table())
366- {
367- TABLE_LIST *duplicate;
368- if ((duplicate= unique_table(thd, lex->query_tables,
369- lex->query_tables->next_global,
370- CHECK_DUP_FOR_CREATE)))
371- {
372- update_non_unique_table_error(lex->query_tables, "CREATE",
373- duplicate);
374- res= TRUE;
375- goto end_with_restore_list;
376- }
377- }
378- {
379- /*
380- Remove target table from main select and name resolution
381- context. This can't be done earlier as it will break view merging in
382- statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT".
383- */
384- lex->unlink_first_table(&link_to_local);
385-
386- /* Store reference to table in case of LOCK TABLES */
387- create_info.table= create_table->table;
388-
389- /*
390- select_create is currently not re-execution friendly and
391- needs to be created for every execution of a PS/SP.
392- Note: In wsrep-patch, CTAS is handled like a regular transaction.
393- */
394- if ((result= new (thd->mem_root) select_create(thd, create_table,
395- &create_info,
396- &alter_info,
397- select_lex->item_list,
398- lex->duplicates,
399- lex->ignore,
400- select_tables)))
401- {
402- /*
403- CREATE from SELECT give its SELECT_LEX for SELECT,
404- and item_list belong to SELECT
405- */
406- if (!(res= handle_select(thd, lex, result, 0)))
407- {
408- if (create_info.tmp_table())
409- thd->variables.option_bits|= OPTION_KEEP_LOG;
410- }
411- delete result;
412- }
413- lex->link_first_table_back(create_table, link_to_local);
414- }
415- }
416- else
417- {
418- /* regular create */
419- if (create_info.like())
420- {
421- /* CREATE TABLE ... LIKE ... */
422- res= mysql_create_like_table(thd, create_table, select_tables,
423- &create_info);
424- }
425- else
426- {
427- /*
428- In STATEMENT format, we probably have to replicate also temporary
429- tables, like mysql replication does. Also check if the requested
430- engine is allowed/supported.
431- */
432- if (WSREP(thd) &&
433- !check_engine(thd, create_table->db, create_table->table_name,
434- &create_info) &&
435- (!thd->is_current_stmt_binlog_format_row() ||
436- !create_info.tmp_table()))
437- {
438- WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL)
439- }
440- /* Regular CREATE TABLE */
441- res= mysql_create_table(thd, create_table, &create_info, &alter_info);
442- }
443- if (!res)
444- {
445- /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
446- if (create_info.tmp_table())
447- thd->variables.option_bits|= OPTION_KEEP_LOG;
448- my_ok(thd);
449- }
450- }
451-
452-end_with_restore_list:
453- break;
454- }
455 case SQLCOM_CREATE_INDEX:
456 case SQLCOM_DROP_INDEX:
457 /*
458@@ -5699,6 +5431,7 @@ mysql_execute_command(THD *thd)
459 case SQLCOM_OPTIMIZE:
460 case SQLCOM_REPAIR:
461 case SQLCOM_TRUNCATE:
462+ case SQLCOM_CREATE_TABLE:
463 case SQLCOM_ALTER_TABLE:
464 DBUG_ASSERT(first_table == all_tables && first_table != 0);
465 /* fall through */
466diff --git a/sql/sql_table.cc b/sql/sql_table.cc
467index ca78c011866..c4c3ef840b1 100644
468--- a/sql/sql_table.cc
469+++ b/sql/sql_table.cc
470@@ -10116,3 +10116,304 @@ bool check_engine(THD *thd, const char *db_name,
471
472 DBUG_RETURN(false);
473 }
474+
475+
476+bool Sql_cmd_create_table::execute(THD *thd)
477+{
478+ DBUG_ENTER("Sql_cmd_create_table::execute");
479+ LEX *lex= thd->lex;
480+ TABLE_LIST *all_tables= lex->query_tables;
481+ SELECT_LEX *select_lex= &lex->select_lex;
482+ TABLE_LIST *first_table= select_lex->table_list.first;
483+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
484+ bool link_to_local;
485+ TABLE_LIST *create_table= first_table;
486+ TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
487+ /* most outer SELECT_LEX_UNIT of query */
488+ SELECT_LEX_UNIT *unit= &lex->unit;
489+ int res= 0;
490+
491+ bool used_engine= lex->create_info.used_fields & HA_CREATE_USED_ENGINE;
492+ DBUG_ASSERT(m_storage_engine_name.length || !used_engine);
493+ if (used_engine)
494+ {
495+ if (thd->resolve_storage_engine(&lex->create_info.db_type,
496+ m_storage_engine_name,
497+ lex->create_info.tmp_table()))
498+ DBUG_RETURN(true); // Engine not found, substitution is not allowed
499+
500+ if (!lex->create_info.db_type)
501+ {
502+ lex->create_info.use_default_db_type(thd);
503+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
504+ ER_WARN_USING_OTHER_HANDLER,
505+ ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
506+ hton_name(lex->create_info.db_type)->str,
507+ create_table->table_name);
508+ }
509+ }
510+
511+ if (lex->tmp_table())
512+ {
513+ status_var_decrement(thd->status_var.com_stat[SQLCOM_CREATE_TABLE]);
514+ status_var_increment(thd->status_var.com_create_tmp_table);
515+ }
516+
517+ /*
518+ Code below (especially in mysql_create_table() and select_create
519+ methods) may modify HA_CREATE_INFO structure in LEX, so we have to
520+ use a copy of this structure to make execution prepared statement-
521+ safe. A shallow copy is enough as this code won't modify any memory
522+ referenced from this structure.
523+ */
524+ Table_specification_st create_info(lex->create_info);
525+ /*
526+ We need to copy alter_info for the same reasons of re-execution
527+ safety, only in case of Alter_info we have to do (almost) a deep
528+ copy.
529+ */
530+ Alter_info alter_info(lex->alter_info, thd->mem_root);
531+
532+ if (thd->is_fatal_error)
533+ {
534+ /* If out of memory when creating a copy of alter_info. */
535+ res= 1;
536+ goto end_with_restore_list;
537+ }
538+
539+ /* Check privileges */
540+ if ((res= create_table_precheck(thd, select_tables, create_table)))
541+ goto end_with_restore_list;
542+
543+ /* Might have been updated in create_table_precheck */
544+ create_info.alias= create_table->alias;
545+
546+ /* Fix names if symlinked or relocated tables */
547+ if (append_file_to_dir(thd, &create_info.data_file_name,
548+ create_table->table_name) ||
549+ append_file_to_dir(thd, &create_info.index_file_name,
550+ create_table->table_name))
551+ goto end_with_restore_list;
552+
553+ /*
554+ If no engine type was given, work out the default now
555+ rather than at parse-time.
556+ */
557+ if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
558+ create_info.use_default_db_type(thd);
559+ /*
560+ If we are using SET CHARSET without DEFAULT, add an implicit
561+ DEFAULT to not confuse old users. (This may change).
562+ */
563+ if ((create_info.used_fields &
564+ (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
565+ HA_CREATE_USED_CHARSET)
566+ {
567+ create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
568+ create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
569+ create_info.default_table_charset= create_info.table_charset;
570+ create_info.table_charset= 0;
571+ }
572+
573+ /*
574+ If we are a slave, we should add OR REPLACE if we don't have
575+ IF EXISTS. This will help a slave to recover from
576+ CREATE TABLE OR EXISTS failures by dropping the table and
577+ retrying the create.
578+ */
579+ if (thd->slave_thread &&
580+ slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT &&
581+ !lex->create_info.if_not_exists())
582+ {
583+ create_info.add(DDL_options_st::OPT_OR_REPLACE);
584+ create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);
585+ }
586+
587+#ifdef WITH_PARTITION_STORAGE_ENGINE
588+ {
589+ partition_info *part_info= thd->lex->part_info;
590+ if (part_info && !(part_info= part_info->get_clone(thd)))
591+ {
592+ res= -1;
593+ goto end_with_restore_list;
594+ }
595+ thd->work_part_info= part_info;
596+ }
597+#endif
598+
599+ if (select_lex->item_list.elements) // With select
600+ {
601+ select_result *result;
602+
603+ /*
604+ CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless
605+ ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore
606+ use row based logging if mixed or row based logging is available.
607+ TODO: Check if the order of the output of the select statement is
608+ deterministic. Waiting for BUG#42415
609+ */
610+ if(lex->ignore)
611+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT);
612+
613+ if(lex->duplicates == DUP_REPLACE)
614+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT);
615+
616+ /*
617+ If:
618+ a) we inside an SP and there was NAME_CONST substitution,
619+ b) binlogging is on (STMT mode),
620+ c) we log the SP as separate statements
621+ raise a warning, as it may cause problems
622+ (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs')
623+ */
624+ if (thd->query_name_consts && mysql_bin_log.is_open() &&
625+ thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
626+ !mysql_bin_log.is_query_in_union(thd, thd->query_id))
627+ {
628+ List_iterator_fast<Item> it(select_lex->item_list);
629+ Item *item;
630+ uint splocal_refs= 0;
631+ /* Count SP local vars in the top-level SELECT list */
632+ while ((item= it++))
633+ {
634+ if (item->get_item_splocal())
635+ splocal_refs++;
636+ }
637+ /*
638+ If it differs from number of NAME_CONST substitution applied,
639+ we may have a SOME_FUNC(NAME_CONST()) in the SELECT list,
640+ that may cause a problem with binary log (see BUG#35383),
641+ raise a warning.
642+ */
643+ if (splocal_refs != thd->query_name_consts)
644+ push_warning(thd,
645+ Sql_condition::WARN_LEVEL_WARN,
646+ ER_UNKNOWN_ERROR,
647+"Invoked routine ran a statement that may cause problems with "
648+"binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' "
649+"section of the manual.");
650+ }
651+
652+ select_lex->options|= SELECT_NO_UNLOCK;
653+ unit->set_limit(select_lex);
654+
655+ /*
656+ Disable non-empty MERGE tables with CREATE...SELECT. Too
657+ complicated. See Bug #26379. Empty MERGE tables are read-only
658+ and don't allow CREATE...SELECT anyway.
659+ */
660+ if (create_info.used_fields & HA_CREATE_USED_UNION)
661+ {
662+ my_error(ER_WRONG_OBJECT, MYF(0), create_table->db,
663+ create_table->table_name, "BASE TABLE");
664+ res= 1;
665+ goto end_with_restore_list;
666+ }
667+
668+ /* Copy temporarily the statement flags to thd for lock_table_names() */
669+ uint save_thd_create_info_options= thd->lex->create_info.options;
670+ thd->lex->create_info.options|= create_info.options;
671+ res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
672+ thd->lex->create_info.options= save_thd_create_info_options;
673+ if (res)
674+ {
675+ /* Got error or warning. Set res to 1 if error */
676+ if (!(res= thd->is_error()))
677+ my_ok(thd); // CREATE ... IF NOT EXISTS
678+ goto end_with_restore_list;
679+ }
680+
681+ /* Ensure we don't try to create something from which we select from */
682+ if (create_info.or_replace() && !create_info.tmp_table())
683+ {
684+ TABLE_LIST *duplicate;
685+ if ((duplicate= unique_table(thd, lex->query_tables,
686+ lex->query_tables->next_global,
687+ CHECK_DUP_FOR_CREATE)))
688+ {
689+ update_non_unique_table_error(lex->query_tables, "CREATE",
690+ duplicate);
691+ res= TRUE;
692+ goto end_with_restore_list;
693+ }
694+ }
695+ {
696+ /*
697+ Remove target table from main select and name resolution
698+ context. This can't be done earlier as it will break view merging in
699+ statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT".
700+ */
701+ lex->unlink_first_table(&link_to_local);
702+
703+ /* Store reference to table in case of LOCK TABLES */
704+ create_info.table= create_table->table;
705+
706+ /*
707+ select_create is currently not re-execution friendly and
708+ needs to be created for every execution of a PS/SP.
709+ Note: In wsrep-patch, CTAS is handled like a regular transaction.
710+ */
711+ if ((result= new (thd->mem_root) select_create(thd, create_table,
712+ &create_info,
713+ &alter_info,
714+ select_lex->item_list,
715+ lex->duplicates,
716+ lex->ignore,
717+ select_tables)))
718+ {
719+ /*
720+ CREATE from SELECT give its SELECT_LEX for SELECT,
721+ and item_list belong to SELECT
722+ */
723+ if (!(res= handle_select(thd, lex, result, 0)))
724+ {
725+ if (create_info.tmp_table())
726+ thd->variables.option_bits|= OPTION_KEEP_LOG;
727+ }
728+ delete result;
729+ }
730+ lex->link_first_table_back(create_table, link_to_local);
731+ }
732+ }
733+ else
734+ {
735+ /* regular create */
736+ if (create_info.like())
737+ {
738+ /* CREATE TABLE ... LIKE ... */
739+ res= mysql_create_like_table(thd, create_table, select_tables,
740+ &create_info);
741+ }
742+ else
743+ {
744+ /*
745+ In STATEMENT format, we probably have to replicate also temporary
746+ tables, like mysql replication does. Also check if the requested
747+ engine is allowed/supported.
748+ */
749+ if (WSREP(thd) &&
750+ !check_engine(thd, create_table->db, create_table->table_name,
751+ &create_info) &&
752+ (!thd->is_current_stmt_binlog_format_row() ||
753+ !create_info.tmp_table()))
754+ {
755+ WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL)
756+ }
757+ /* Regular CREATE TABLE */
758+ res= mysql_create_table(thd, create_table, &create_info, &alter_info);
759+ }
760+ if (!res)
761+ {
762+ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
763+ if (create_info.tmp_table())
764+ thd->variables.option_bits|= OPTION_KEEP_LOG;
765+ my_ok(thd);
766+ }
767+ }
768+
769+end_with_restore_list:
770+ DBUG_RETURN(res);
771+
772+WSREP_ERROR_LABEL:
773+ DBUG_RETURN(true);
774+}
775diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
776index 59cc73d88af..7de5bef0642 100644
777--- a/sql/sql_yacc.yy
778+++ b/sql/sql_yacc.yy
779@@ -2454,6 +2454,8 @@ create:
780 create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident
781 {
782 LEX *lex= thd->lex;
783+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_table()))
784+ MYSQL_YYABORT;
785 lex->create_info.init();
786 if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
787 MYSQL_YYABORT;
788@@ -2475,16 +2477,6 @@ create:
789 {
790 LEX *lex= thd->lex;
791 lex->current_select= &lex->select_lex;
792- if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
793- !lex->create_info.db_type)
794- {
795- lex->create_info.use_default_db_type(thd);
796- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
797- ER_WARN_USING_OTHER_HANDLER,
798- ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
799- hton_name(lex->create_info.db_type)->str,
800- $5->table.str);
801- }
802 create_table_set_open_action_and_adjust_tables(lex);
803 }
804 | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident
805@@ -5515,10 +5507,19 @@ create_table_options:
806 ;
807
808 create_table_option:
809- ENGINE_SYM opt_equal storage_engines
810+ ENGINE_SYM opt_equal ident_or_text
811 {
812- Lex->create_info.db_type= $3;
813- Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
814+ LEX *lex= Lex;
815+ if (!lex->m_sql_cmd)
816+ {
817+ DBUG_ASSERT(lex->sql_command == SQLCOM_ALTER_TABLE);
818+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table()))
819+ MYSQL_YYABORT;
820+ }
821+ Sql_cmd_options_table_dml *opt= lex->m_sql_cmd->options_table_dml();
822+ DBUG_ASSERT(opt); // Expect a proper Sql_cmd
823+ opt->set_storage_engine_name({$3.str, $3.length});
824+ lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
825 }
826 | MAX_ROWS opt_equal ulonglong_num
827 {
828@@ -5783,21 +5784,10 @@ default_collation:
829 storage_engines:
830 ident_or_text
831 {
832- plugin_ref plugin= ha_resolve_by_name(thd, &$1,
833- thd->lex->create_info.tmp_table());
834-
835- if (plugin)
836- $$= plugin_hton(plugin);
837- else
838- {
839- if (thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
840- my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str));
841- $$= 0;
842- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
843- ER_UNKNOWN_STORAGE_ENGINE,
844- ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE),
845- $1.str);
846- }
847+ LEX_CSTRING tmp= {$1.str, $1.length};
848+ if (thd->resolve_storage_engine(&$$, tmp,
849+ thd->lex->create_info.tmp_table()))
850+ MYSQL_YYABORT;
851 }
852 ;
853
854@@ -7533,11 +7523,6 @@ alter_list_item:
855 {
856 LEX *lex=Lex;
857 lex->alter_info.flags|= Alter_info::ALTER_OPTIONS;
858- if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
859- !lex->create_info.db_type)
860- {
861- lex->create_info.used_fields&= ~HA_CREATE_USED_ENGINE;
862- }
863 }
864 | FORCE_SYM
865 {