mysql5/mysql-5.7.27/sql/sql_insert.h

315 lines
10 KiB
C++

/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef SQL_INSERT_INCLUDED
#define SQL_INSERT_INCLUDED
#include "sql_class.h" // Query_result_interceptor
#include "sql_cmd_dml.h" // Sql_cmd_dml
#include "sql_data_change.h" // enum_duplicates
struct TABLE_LIST;
typedef List<Item> List_item;
int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
TABLE_LIST *table_list);
void prepare_triggers_for_insert_stmt(TABLE *table);
int write_record(THD *thd, TABLE *table,
COPY_INFO *info, COPY_INFO *update);
bool validate_default_values_of_unset_fields(THD *thd, TABLE *table);
bool mysql_insert_select_prepare(THD *thd);
class Query_result_insert :public Query_result_interceptor
{
public:
TABLE_LIST *table_list;
TABLE *table;
private:
/**
The columns of the table to be inserted into, *or* the columns of the
table from which values are selected. For legacy reasons both are
allowed.
*/
List<Item> *fields;
protected:
/// ha_start_bulk_insert has been called. Never cleared.
bool bulk_insert_started;
public:
ulonglong autoinc_value_of_last_inserted_row; // autogenerated or not
COPY_INFO info;
COPY_INFO update; ///< the UPDATE part of "info"
bool insert_into_view;
/**
Creates a Query_result_insert for routing a result set to an existing
table.
@param table_list_par The table reference for the destination table.
@param table_par The destination table. May be NULL.
@param target_columns See details.
@param target_or_source_columns See details.
@param update_fields The columns to be updated in case of duplicate
keys. May be NULL.
@param update_values The values to be assigned in case of duplicate
keys. May be NULL.
@param duplicate The policy for handling duplicates.
@todo This constructor takes 8 arguments, 6 of which are used to
immediately construct a COPY_INFO object. Obviously the constructor
should take the COPY_INFO object as argument instead. Also, some
Query_result_insert members initialized here are totally redundant, as they are
found inside the COPY_INFO.
The target_columns and target_or_source_columns arguments are set by
callers as follows:
@li if CREATE SELECT:
- target_columns == NULL,
- target_or_source_columns == expressions listed after SELECT, as in
CREATE ... SELECT expressions
@li if INSERT SELECT:
target_columns
== target_or_source_columns
== columns listed between INSERT and SELECT, as in
INSERT INTO t (columns) SELECT ...
We set the manage_defaults argument of info's constructor as follows
([...] denotes something optional):
@li If target_columns==NULL, the statement is
@verbatim
CREATE TABLE a_table [(columns1)] SELECT expressions2
@endverbatim
so 'info' must manage defaults of columns1.
@li Otherwise it is:
@verbatim
INSERT INTO a_table [(columns1)] SELECT ...
@verbatim
target_columns is columns1, if not empty then 'info' must manage defaults
of other columns than columns1.
*/
Query_result_insert(TABLE_LIST *table_list_par,
TABLE *table_par,
List<Item> *target_columns,
List<Item> *target_or_source_columns,
List<Item> *update_fields,
List<Item> *update_values,
enum_duplicates duplic)
:table_list(table_list_par),
table(table_par),
fields(target_or_source_columns),
bulk_insert_started(false),
autoinc_value_of_last_inserted_row(0),
info(COPY_INFO::INSERT_OPERATION,
target_columns,
// manage_defaults
(target_columns == NULL || target_columns->elements != 0),
duplic),
update(COPY_INFO::UPDATE_OPERATION,
update_fields,
update_values),
insert_into_view(table_list_par && table_list_par->is_view())
{
DBUG_ASSERT(target_or_source_columns != NULL);
DBUG_ASSERT(target_columns == target_or_source_columns ||
target_columns == NULL);
}
public:
~Query_result_insert();
virtual bool need_explain_interceptor() const { return true; }
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
virtual int prepare2(void);
bool send_data(List<Item> &items);
virtual void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
bool send_eof();
virtual void abort_result_set();
/* not implemented: Query_result_insert is never re-used in prepared statements */
void cleanup();
};
/**
@todo This class inherits a class which is non-abstract. This is not in
line with good programming practices and the inheritance should be broken
up.
*/
class Query_result_create: public Query_result_insert {
TABLE_LIST *create_table;
HA_CREATE_INFO *create_info;
TABLE_LIST *select_tables;
Alter_info *alter_info;
Field **field;
/* lock data for tmp table */
MYSQL_LOCK *m_lock;
/* m_lock or thd->extra_lock */
MYSQL_LOCK **m_plock;
public:
Query_result_create(TABLE_LIST *table_arg,
HA_CREATE_INFO *create_info_par,
Alter_info *alter_info_arg,
List<Item> &select_fields,
enum_duplicates duplic,
TABLE_LIST *select_tables_arg)
:Query_result_insert (NULL, // table_list_par
NULL, // table_par
NULL, // target_columns
&select_fields,
NULL, // update_fields
NULL, // update_values
duplic),
create_table(table_arg),
create_info(create_info_par),
select_tables(select_tables_arg),
alter_info(alter_info_arg),
m_plock(NULL)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
int binlog_show_create_table(TABLE **tables, uint count);
void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
bool send_eof();
virtual void abort_result_set();
// Needed for access from local class MY_HOOKS in prepare(), since thd is proteted.
const THD *get_thd(void) { return thd; }
const HA_CREATE_INFO *get_create_info() { return create_info; };
int prepare2(void);
};
class Sql_cmd_insert_base : public Sql_cmd_dml
{
/*
field_list was created for view and should be removed before PS/SP
rexecuton
*/
bool empty_field_list_on_rset;
protected:
const bool is_replace;
public:
/**
Field list to insert/replace
One of two things:
1. For the INSERT/REPLACE ... (col1, ... colN) VALUES ... syntax
this is a list of col1, ..., colN fields.
2. For the INSERT/REPLACE ... SET col1=x1, ... colM=xM syntax extension
this is a list of col1, ... colM fields as well.
*/
List<Item> insert_field_list;
/**
ON DUPLICATE KEY UPDATE data value list
*/
List<Item> insert_value_list;
/**
ON DUPLICATE KEY UPDATE field list
*/
List<Item> insert_update_list;
/**
Row data to insert/replace
One of two things:
1. For the INSERT/REPLACE ... VALUES (row1), (row2), ... (rowN) syntax
the list contains N List_item lists: one List_item per row.
2. For the INSERT/REPLACE ... SET col1=x1, ... colM=xM syntax extension
this list contains only 1 List_item of M data values: this way we
emulate this syntax:
INSERT/REPLACE ... (col1, ... colM) VALUE (x1, ..., xM);
*/
List<List_item> insert_many_values; // TODO: move to Sql_cmd_insert
const enum_duplicates duplicates;
explicit
Sql_cmd_insert_base(bool is_replace_arg, enum_duplicates duplicates_arg)
: empty_field_list_on_rset(false),
is_replace(is_replace_arg),
duplicates(duplicates_arg)
{}
virtual void cleanup(THD *thd)
{
if (empty_field_list_on_rset)
{
empty_field_list_on_rset= false;
insert_field_list.empty();
}
}
protected:
bool mysql_prepare_insert(THD *thd,
TABLE_LIST *table_list,
List_item *values,
bool select_insert);
bool insert_precheck(THD *thd, TABLE_LIST *tables);
bool mysql_prepare_insert_check_table(THD *thd,
TABLE_LIST *table_list,
List<Item> &fields,
bool select_insert);
};
class Sql_cmd_insert : public Sql_cmd_insert_base
{
public:
explicit
Sql_cmd_insert(bool is_replace_arg, enum_duplicates duplicates_arg)
: Sql_cmd_insert_base(is_replace_arg, duplicates_arg)
{}
virtual enum_sql_command sql_command_code() const
{
return is_replace ? SQLCOM_REPLACE : SQLCOM_INSERT;
}
virtual bool execute(THD *thd);
virtual bool prepared_statement_test(THD *thd);
virtual bool prepare(THD *thd) { return false; }
private:
bool mysql_insert(THD *thd,TABLE_LIST *table);
bool mysql_test_insert(THD *thd, TABLE_LIST *table_list);
};
class Sql_cmd_insert_select : public Sql_cmd_insert_base
{
public:
explicit
Sql_cmd_insert_select(bool is_replace_arg, enum_duplicates duplicates_arg)
: Sql_cmd_insert_base(is_replace_arg, duplicates_arg)
{}
virtual enum_sql_command sql_command_code() const
{
return is_replace ? SQLCOM_REPLACE_SELECT : SQLCOM_INSERT_SELECT;
}
virtual bool execute(THD *thd);
virtual bool prepared_statement_test(THD *thd);
virtual bool prepare(THD *thd);
protected:
bool mysql_insert_select_prepare(THD *thd);
};
#endif /* SQL_INSERT_INCLUDED */