sql_error.cc, sql_prepare.cc:
new file Client-server protocol 4.1 changes - Server side: * Enhanced metadata information: - SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows] - SHOW [COUNT(*)] WARNING [LIMIT [offset,] rows] - SHOW TABLE TYPES - SHOW PRIVILEGES - SHOW COLUMN TYPES (Not fully implemented) * Prepared execution * Long data handling in pieces * And other misc changes
This commit is contained in:
parent
049a8386f3
commit
6cdebb33d7
@ -67,6 +67,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
|||||||
mysqld.cc password.c hash_filo.cc hostname.cc \
|
mysqld.cc password.c hash_filo.cc hostname.cc \
|
||||||
convert.cc sql_parse.cc sql_yacc.yy \
|
convert.cc sql_parse.cc sql_yacc.yy \
|
||||||
sql_base.cc table.cc sql_select.cc sql_insert.cc \
|
sql_base.cc table.cc sql_select.cc sql_insert.cc \
|
||||||
|
sql_prepare.cc sql_error.cc \
|
||||||
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
|
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
|
||||||
procedure.cc item_uniq.cc sql_test.cc \
|
procedure.cc item_uniq.cc sql_test.cc \
|
||||||
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
|
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
|
||||||
|
@ -279,8 +279,10 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
|
|||||||
|
|
||||||
void Field_num::make_field(Send_field *field)
|
void Field_num::make_field(Send_field *field)
|
||||||
{
|
{
|
||||||
|
field->db_name=table->table_cache_key ? table->table_cache_key : "";
|
||||||
|
field->org_table_name=table->real_name;
|
||||||
field->table_name=table_name;
|
field->table_name=table_name;
|
||||||
field->col_name=field_name;
|
field->col_name=field->org_col_name=field_name;
|
||||||
field->length=field_length;
|
field->length=field_length;
|
||||||
field->type=type();
|
field->type=type();
|
||||||
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
|
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
|
||||||
@ -290,8 +292,10 @@ void Field_num::make_field(Send_field *field)
|
|||||||
|
|
||||||
void Field_str::make_field(Send_field *field)
|
void Field_str::make_field(Send_field *field)
|
||||||
{
|
{
|
||||||
|
field->db_name=table->table_cache_key ? table->table_cache_key : "";
|
||||||
|
field->org_table_name=table->real_name;
|
||||||
field->table_name=table_name;
|
field->table_name=table_name;
|
||||||
field->col_name=field_name;
|
field->col_name=field->org_col_name=field_name;
|
||||||
field->length=field_length;
|
field->length=field_length;
|
||||||
field->type=type();
|
field->type=type();
|
||||||
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
|
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
|
||||||
|
@ -1038,7 +1038,9 @@ public:
|
|||||||
|
|
||||||
class Send_field {
|
class Send_field {
|
||||||
public:
|
public:
|
||||||
const char *table_name,*col_name;
|
const char *db_name;
|
||||||
|
const char *table_name,*org_table_name;
|
||||||
|
const char *col_name,*org_col_name;
|
||||||
uint length,flags,decimals;
|
uint length,flags,decimals;
|
||||||
enum_field_types type;
|
enum_field_types type;
|
||||||
Send_field() {}
|
Send_field() {}
|
||||||
|
137
sql/item.cc
137
sql/item.cc
@ -287,6 +287,140 @@ String *Item_null::val_str(String *str)
|
|||||||
{ null_value=1; return 0;}
|
{ null_value=1; return 0;}
|
||||||
|
|
||||||
|
|
||||||
|
/* Item_param related */
|
||||||
|
void Item_param::set_null()
|
||||||
|
{
|
||||||
|
maybe_null=null_value=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_param::set_int(longlong i)
|
||||||
|
{
|
||||||
|
int_value=(longlong)i;
|
||||||
|
item_result_type = INT_RESULT;
|
||||||
|
item_type = INT_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_param::set_double(double i)
|
||||||
|
{
|
||||||
|
double value = (double)i;
|
||||||
|
real_value=value;
|
||||||
|
item_result_type = REAL_RESULT;
|
||||||
|
item_type = REAL_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_param::set_double(float i)
|
||||||
|
{
|
||||||
|
float value = (float)i;
|
||||||
|
real_value=(double)value;
|
||||||
|
item_result_type = REAL_RESULT;
|
||||||
|
item_type = REAL_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_param::set_value(const char *str, uint length)
|
||||||
|
{
|
||||||
|
str_value.set(str,length,default_charset_info);
|
||||||
|
item_result_type = STRING_RESULT;
|
||||||
|
item_type = STRING_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_param::set_longdata(const char *str, ulong length)
|
||||||
|
{
|
||||||
|
/* TODO: Fix this for binary handling by making use of
|
||||||
|
buffer_type..
|
||||||
|
*/
|
||||||
|
str_value.append(str,length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_param::set_long_end()
|
||||||
|
{
|
||||||
|
long_data_supplied = true;
|
||||||
|
item_result_type = STRING_RESULT;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Item_param::save_in_field(Field *field)
|
||||||
|
{
|
||||||
|
if (null_value)
|
||||||
|
return set_field_to_null(field);
|
||||||
|
|
||||||
|
field->set_notnull();
|
||||||
|
if (item_result_type == INT_RESULT)
|
||||||
|
{
|
||||||
|
longlong nr=val_int();
|
||||||
|
field->store(nr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (item_result_type == REAL_RESULT)
|
||||||
|
{
|
||||||
|
double nr=val();
|
||||||
|
field->store(nr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
String *result;
|
||||||
|
CHARSET_INFO *cs=default_charset_info;//fix this
|
||||||
|
result=val_str(&str_value);
|
||||||
|
field->store(result->ptr(),result->length(),cs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_param::make_field(Send_field *tmp_field)
|
||||||
|
{
|
||||||
|
init_make_field(tmp_field,FIELD_TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Item_param::val()
|
||||||
|
{
|
||||||
|
/* Cross check whether we need need this conversions ? or direct
|
||||||
|
return(real_value) is enough ?
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch(item_result_type) {
|
||||||
|
|
||||||
|
case STRING_RESULT:
|
||||||
|
return (double)atof(str_value.ptr());
|
||||||
|
case INT_RESULT:
|
||||||
|
return (double)int_value;
|
||||||
|
default:
|
||||||
|
return real_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Item_param::val_int()
|
||||||
|
{
|
||||||
|
/* Cross check whether we need need this conversions ? or direct
|
||||||
|
return(int_value) is enough ?
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch(item_result_type) {
|
||||||
|
|
||||||
|
case STRING_RESULT:
|
||||||
|
return (longlong)strtoll(str_value.ptr(),(char**) 0,10);
|
||||||
|
case REAL_RESULT:
|
||||||
|
return (longlong) (real_value+(real_value > 0 ? 0.5 : -0.5));
|
||||||
|
default:
|
||||||
|
return int_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String *Item_param::val_str(String* str)
|
||||||
|
{
|
||||||
|
/* Cross check whether we need need this conversions ? or direct
|
||||||
|
return(&str_value) is enough ?
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch(item_result_type) {
|
||||||
|
|
||||||
|
case INT_RESULT:
|
||||||
|
str->set(int_value);
|
||||||
|
return str;
|
||||||
|
case REAL_RESULT:
|
||||||
|
str->set(real_value);
|
||||||
|
return str;
|
||||||
|
default:
|
||||||
|
return (String*) &str_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* End of Item_param related */
|
||||||
|
|
||||||
void Item_copy_string::copy()
|
void Item_copy_string::copy()
|
||||||
{
|
{
|
||||||
String *res=item->val_str(&str_value);
|
String *res=item->val_str(&str_value);
|
||||||
@ -374,6 +508,9 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
|
|||||||
void Item::init_make_field(Send_field *tmp_field,
|
void Item::init_make_field(Send_field *tmp_field,
|
||||||
enum enum_field_types field_type)
|
enum enum_field_types field_type)
|
||||||
{
|
{
|
||||||
|
tmp_field->db_name=(char*) "";
|
||||||
|
tmp_field->org_table_name=(char*) "";
|
||||||
|
tmp_field->org_col_name=(char*) "";
|
||||||
tmp_field->table_name=(char*) "";
|
tmp_field->table_name=(char*) "";
|
||||||
tmp_field->col_name=name;
|
tmp_field->col_name=name;
|
||||||
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
|
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
|
||||||
|
34
sql/item.h
34
sql/item.h
@ -155,6 +155,40 @@ public:
|
|||||||
bool is_null() { return 1; }
|
bool is_null() { return 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Item_param :public Item
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
longlong int_value;
|
||||||
|
double real_value;
|
||||||
|
enum Item_result item_result_type;
|
||||||
|
enum Type item_type;
|
||||||
|
enum enum_field_types buffer_type;
|
||||||
|
my_bool long_data_supplied;
|
||||||
|
|
||||||
|
Item_param(char *name_par=0){
|
||||||
|
name= name_par ? name_par : (char*) "?";
|
||||||
|
long_data_supplied = false;
|
||||||
|
item_type = STRING_ITEM; item_result_type = STRING_RESULT;
|
||||||
|
}
|
||||||
|
enum Type type() const { return item_type; }
|
||||||
|
double val();
|
||||||
|
longlong val_int();
|
||||||
|
String *val_str(String*);
|
||||||
|
void make_field(Send_field *field);
|
||||||
|
bool save_in_field(Field *field);
|
||||||
|
void set_null();
|
||||||
|
void set_int(longlong i);
|
||||||
|
void set_double(float i);
|
||||||
|
void set_double(double i);
|
||||||
|
void set_value(const char *str, uint length);
|
||||||
|
void set_long_str(const char *str, ulong length);
|
||||||
|
void set_long_binary(const char *str, ulong length);
|
||||||
|
void set_longdata(const char *str, ulong length);
|
||||||
|
void set_long_end();
|
||||||
|
enum Item_result result_type () const
|
||||||
|
{ return item_result_type; }
|
||||||
|
Item *new_item() { return new Item_param(name); }
|
||||||
|
};
|
||||||
|
|
||||||
class Item_int :public Item
|
class Item_int :public Item
|
||||||
{
|
{
|
||||||
|
@ -60,8 +60,9 @@ void Item_sum::make_field(Send_field *tmp_field)
|
|||||||
result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE :
|
result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE :
|
||||||
FIELD_TYPE_VAR_STRING);
|
FIELD_TYPE_VAR_STRING);
|
||||||
}
|
}
|
||||||
tmp_field->table_name=(char*)"";
|
tmp_field->db_name=(char*)"";
|
||||||
tmp_field->col_name=name;
|
tmp_field->org_table_name=tmp_field->table_name=(char*)"";
|
||||||
|
tmp_field->org_col_name=tmp_field->col_name=name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item_sum::print(String *str)
|
void Item_sum::print(String *str)
|
||||||
|
@ -129,6 +129,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "DROP", SYM(DROP),0,0},
|
{ "DROP", SYM(DROP),0,0},
|
||||||
{ "DUMPFILE", SYM(DUMPFILE),0,0},
|
{ "DUMPFILE", SYM(DUMPFILE),0,0},
|
||||||
{ "DYNAMIC", SYM(DYNAMIC_SYM),0,0},
|
{ "DYNAMIC", SYM(DYNAMIC_SYM),0,0},
|
||||||
|
{ "ERRORS", SYM(ERRORS),0,0},
|
||||||
{ "END", SYM(END),0,0},
|
{ "END", SYM(END),0,0},
|
||||||
{ "ELSE", SYM(ELSE),0,0},
|
{ "ELSE", SYM(ELSE),0,0},
|
||||||
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
|
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
|
||||||
@ -327,6 +328,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
|
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
|
||||||
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
|
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
|
||||||
{ "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0},
|
{ "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0},
|
||||||
|
{ "SQL_ERROR_COUNT", SYM(SQL_ERROR_COUNT),0,0},
|
||||||
{ "SQL_LOG_BIN", SYM(SQL_LOG_BIN),0,0},
|
{ "SQL_LOG_BIN", SYM(SQL_LOG_BIN),0,0},
|
||||||
{ "SQL_LOG_OFF", SYM(SQL_LOG_OFF),0,0},
|
{ "SQL_LOG_OFF", SYM(SQL_LOG_OFF),0,0},
|
||||||
{ "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0},
|
{ "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0},
|
||||||
@ -366,6 +368,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "TRUNCATE", SYM(TRUNCATE_SYM),0,0},
|
{ "TRUNCATE", SYM(TRUNCATE_SYM),0,0},
|
||||||
{ "TO", SYM(TO_SYM),0,0},
|
{ "TO", SYM(TO_SYM),0,0},
|
||||||
{ "TYPE", SYM(TYPE_SYM),0,0},
|
{ "TYPE", SYM(TYPE_SYM),0,0},
|
||||||
|
{ "TYPES", SYM(TYPES_SYM),0,0},
|
||||||
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM),0,0},
|
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM),0,0},
|
||||||
{ "UNION", SYM(UNION_SYM),0,0},
|
{ "UNION", SYM(UNION_SYM),0,0},
|
||||||
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
|
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
|
||||||
@ -381,6 +384,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "VARIABLES", SYM(VARIABLES),0,0},
|
{ "VARIABLES", SYM(VARIABLES),0,0},
|
||||||
{ "VARYING", SYM(VARYING),0,0},
|
{ "VARYING", SYM(VARYING),0,0},
|
||||||
{ "VARBINARY", SYM(VARBINARY),0,0},
|
{ "VARBINARY", SYM(VARBINARY),0,0},
|
||||||
|
{ "WARNINGS", SYM(WARNINGS),0,0},
|
||||||
{ "WITH", SYM(WITH),0,0},
|
{ "WITH", SYM(WITH),0,0},
|
||||||
{ "WORK", SYM(WORK_SYM),0,0},
|
{ "WORK", SYM(WORK_SYM),0,0},
|
||||||
{ "WRITE", SYM(WRITE_SYM),0,0},
|
{ "WRITE", SYM(WRITE_SYM),0,0},
|
||||||
|
@ -287,6 +287,8 @@ inline THD *_current_thd(void)
|
|||||||
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
|
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
|
||||||
#endif /*HAVE_QUERY_CACHE*/
|
#endif /*HAVE_QUERY_CACHE*/
|
||||||
|
|
||||||
|
#define prepare_execute(A) ((A)->command == COM_EXECUTE)
|
||||||
|
|
||||||
int mysql_create_db(THD *thd, char *db, uint create_info, bool silent);
|
int mysql_create_db(THD *thd, char *db, uint create_info, bool silent);
|
||||||
int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
|
int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
|
||||||
void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags);
|
void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags);
|
||||||
@ -363,6 +365,8 @@ bool net_store_data(String *packet, CONVERT *convert, const char *from);
|
|||||||
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
|
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
|
||||||
int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
|
int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
|
||||||
List <Item> &all_fields, ORDER *order);
|
List <Item> &all_fields, ORDER *order);
|
||||||
|
int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
||||||
|
List<Item> &all_fields, ORDER *order, bool *hidden_group_fields);
|
||||||
|
|
||||||
int handle_select(THD *thd, LEX *lex, select_result *result);
|
int handle_select(THD *thd, LEX *lex, select_result *result);
|
||||||
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
|
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
|
||||||
@ -455,7 +459,7 @@ bool load_des_key_file(const char *file_name);
|
|||||||
/* sql_do.cc */
|
/* sql_do.cc */
|
||||||
int mysql_do(THD *thd, List<Item> &values);
|
int mysql_do(THD *thd, List<Item> &values);
|
||||||
|
|
||||||
/* sql_list.c */
|
/* sql_show.c */
|
||||||
int mysqld_show_dbs(THD *thd,const char *wild);
|
int mysqld_show_dbs(THD *thd,const char *wild);
|
||||||
int mysqld_show_open_tables(THD *thd,const char *wild);
|
int mysqld_show_open_tables(THD *thd,const char *wild);
|
||||||
int mysqld_show_tables(THD *thd,const char *db,const char *wild);
|
int mysqld_show_tables(THD *thd,const char *db,const char *wild);
|
||||||
@ -473,6 +477,24 @@ int mysqld_show_status(THD *thd);
|
|||||||
int mysqld_show_variables(THD *thd,const char *wild);
|
int mysqld_show_variables(THD *thd,const char *wild);
|
||||||
int mysqld_show(THD *thd, const char *wild, show_var_st *variables);
|
int mysqld_show(THD *thd, const char *wild, show_var_st *variables);
|
||||||
int mysqld_show_charsets(THD *thd,const char *wild);
|
int mysqld_show_charsets(THD *thd,const char *wild);
|
||||||
|
int mysqld_show_privileges(THD *thd);
|
||||||
|
int mysqld_show_column_types(THD *thd);
|
||||||
|
|
||||||
|
/* sql_prepare.cc */
|
||||||
|
void mysql_com_prepare(THD *thd,char*packet,uint packet_length);
|
||||||
|
void mysql_init_query(THD *thd);/* sql_parse. cc */
|
||||||
|
void mysql_com_execute(THD *thd);
|
||||||
|
void mysql_com_longdata(THD *thd);
|
||||||
|
int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
|
||||||
|
List<Item> &values, ulong counter);
|
||||||
|
|
||||||
|
/* sql_error.cc */
|
||||||
|
void push_error(uint code, const char *msg);
|
||||||
|
void push_warning(uint code, const char *msg);
|
||||||
|
int mysqld_show_warnings(THD *thd);
|
||||||
|
int mysqld_show_errors(THD *thd);
|
||||||
|
int mysqld_show_warnings_count(THD *thd);
|
||||||
|
int mysqld_show_errors_count(THD *);
|
||||||
|
|
||||||
/* sql_handler.cc */
|
/* sql_handler.cc */
|
||||||
int mysql_ha_open(THD *thd, TABLE_LIST *tables);
|
int mysql_ha_open(THD *thd, TABLE_LIST *tables);
|
||||||
@ -654,6 +676,10 @@ extern const char *default_tx_isolation_name;
|
|||||||
extern String empty_string;
|
extern String empty_string;
|
||||||
extern struct show_var_st init_vars[];
|
extern struct show_var_st init_vars[];
|
||||||
extern struct show_var_st status_vars[];
|
extern struct show_var_st status_vars[];
|
||||||
|
extern struct show_table_type_st table_type_vars[];
|
||||||
|
extern SHOW_COMP_OPTION have_isam;
|
||||||
|
extern SHOW_COMP_OPTION have_innodb;
|
||||||
|
extern SHOW_COMP_OPTION have_berkeley_db;
|
||||||
extern enum db_type default_table_type;
|
extern enum db_type default_table_type;
|
||||||
extern enum enum_tx_isolation default_tx_isolation;
|
extern enum enum_tx_isolation default_tx_isolation;
|
||||||
extern char glob_hostname[FN_REFLEN];
|
extern char glob_hostname[FN_REFLEN];
|
||||||
|
@ -48,6 +48,7 @@ void send_error(NET *net, uint sql_errno, const char *err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
push_error(sql_errno, err);
|
||||||
if (net->vio == 0)
|
if (net->vio == 0)
|
||||||
{
|
{
|
||||||
if (thd && thd->bootstrap)
|
if (thd && thd->bootstrap)
|
||||||
@ -83,6 +84,13 @@ void send_error(NET *net, uint sql_errno, const char *err)
|
|||||||
void send_warning(NET *net, uint sql_errno, const char *err)
|
void send_warning(NET *net, uint sql_errno, const char *err)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("send_warning");
|
DBUG_ENTER("send_warning");
|
||||||
|
push_warning(sql_errno, err ? err : ER(sql_errno));
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO :
|
||||||
|
Try to return ok with warning status to client, instead
|
||||||
|
of returning error ..
|
||||||
|
*/
|
||||||
send_error(net,sql_errno,err);
|
send_error(net,sql_errno,err);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
@ -123,6 +131,7 @@ net_printf(NET *net, uint errcode, ...)
|
|||||||
length=sizeof(net->last_error)-1; /* purecov: inspected */
|
length=sizeof(net->last_error)-1; /* purecov: inspected */
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
|
push_error(errcode, text_pos);
|
||||||
if (net->vio == 0)
|
if (net->vio == 0)
|
||||||
{
|
{
|
||||||
if (thd && thd->bootstrap)
|
if (thd && thd->bootstrap)
|
||||||
|
182
sql/sql_base.cc
182
sql/sql_base.cc
@ -179,56 +179,58 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
|
|||||||
DBUG_RETURN(open_list);
|
DBUG_RETURN(open_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/******************************************************************************
|
Send name and type of result to client.
|
||||||
** Send name and type of result to client.
|
Sum fields has table name empty and field_name.
|
||||||
** Sum fields has table name empty and field_name.
|
flag is a bit mask with the following functions:
|
||||||
** flag is a bit mask with the following functions:
|
1 send number of rows
|
||||||
** 1 send number of rows
|
2 send default values
|
||||||
** 2 send default values
|
4 Don't convert field names
|
||||||
** 4 Don't convert field names
|
*/
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
send_fields(THD *thd,List<Item> &list,uint flag)
|
send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag)
|
||||||
{
|
{
|
||||||
List_iterator_fast<Item> it(list);
|
List_iterator_fast<Item> it(list);
|
||||||
Item *item;
|
Item *item;
|
||||||
char buff[80];
|
char buff[80];
|
||||||
CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->convert_set;
|
|
||||||
DBUG_ENTER("send_fields");
|
|
||||||
|
|
||||||
String tmp((char*) buff,sizeof(buff),default_charset_info);
|
String tmp((char*) buff,sizeof(buff),default_charset_info);
|
||||||
String *res,*packet= &thd->packet;
|
String *res,*packet= &thd->packet;
|
||||||
|
|
||||||
if (thd->fatal_error) // We have got an error
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (flag & 1)
|
|
||||||
{ // Packet with number of elements
|
|
||||||
char *pos=net_store_length(buff,(uint) list.elements);
|
|
||||||
(void) my_net_write(&thd->net, buff,(uint) (pos-buff));
|
|
||||||
}
|
|
||||||
while ((item=it++))
|
while ((item=it++))
|
||||||
{
|
{
|
||||||
char *pos;
|
char *pos;
|
||||||
Send_field field;
|
Send_field field;
|
||||||
item->make_field(&field);
|
item->make_field(&field);
|
||||||
|
|
||||||
packet->length(0);
|
packet->length(0);
|
||||||
|
|
||||||
if (convert)
|
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
|
||||||
|
{
|
||||||
|
if (convert->store(packet,field.db_name,
|
||||||
|
(uint) strlen(field.db_name)) ||
|
||||||
|
convert->store(packet,field.table_name,
|
||||||
|
(uint) strlen(field.table_name)) ||
|
||||||
|
convert->store(packet,field.org_table_name,
|
||||||
|
(uint) strlen(field.org_table_name)) ||
|
||||||
|
convert->store(packet,field.col_name,
|
||||||
|
(uint) strlen(field.col_name)) ||
|
||||||
|
convert->store(packet,field.org_col_name,
|
||||||
|
(uint) strlen(field.org_col_name)) ||
|
||||||
|
packet->realloc(packet->length()+10))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (convert->store(packet,field.table_name,
|
if (convert->store(packet,field.table_name,
|
||||||
(uint) strlen(field.table_name)) ||
|
(uint) strlen(field.table_name)) ||
|
||||||
convert->store(packet,field.col_name,
|
convert->store(packet,field.col_name,
|
||||||
(uint) strlen(field.col_name)) ||
|
(uint) strlen(field.col_name)) ||
|
||||||
packet->realloc(packet->length()+10))
|
packet->realloc(packet->length()+10))
|
||||||
goto err;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (net_store_data(packet,field.table_name) ||
|
|
||||||
net_store_data(packet,field.col_name) ||
|
|
||||||
packet->realloc(packet->length()+10))
|
|
||||||
goto err; /* purecov: inspected */
|
|
||||||
pos= (char*) packet->ptr()+packet->length();
|
pos= (char*) packet->ptr()+packet->length();
|
||||||
|
|
||||||
if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
|
if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
|
||||||
@ -250,19 +252,135 @@ send_fields(THD *thd,List<Item> &list,uint flag)
|
|||||||
if (!(res=item->val_str(&tmp)))
|
if (!(res=item->val_str(&tmp)))
|
||||||
{
|
{
|
||||||
if (net_store_null(packet))
|
if (net_store_null(packet))
|
||||||
goto err;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (net_store_data(packet,res->ptr(),res->length()))
|
else if (net_store_data(packet,res->ptr(),res->length()))
|
||||||
goto err;
|
return 1;
|
||||||
}
|
}
|
||||||
if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
|
if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
|
||||||
break; /* purecov: inspected */
|
break; /* purecov: inspected */
|
||||||
}
|
}
|
||||||
send_eof(&thd->net,1);
|
return 0;
|
||||||
DBUG_RETURN(0);
|
}
|
||||||
err:
|
|
||||||
|
/*
|
||||||
|
Send name and type of result to client.
|
||||||
|
Sum fields has table name empty and field_name
|
||||||
|
flag is a bit mask with the following functios:
|
||||||
|
1 send number of rows
|
||||||
|
2 send default values
|
||||||
|
4 Don't convert field names
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
send_non_convert_fields(THD *thd,List<Item> &list,uint flag)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item> it(list);
|
||||||
|
Item *item;
|
||||||
|
char buff[80];
|
||||||
|
|
||||||
|
String tmp((char*) buff,sizeof(buff),default_charset_info);
|
||||||
|
String *res,*packet= &thd->packet;
|
||||||
|
|
||||||
|
while ((item=it++))
|
||||||
|
{
|
||||||
|
char *pos;
|
||||||
|
Send_field field;
|
||||||
|
item->make_field(&field);
|
||||||
|
|
||||||
|
packet->length(0);
|
||||||
|
|
||||||
|
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
|
||||||
|
{
|
||||||
|
if (net_store_data(packet,field.db_name) ||
|
||||||
|
net_store_data(packet,field.table_name) ||
|
||||||
|
net_store_data(packet,field.org_table_name) ||
|
||||||
|
net_store_data(packet,field.col_name) ||
|
||||||
|
net_store_data(packet,field.org_col_name) ||
|
||||||
|
packet->realloc(packet->length()+10))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (net_store_data(packet,field.table_name) ||
|
||||||
|
net_store_data(packet,field.col_name) ||
|
||||||
|
packet->realloc(packet->length()+10))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos= (char*) packet->ptr()+packet->length();
|
||||||
|
|
||||||
|
if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
|
||||||
|
{
|
||||||
|
packet->length(packet->length()+9);
|
||||||
|
pos[0]=3; int3store(pos+1,field.length);
|
||||||
|
pos[4]=1; pos[5]=field.type;
|
||||||
|
pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet->length(packet->length()+10);
|
||||||
|
pos[0]=3; int3store(pos+1,field.length);
|
||||||
|
pos[4]=1; pos[5]=field.type;
|
||||||
|
pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals;
|
||||||
|
}
|
||||||
|
if (flag & 2)
|
||||||
|
{ // Send default value
|
||||||
|
if (!(res=item->val_str(&tmp)))
|
||||||
|
{
|
||||||
|
if (net_store_null(packet))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (net_store_data(packet,res->ptr(),res->length()))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
** Send name and type of result to client.
|
||||||
|
** Sum fields has table name empty and field_name.
|
||||||
|
** flag is a bit mask with the following functions:
|
||||||
|
** 1 send number of rows
|
||||||
|
** 2 send default values
|
||||||
|
** 4 Don't convert field names
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
bool
|
||||||
|
send_fields(THD *thd,List<Item> &list,uint flag)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item> it(list);
|
||||||
|
char buff[80];
|
||||||
|
CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->convert_set;
|
||||||
|
|
||||||
|
String tmp((char*) buff,sizeof(buff),default_charset_info);
|
||||||
|
|
||||||
|
if (thd->fatal_error) // We have got an error
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (flag & 1)
|
||||||
|
{ // Packet with number of elements
|
||||||
|
char *pos=net_store_length(buff,(uint) list.elements);
|
||||||
|
(void) my_net_write(&thd->net, buff,(uint) (pos-buff));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoid check conditions on convert() for each field
|
||||||
|
by having two diffrent functions
|
||||||
|
*/
|
||||||
|
if (convert && send_convert_fields(thd,list,convert,flag))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
else if(send_non_convert_fields(thd,list,flag))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
send_eof(&thd->net);
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */
|
send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */
|
||||||
DBUG_RETURN(1); /* purecov: inspected */
|
return 1; /* purecov: inspected */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
|
|||||||
command=COM_CONNECT;
|
command=COM_CONNECT;
|
||||||
set_query_id=1;
|
set_query_id=1;
|
||||||
default_select_limit= HA_POS_ERROR;
|
default_select_limit= HA_POS_ERROR;
|
||||||
|
max_error_count=max_warning_count=MYSQL_DEFAULT_ERROR_COUNT;
|
||||||
max_join_size= ((::max_join_size != ~ (ulong) 0L) ? ::max_join_size :
|
max_join_size= ((::max_join_size != ~ (ulong) 0L) ? ::max_join_size :
|
||||||
HA_POS_ERROR);
|
HA_POS_ERROR);
|
||||||
db_access=NO_ACCESS;
|
db_access=NO_ACCESS;
|
||||||
@ -147,6 +148,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
|
|||||||
/* Initialize sub structures */
|
/* Initialize sub structures */
|
||||||
bzero((char*) &mem_root,sizeof(mem_root));
|
bzero((char*) &mem_root,sizeof(mem_root));
|
||||||
bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
|
bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
|
||||||
|
bzero((char*) &con_root,sizeof(con_root));
|
||||||
user_connect=(USER_CONN *)0;
|
user_connect=(USER_CONN *)0;
|
||||||
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
|
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
|
||||||
(hash_get_key) get_var_key,
|
(hash_get_key) get_var_key,
|
||||||
@ -223,6 +225,7 @@ THD::~THD()
|
|||||||
safeFree(db);
|
safeFree(db);
|
||||||
safeFree(ip);
|
safeFree(ip);
|
||||||
free_root(&mem_root,MYF(0));
|
free_root(&mem_root,MYF(0));
|
||||||
|
free_root(&con_root,MYF(0));
|
||||||
free_root(&transaction.mem_root,MYF(0));
|
free_root(&transaction.mem_root,MYF(0));
|
||||||
mysys_var=0; // Safety (shouldn't be needed)
|
mysys_var=0; // Safety (shouldn't be needed)
|
||||||
#ifdef SIGNAL_WITH_VIO_CLOSE
|
#ifdef SIGNAL_WITH_VIO_CLOSE
|
||||||
|
@ -289,7 +289,30 @@ public:
|
|||||||
i_string_pair():key(0),val(0) { }
|
i_string_pair():key(0),val(0) { }
|
||||||
i_string_pair(char* key_arg, char* val_arg) : key(key_arg),val(val_arg) {}
|
i_string_pair(char* key_arg, char* val_arg) : key(key_arg),val(val_arg) {}
|
||||||
};
|
};
|
||||||
|
#define MYSQL_DEFAULT_ERROR_COUNT 500
|
||||||
|
|
||||||
|
class mysql_st_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint code;
|
||||||
|
char msg[MYSQL_ERRMSG_SIZE+1];
|
||||||
|
char query[NAME_LEN+1];
|
||||||
|
|
||||||
|
static void *operator new(size_t size)
|
||||||
|
{
|
||||||
|
return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE));
|
||||||
|
}
|
||||||
|
static void operator delete(void* ptr_arg, size_t size)
|
||||||
|
{
|
||||||
|
my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
|
||||||
|
}
|
||||||
|
mysql_st_error(uint ecode, const char *emsg, const char *equery)
|
||||||
|
{
|
||||||
|
code = ecode;
|
||||||
|
strmov(msg, emsg);
|
||||||
|
strnmov(query, equery ? equery : "", NAME_LEN);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class delayed_insert;
|
class delayed_insert;
|
||||||
|
|
||||||
@ -308,6 +331,7 @@ public:
|
|||||||
NET net; // client connection descriptor
|
NET net; // client connection descriptor
|
||||||
LEX lex; // parse tree descriptor
|
LEX lex; // parse tree descriptor
|
||||||
MEM_ROOT mem_root; // 1 command-life memory
|
MEM_ROOT mem_root; // 1 command-life memory
|
||||||
|
MEM_ROOT con_root; // connection-life memory
|
||||||
HASH user_vars; // hash for user variables
|
HASH user_vars; // hash for user variables
|
||||||
String packet; // buffer used for network I/O
|
String packet; // buffer used for network I/O
|
||||||
struct sockaddr_in remote; // client socket address
|
struct sockaddr_in remote; // client socket address
|
||||||
@ -410,7 +434,8 @@ public:
|
|||||||
max_join_size, sent_row_count, examined_row_count;
|
max_join_size, sent_row_count, examined_row_count;
|
||||||
table_map used_tables;
|
table_map used_tables;
|
||||||
USER_CONN *user_connect;
|
USER_CONN *user_connect;
|
||||||
ulong query_id,version, inactive_timeout,options,thread_id;
|
ulong query_id,version, inactive_timeout,options,thread_id,
|
||||||
|
max_error_count, max_warning_count;
|
||||||
long dbug_thread_id;
|
long dbug_thread_id;
|
||||||
pthread_t real_id;
|
pthread_t real_id;
|
||||||
uint current_tablenr,tmp_table,cond_count,col_access;
|
uint current_tablenr,tmp_table,cond_count,col_access;
|
||||||
@ -428,8 +453,13 @@ public:
|
|||||||
bool query_error, bootstrap, cleanup_done;
|
bool query_error, bootstrap, cleanup_done;
|
||||||
bool safe_to_cache_query;
|
bool safe_to_cache_query;
|
||||||
bool volatile killed;
|
bool volatile killed;
|
||||||
// TRUE when having fix field called
|
bool having_fix_field; //TRUE when having fix field called
|
||||||
bool having_fix_field;
|
bool prepare_command;
|
||||||
|
ulong param_count,current_param_number;
|
||||||
|
Error<mysql_st_error> err_list;
|
||||||
|
Error<mysql_st_error> warn_list;
|
||||||
|
Item_param *current_param;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If we do a purge of binary logs, log index info of the threads
|
If we do a purge of binary logs, log index info of the threads
|
||||||
that are currently reading it needs to be adjusted. To do that
|
that are currently reading it needs to be adjusted. To do that
|
||||||
|
219
sql/sql_error.cc
Normal file
219
sql/sql_error.cc
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/* Copyright (C) 1995-2002 MySQL AB
|
||||||
|
|
||||||
|
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; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
This file contains the implementation of error and warnings related
|
||||||
|
|
||||||
|
- Whenever an error or warning occured, it pushes the same to
|
||||||
|
the respective list along with sending it to client.
|
||||||
|
|
||||||
|
- When client requests the information using SHOW command, then
|
||||||
|
server processes from this list and returns back in the form of
|
||||||
|
resultset.
|
||||||
|
|
||||||
|
syntax : SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows]
|
||||||
|
SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows]
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
/* Handles errors and warnings .. */
|
||||||
|
|
||||||
|
#include "mysql_priv.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Push the error to error list
|
||||||
|
*/
|
||||||
|
|
||||||
|
void push_error(uint code, const char *msg)
|
||||||
|
{
|
||||||
|
THD *thd=current_thd;
|
||||||
|
|
||||||
|
mysql_st_error *err = new mysql_st_error(code,msg,(const char*)thd->query);
|
||||||
|
|
||||||
|
if (thd->err_list.elements >= thd->max_error_count)
|
||||||
|
{
|
||||||
|
/* Remove the old elements and always maintain the max size
|
||||||
|
equal to sql_error_count.
|
||||||
|
|
||||||
|
If one max_error_count using sets sql_error_count less than
|
||||||
|
the current list size, then make sure it always grows upto
|
||||||
|
sql_error_count size only
|
||||||
|
|
||||||
|
** BUG ** : Doesn't work in removing the old one
|
||||||
|
from the list, and thus SET SQL_ERROR_COUNT=x doesn't work
|
||||||
|
*/
|
||||||
|
for (uint count=thd->err_list.elements-1;
|
||||||
|
count <= thd->max_error_count-1; count++)
|
||||||
|
{
|
||||||
|
thd->err_list.remove_last();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thd->err_list.push_front(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Push the warning to warning list
|
||||||
|
*/
|
||||||
|
|
||||||
|
void push_warning(uint code, const char *msg)
|
||||||
|
{
|
||||||
|
THD *thd=current_thd;
|
||||||
|
|
||||||
|
mysql_st_error *warn = new mysql_st_error(code,msg,(const char *)thd->query);
|
||||||
|
|
||||||
|
if (thd->warn_list.elements >= thd->max_warning_count)
|
||||||
|
{
|
||||||
|
/* Remove the old elements and always maintian the max size
|
||||||
|
equal to sql_error_count
|
||||||
|
*/
|
||||||
|
for (uint count=thd->warn_list.elements;
|
||||||
|
count <= thd->max_warning_count-1; count++)
|
||||||
|
{
|
||||||
|
thd->warn_list.remove_last();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thd->warn_list.push_front(warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
List all errors
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mysqld_show_errors(THD *thd)
|
||||||
|
{
|
||||||
|
List<Item> field_list;
|
||||||
|
DBUG_ENTER("mysqld_show_errors");
|
||||||
|
|
||||||
|
field_list.push_back(new Item_int("CODE",0,4));
|
||||||
|
field_list.push_back(new Item_empty_string("MESSAGE",MYSQL_ERRMSG_SIZE));
|
||||||
|
field_list.push_back(new Item_empty_string("QUERY",NAME_LEN));
|
||||||
|
|
||||||
|
if (send_fields(thd,field_list,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
mysql_st_error *err;
|
||||||
|
SELECT_LEX *sel=&thd->lex.select_lex;
|
||||||
|
ha_rows offset = sel->offset_limit,limit = sel->select_limit;
|
||||||
|
uint num_rows = 0;
|
||||||
|
|
||||||
|
Error_iterator<mysql_st_error> it(thd->err_list);
|
||||||
|
|
||||||
|
while(offset-- && (err = it++));/* Should be fixed with overloaded
|
||||||
|
operator '+' or with new funtion
|
||||||
|
goto() in list ?
|
||||||
|
*/
|
||||||
|
|
||||||
|
while((num_rows++ < limit) && (err = it++))
|
||||||
|
{
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,(uint32)err->code);
|
||||||
|
net_store_data(&thd->packet,err->msg);
|
||||||
|
net_store_data(&thd->packet,err->query);
|
||||||
|
|
||||||
|
if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
send_eof(&thd->net);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return errors count
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mysqld_show_errors_count(THD *thd)
|
||||||
|
{
|
||||||
|
List<Item> field_list;
|
||||||
|
DBUG_ENTER("mysqld_show_errors_count");
|
||||||
|
|
||||||
|
field_list.push_back(new Item_int("COUNT(*)",0,4));
|
||||||
|
|
||||||
|
if (send_fields(thd,field_list,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,(uint32)thd->err_list.elements);
|
||||||
|
|
||||||
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
send_eof(&thd->net);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
List all warnings
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mysqld_show_warnings(THD *thd)
|
||||||
|
{
|
||||||
|
List<Item> field_list;
|
||||||
|
DBUG_ENTER("mysqld_show_warnings");
|
||||||
|
|
||||||
|
field_list.push_back(new Item_int("CODE",0,21));
|
||||||
|
field_list.push_back(new Item_empty_string("MESSAGE",MYSQL_ERRMSG_SIZE));
|
||||||
|
field_list.push_back(new Item_empty_string("QUERY",NAME_LEN));
|
||||||
|
|
||||||
|
if (send_fields(thd,field_list,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
mysql_st_error *warn;
|
||||||
|
|
||||||
|
|
||||||
|
SELECT_LEX *sel=&thd->lex.select_lex;
|
||||||
|
ha_rows offset = sel->offset_limit,limit = sel->select_limit;
|
||||||
|
uint num_rows = 0;
|
||||||
|
|
||||||
|
Error_iterator<mysql_st_error> it(thd->warn_list);
|
||||||
|
while(offset-- && (warn = it++));
|
||||||
|
while((num_rows++ < limit) && (warn = it++))
|
||||||
|
{
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,(uint32)warn->code);
|
||||||
|
net_store_data(&thd->packet,warn->msg);
|
||||||
|
net_store_data(&thd->packet,warn->query);
|
||||||
|
|
||||||
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
send_eof(&thd->net);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return warnings count
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mysqld_show_warnings_count(THD *thd)
|
||||||
|
{
|
||||||
|
List<Item> field_list;
|
||||||
|
DBUG_ENTER("mysqld_show_warnings_count");
|
||||||
|
|
||||||
|
field_list.push_back(new Item_int("COUNT(*)",0,21));
|
||||||
|
|
||||||
|
if (send_fields(thd,field_list,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,(uint32)thd->warn_list.elements);
|
||||||
|
|
||||||
|
if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
send_eof(&thd->net);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ static void unlink_blobs(register TABLE *table);
|
|||||||
Resets form->time_stamp if a timestamp value is set
|
Resets form->time_stamp if a timestamp value is set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
int
|
||||||
check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
|
check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
|
||||||
List<Item> &values, ulong counter)
|
List<Item> &values, ulong counter)
|
||||||
{
|
{
|
||||||
|
@ -57,8 +57,10 @@ enum enum_sql_command {
|
|||||||
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
|
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
|
||||||
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
|
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
|
||||||
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
|
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
|
||||||
SQLCOM_EMPTY_QUERY,
|
SQLCOM_END, SQLCOM_SHOW_WARNS, SQLCOM_SHOW_WARNS_COUNT,
|
||||||
SQLCOM_END
|
SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
|
||||||
|
SQLCOM_SHOW_ERRORS_COUNT, SQLCOM_SHOW_COLUMN_TYPES,
|
||||||
|
SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES
|
||||||
};
|
};
|
||||||
|
|
||||||
enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
|
enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
|
||||||
@ -318,6 +320,7 @@ typedef struct st_lex {
|
|||||||
List<Item> *insert_list,field_list,value_list;
|
List<Item> *insert_list,field_list,value_list;
|
||||||
List<List_item> many_values;
|
List<List_item> many_values;
|
||||||
List<Set_option> option_list;
|
List<Set_option> option_list;
|
||||||
|
List<Item> param_list;
|
||||||
SQL_LIST proc_list, auxilliary_table_list;
|
SQL_LIST proc_list, auxilliary_table_list;
|
||||||
TYPELIB *interval;
|
TYPELIB *interval;
|
||||||
create_field *last_field;
|
create_field *last_field;
|
||||||
|
121
sql/sql_list.h
121
sql/sql_list.h
@ -122,11 +122,14 @@ public:
|
|||||||
last= &first;
|
last= &first;
|
||||||
return tmp->info;
|
return tmp->info;
|
||||||
}
|
}
|
||||||
|
inline list_node* last_node() { return *last; }
|
||||||
|
inline list_node* first_node() { return first;}
|
||||||
inline void *head() { return first->info; }
|
inline void *head() { return first->info; }
|
||||||
inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
|
inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
|
||||||
inline bool is_empty() { return first == &end_of_list ; }
|
inline bool is_empty() { return first == &end_of_list ; }
|
||||||
inline list_node *last_ref() { return &end_of_list; }
|
inline list_node *last_ref() { return &end_of_list; }
|
||||||
friend class base_list_iterator;
|
friend class base_list_iterator;
|
||||||
|
friend class error_list;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void after(void *info,list_node *node)
|
void after(void *info,list_node *node)
|
||||||
@ -204,6 +207,7 @@ public:
|
|||||||
{
|
{
|
||||||
return el == &list->last_ref()->next;
|
return el == &list->last_ref()->next;
|
||||||
}
|
}
|
||||||
|
friend class error_list_iterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -356,3 +360,120 @@ public:
|
|||||||
I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
|
I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
|
||||||
inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
|
inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
New error list without mem_root from THD, to have the life of the
|
||||||
|
allocation becomes connection level . by ovveriding new from Sql_alloc.
|
||||||
|
*/
|
||||||
|
class Error_alloc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void *operator new(size_t size)
|
||||||
|
{
|
||||||
|
return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE));
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
static void operator delete(void* ptr_arg, size_t size)
|
||||||
|
{
|
||||||
|
my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
friend class error_node;
|
||||||
|
friend class error_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
class error_node :public Error_alloc, public list_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void *operator new(size_t size)
|
||||||
|
{
|
||||||
|
return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE));
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
static void operator delete(void* ptr_arg, size_t size)
|
||||||
|
{
|
||||||
|
my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
error_node(void *info_par,list_node *next_par):list_node(info_par,next_par){};
|
||||||
|
error_node() : list_node() {};
|
||||||
|
friend class error_list;
|
||||||
|
friend class error_list_iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
class error_list: public Error_alloc, public base_list
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline error_list() : base_list() { };
|
||||||
|
inline error_list(const error_list &tmp) : Error_alloc()
|
||||||
|
{
|
||||||
|
elements=tmp.elements;
|
||||||
|
first=tmp.first;
|
||||||
|
last=tmp.last;
|
||||||
|
}
|
||||||
|
inline bool push_front(void *info)
|
||||||
|
{
|
||||||
|
error_node *node=new error_node(info,first);
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
if (last == &first)
|
||||||
|
last= &node->next;
|
||||||
|
first=node;
|
||||||
|
elements++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
inline void remove_last(void)
|
||||||
|
{
|
||||||
|
remove(last);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
void after(void *info,list_node *node)
|
||||||
|
{
|
||||||
|
error_node *new_node=new error_node(info,node->next);
|
||||||
|
node->next=new_node;
|
||||||
|
elements++;
|
||||||
|
if (last == &(node->next))
|
||||||
|
last= &new_node->next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class error_list_iterator : public base_list_iterator
|
||||||
|
{
|
||||||
|
inline error_list_iterator(base_list &base_ptr): base_list_iterator(base_ptr) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> class Error :public error_list
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline Error() :error_list() {}
|
||||||
|
inline Error(const Error<T> &tmp) :error_list(tmp) {}
|
||||||
|
inline bool push_back(T *a) { return error_list::push_back(a); }
|
||||||
|
inline bool push_front(T *a) { return error_list::push_front(a); }
|
||||||
|
inline T* head() {return (T*) error_list::head(); }
|
||||||
|
inline T** head_ref() {return (T**) error_list::head_ref(); }
|
||||||
|
inline T* pop() {return (T*) error_list::pop(); }
|
||||||
|
void delete_elements(void)
|
||||||
|
{
|
||||||
|
error_node *element,*next;
|
||||||
|
for (element=first; element != &error_end_of_list; element=next)
|
||||||
|
{
|
||||||
|
next=element->next;
|
||||||
|
delete (T*) element->info;
|
||||||
|
}
|
||||||
|
empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> class Error_iterator :public base_list_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Error_iterator(Error<T> &a) : base_list_iterator(a) {}
|
||||||
|
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
|
||||||
|
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
|
||||||
|
inline T *replace(Error<T> &a) { return (T*) base_list_iterator::replace(a); }
|
||||||
|
inline void after(T *a) { base_list_iterator::after(a); }
|
||||||
|
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
@ -65,7 +65,6 @@ static void decrease_user_connections(USER_CONN *uc);
|
|||||||
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
||||||
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
|
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
|
||||||
static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
|
static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
|
||||||
void mysql_init_query(THD *thd);
|
|
||||||
static void remove_escape(char *name);
|
static void remove_escape(char *name);
|
||||||
static void refresh_status(void);
|
static void refresh_status(void);
|
||||||
static bool append_file_to_dir(THD *thd, char **filename_ptr,
|
static bool append_file_to_dir(THD *thd, char **filename_ptr,
|
||||||
@ -77,7 +76,8 @@ const char *command_name[]={
|
|||||||
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
|
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
|
||||||
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
|
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
|
||||||
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
|
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
|
||||||
"Binlog Dump","Table Dump", "Connect Out", "Register Slave"
|
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
|
||||||
|
"Prepare", "Prepare Execute", "Long Data"
|
||||||
};
|
};
|
||||||
|
|
||||||
bool volatile abort_slave = 0;
|
bool volatile abort_slave = 0;
|
||||||
@ -486,7 +486,7 @@ check_connections(THD *thd)
|
|||||||
{
|
{
|
||||||
/* buff[] needs to big enough to hold the server_version variable */
|
/* buff[] needs to big enough to hold the server_version variable */
|
||||||
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
|
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
|
||||||
int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
|
int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41;
|
||||||
|
|
||||||
if (opt_using_transactions)
|
if (opt_using_transactions)
|
||||||
client_flags|=CLIENT_TRANSACTIONS;
|
client_flags|=CLIENT_TRANSACTIONS;
|
||||||
@ -957,7 +957,21 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||||||
thd->password=test(passwd[0]);
|
thd->password=test(passwd[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case COM_EXECUTE:
|
||||||
|
{
|
||||||
|
mysql_com_execute(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_LONG_DATA:
|
||||||
|
{
|
||||||
|
mysql_com_longdata(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_PREPARE:
|
||||||
|
{
|
||||||
|
mysql_com_prepare(thd,packet,packet_length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case COM_QUERY:
|
case COM_QUERY:
|
||||||
{
|
{
|
||||||
packet_length--; // Remove end null
|
packet_length--; // Remove end null
|
||||||
@ -1380,6 +1394,26 @@ mysql_execute_command(void)
|
|||||||
res = purge_master_logs(thd, lex->to_log);
|
res = purge_master_logs(thd, lex->to_log);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SQLCOM_SHOW_WARNS_COUNT:
|
||||||
|
{
|
||||||
|
res = mysqld_show_warnings_count(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLCOM_SHOW_WARNS:
|
||||||
|
{
|
||||||
|
res = mysqld_show_warnings(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLCOM_SHOW_ERRORS_COUNT:
|
||||||
|
{
|
||||||
|
res = mysqld_show_errors_count(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLCOM_SHOW_ERRORS:
|
||||||
|
{
|
||||||
|
res = mysqld_show_errors(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SQLCOM_SHOW_NEW_MASTER:
|
case SQLCOM_SHOW_NEW_MASTER:
|
||||||
{
|
{
|
||||||
if (check_access(thd, FILE_ACL, any_db))
|
if (check_access(thd, FILE_ACL, any_db))
|
||||||
@ -2048,6 +2082,15 @@ mysql_execute_command(void)
|
|||||||
mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
|
mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
|
||||||
thd->priv_user,lex->verbose);
|
thd->priv_user,lex->verbose);
|
||||||
break;
|
break;
|
||||||
|
case SQLCOM_SHOW_TABLE_TYPES:
|
||||||
|
res= mysqld_show_table_types(thd);
|
||||||
|
break;
|
||||||
|
case SQLCOM_SHOW_PRIVILEGES:
|
||||||
|
res= mysqld_show_privileges(thd);
|
||||||
|
break;
|
||||||
|
case SQLCOM_SHOW_COLUMN_TYPES:
|
||||||
|
res= mysqld_show_column_types(thd);
|
||||||
|
break;
|
||||||
case SQLCOM_SHOW_STATUS:
|
case SQLCOM_SHOW_STATUS:
|
||||||
res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars);
|
res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars);
|
||||||
break;
|
break;
|
||||||
@ -2732,6 +2775,9 @@ mysql_init_query(THD *thd)
|
|||||||
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
|
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
|
||||||
thd->sent_row_count= thd->examined_row_count= 0;
|
thd->sent_row_count= thd->examined_row_count= 0;
|
||||||
thd->safe_to_cache_query= 1;
|
thd->safe_to_cache_query= 1;
|
||||||
|
thd->param_count=0;
|
||||||
|
thd->prepare_command=false;
|
||||||
|
thd->lex.param_list.empty();
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
709
sql/sql_prepare.cc
Normal file
709
sql/sql_prepare.cc
Normal file
@ -0,0 +1,709 @@
|
|||||||
|
/* Copyright (C) 1995-2002 MySQL AB
|
||||||
|
|
||||||
|
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; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
This file contains the implementation of prepare and executes.
|
||||||
|
|
||||||
|
Prepare:
|
||||||
|
|
||||||
|
- Server gets the query from client with command 'COM_PREPARE'
|
||||||
|
- Parse the query and recognize any parameter markers '?' and
|
||||||
|
store its information list lex->param_list
|
||||||
|
- Without executing the query, return back to client the total
|
||||||
|
number of parameters along with result-set metadata information
|
||||||
|
(if any )
|
||||||
|
|
||||||
|
Prepare-execute:
|
||||||
|
|
||||||
|
- Server gets the command 'COM_EXECUTE' to execute the
|
||||||
|
previously prepared query.
|
||||||
|
- If there is are any parameters, then replace the markers with the
|
||||||
|
data supplied by client with the following format:
|
||||||
|
[types_specified(0/1)][type][length][data] .. [type][length]..
|
||||||
|
- Execute the query without re-parsing and send back the results
|
||||||
|
to client
|
||||||
|
|
||||||
|
Long data handling:
|
||||||
|
|
||||||
|
- Server gets the long data in pieces with command type 'COM_LONG_DATA'.
|
||||||
|
- The packet recieved will have the format as:
|
||||||
|
[type_spec_exists][type][length][data]
|
||||||
|
- Checks if the type is specified by client, and if yes reads the type,
|
||||||
|
and stores the data in that format.
|
||||||
|
- If length == MYSQL_END_OF_DATA, then server sets up the data read ended.
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include "mysql_priv.h"
|
||||||
|
#include "sql_acl.h"
|
||||||
|
#include <assert.h> // for DEBUG_ASSERT()
|
||||||
|
#include <ctype.h> // for isspace()
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
extern int yyparse(void);
|
||||||
|
static ulong get_param_length(uchar **packet);
|
||||||
|
static uint get_buffer_type(uchar **packet);
|
||||||
|
static bool param_is_null(uchar **packet);
|
||||||
|
static bool setup_param_fields(THD *thd,List<Item> ¶ms);
|
||||||
|
static uchar* setup_param_field(Item_param *item_param, uchar *pos, uint buffer_type);
|
||||||
|
static void setup_longdata_field(Item_param *item_param, uchar *pos);
|
||||||
|
static bool setup_longdata(THD *thd,List<Item> ¶ms);
|
||||||
|
static void send_prepare_results(THD *thd);
|
||||||
|
static void mysql_parse_prepare_query(THD *thd,char *packet,uint length);
|
||||||
|
static bool mysql_send_insert_fields(THD *thd,TABLE_LIST *table_list,
|
||||||
|
List<Item> &fields,
|
||||||
|
List<List_item> &values_list,thr_lock_type lock_type);
|
||||||
|
static bool mysql_test_insert_fields(THD *thd,TABLE_LIST *table_list,
|
||||||
|
List<Item> &fields,
|
||||||
|
List<List_item> &values_list,thr_lock_type lock_type);
|
||||||
|
static bool mysql_test_upd_fields(THD *thd,TABLE_LIST *table_list,
|
||||||
|
List<Item> &fields, List<Item> &values,
|
||||||
|
COND *conds,thr_lock_type lock_type);
|
||||||
|
static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables,
|
||||||
|
List<Item> &fields, List<Item> &values,
|
||||||
|
COND *conds, ORDER *order, ORDER *group,
|
||||||
|
Item *having,thr_lock_type lock_type);
|
||||||
|
extern const char *any_db;
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read the buffer type, this happens only first time
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint get_buffer_type(uchar **packet)
|
||||||
|
{
|
||||||
|
reg1 uchar *pos= *packet;
|
||||||
|
(*packet)+= 2;
|
||||||
|
return (uint) uint2korr(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check for NULL param data
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool param_is_null(uchar **packet)
|
||||||
|
{
|
||||||
|
reg1 uchar *pos= *packet;
|
||||||
|
if (*pos == 251)
|
||||||
|
{
|
||||||
|
(*packet)++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read the length of the parameter data and retun back to
|
||||||
|
caller by positing the pointer to param data
|
||||||
|
*/
|
||||||
|
|
||||||
|
static ulong get_param_length(uchar **packet)
|
||||||
|
{
|
||||||
|
reg1 uchar *pos= *packet;
|
||||||
|
if (*pos < 251)
|
||||||
|
{
|
||||||
|
(*packet)++;
|
||||||
|
return (ulong) *pos;
|
||||||
|
}
|
||||||
|
if (*pos == 252)
|
||||||
|
{
|
||||||
|
(*packet)+=3;
|
||||||
|
return (ulong) uint2korr(pos+1);
|
||||||
|
}
|
||||||
|
if (*pos == 253)
|
||||||
|
{
|
||||||
|
(*packet)+=4;
|
||||||
|
return (ulong) uint3korr(pos+1);
|
||||||
|
}
|
||||||
|
(*packet)+=9; // Must be 254 when here
|
||||||
|
return (ulong) uint4korr(pos+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read and return the data for parameters supplied by client
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uchar* setup_param_field(Item_param *item_param,
|
||||||
|
uchar *pos, uint buffer_type)
|
||||||
|
{
|
||||||
|
if (param_is_null(&pos))
|
||||||
|
{
|
||||||
|
item_param->set_null();
|
||||||
|
return(pos);
|
||||||
|
}
|
||||||
|
switch (buffer_type)
|
||||||
|
{
|
||||||
|
case FIELD_TYPE_TINY:
|
||||||
|
item_param->set_int((longlong)(*pos));
|
||||||
|
pos += 1;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_SHORT:
|
||||||
|
item_param->set_int((longlong)sint2korr(pos));
|
||||||
|
pos += 2;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_INT24:
|
||||||
|
item_param->set_int((longlong)sint4korr(pos));
|
||||||
|
pos += 3;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_LONG:
|
||||||
|
item_param->set_int((longlong)sint4korr(pos));
|
||||||
|
pos += 4;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_LONGLONG:
|
||||||
|
item_param->set_int((longlong)sint8korr(pos));
|
||||||
|
pos += 8;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_FLOAT:
|
||||||
|
float data;
|
||||||
|
float4get(data,pos);
|
||||||
|
item_param->set_double(data);
|
||||||
|
pos += 4;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_DOUBLE:
|
||||||
|
double j;
|
||||||
|
float8get(j,pos)
|
||||||
|
item_param->set_double(j);
|
||||||
|
pos += 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ulong len=get_param_length(&pos);
|
||||||
|
item_param->set_value((const char*)pos,len);
|
||||||
|
pos+=len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update the parameter markers by reading the data
|
||||||
|
from client ..
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool setup_param_fields(THD *thd, List<Item> ¶ms)
|
||||||
|
{
|
||||||
|
reg2 Item_param *item_param;
|
||||||
|
List_iterator<Item> it(params);
|
||||||
|
NET *net = &thd->net;
|
||||||
|
DBUG_ENTER("setup_param_fields");
|
||||||
|
|
||||||
|
ulong param_count=0;
|
||||||
|
uchar *pos=(uchar*)net->read_pos+1;// skip command type
|
||||||
|
|
||||||
|
if(*pos++) // No types supplied, read only param data
|
||||||
|
{
|
||||||
|
while ((item_param=(Item_param *)it++) &&
|
||||||
|
(param_count++ < thd->param_count))
|
||||||
|
{
|
||||||
|
if (item_param->long_data_supplied)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(pos=setup_param_field(item_param,pos,item_param->buffer_type)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Types supplied, read and store it along with param data
|
||||||
|
{
|
||||||
|
while ((item_param=(Item_param *)it++) &&
|
||||||
|
(param_count++ < thd->param_count))
|
||||||
|
{
|
||||||
|
if (item_param->long_data_supplied)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(pos=setup_param_field(item_param,pos,
|
||||||
|
item_param->buffer_type=(enum_field_types)get_buffer_type(&pos))))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Buffer the long data and update the flags
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void setup_longdata_field(Item_param *item_param, uchar *pos)
|
||||||
|
{
|
||||||
|
ulong len;
|
||||||
|
|
||||||
|
if (!*pos++)
|
||||||
|
item_param->buffer_type=(enum_field_types)get_buffer_type(&pos);
|
||||||
|
|
||||||
|
if (*pos == MYSQL_LONG_DATA_END)
|
||||||
|
item_param->set_long_end();
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = get_param_length(&pos);
|
||||||
|
item_param->set_longdata((const char *)pos, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Store the long data from client in pieces
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool setup_longdata(THD *thd, List<Item> ¶ms)
|
||||||
|
{
|
||||||
|
NET *net=&thd->net;
|
||||||
|
List_iterator<Item> it(params);
|
||||||
|
DBUG_ENTER("setup_longdata");
|
||||||
|
|
||||||
|
uchar *pos=(uchar*)net->read_pos+1;// skip command type at first position
|
||||||
|
ulong param_number = get_param_length(&pos);
|
||||||
|
Item_param *item_param = thd->current_param;
|
||||||
|
|
||||||
|
if (thd->current_param_number != param_number)
|
||||||
|
{
|
||||||
|
thd->current_param_number = param_number;
|
||||||
|
while (param_number--) /* TODO:
|
||||||
|
Change this loop by either having operator '+'
|
||||||
|
overloaded to point to desired 'item' or
|
||||||
|
add another memeber in list as 'goto' with
|
||||||
|
location count as parameter number, but what
|
||||||
|
is the best way to traverse ?
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
thd->current_param = item_param = (Item_param *)it++;
|
||||||
|
}
|
||||||
|
setup_longdata_field(item_param,pos);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validates insert fields
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields,
|
||||||
|
List<Item> &values, ulong counter)
|
||||||
|
{
|
||||||
|
if (fields.elements == 0 && values.elements != 0)
|
||||||
|
{
|
||||||
|
if (values.elements != table->fields)
|
||||||
|
{
|
||||||
|
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
|
||||||
|
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
|
||||||
|
MYF(0),counter);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fields.elements != values.elements)
|
||||||
|
{
|
||||||
|
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
|
||||||
|
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
|
||||||
|
MYF(0),counter);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
TABLE_LIST table_list;
|
||||||
|
bzero((char*) &table_list,sizeof(table_list));
|
||||||
|
table_list.name=table->table_name;
|
||||||
|
table_list.table=table;
|
||||||
|
table_list.grant=table->grant;
|
||||||
|
|
||||||
|
thd->dupp_field=0;
|
||||||
|
if (setup_tables(&table_list) ||
|
||||||
|
setup_fields(thd,&table_list,fields,1,0,0))
|
||||||
|
return -1;
|
||||||
|
if (thd->dupp_field)
|
||||||
|
{
|
||||||
|
my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate the following information for INSERT statement:
|
||||||
|
- field existance
|
||||||
|
- fields count
|
||||||
|
|
||||||
|
If there is no column list spec exists, then update the field_list
|
||||||
|
with all columns from the table, and send fields info back to client
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list,
|
||||||
|
List<Item> &fields,
|
||||||
|
List<List_item> &values_list,
|
||||||
|
thr_lock_type lock_type)
|
||||||
|
{
|
||||||
|
TABLE *table;
|
||||||
|
List_iterator_fast<List_item> its(values_list);
|
||||||
|
List_item *values;
|
||||||
|
DBUG_ENTER("mysql_test_insert_fields");
|
||||||
|
|
||||||
|
if (!(table = open_ltable(thd,table_list,lock_type)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
if ((values= its++))
|
||||||
|
{
|
||||||
|
uint value_count;
|
||||||
|
ulong counter=0;
|
||||||
|
|
||||||
|
if (check_insert_fields(thd,table,fields,*values,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
value_count= values->elements;
|
||||||
|
its.rewind();
|
||||||
|
|
||||||
|
while ((values = its++))
|
||||||
|
{
|
||||||
|
counter++;
|
||||||
|
if (values->elements != value_count)
|
||||||
|
{
|
||||||
|
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
|
||||||
|
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
|
||||||
|
MYF(0),counter);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fields.elements == 0)
|
||||||
|
{
|
||||||
|
/* No field listing, so setup all fields */
|
||||||
|
List<Item> all_fields;
|
||||||
|
Field **ptr,*field;
|
||||||
|
for (ptr=table->field; (field= *ptr) ; ptr++)
|
||||||
|
{
|
||||||
|
all_fields.push_back(new Item_field(table->table_cache_key,
|
||||||
|
table->real_name,
|
||||||
|
field->field_name));
|
||||||
|
}
|
||||||
|
if ((setup_fields(thd,table_list,all_fields,1,0,0) ||
|
||||||
|
send_fields(thd,all_fields,1)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
else if (send_fields(thd,fields,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate the following information
|
||||||
|
UPDATE - set and where clause DELETE - where clause
|
||||||
|
|
||||||
|
And send update-set cluase column list fields info
|
||||||
|
back to client. For DELETE, just validate where cluase
|
||||||
|
and return no fields information back to client.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list,
|
||||||
|
List<Item> &fields, List<Item> &values,
|
||||||
|
COND *conds, thr_lock_type lock_type)
|
||||||
|
{
|
||||||
|
TABLE *table;
|
||||||
|
DBUG_ENTER("mysql_test_upd_fields");
|
||||||
|
|
||||||
|
if (!(table = open_ltable(thd,table_list,lock_type)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) ||
|
||||||
|
setup_conds(thd,table_list,&conds))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Currently return only column list info only, and we are not
|
||||||
|
sending any info on where clause.
|
||||||
|
*/
|
||||||
|
if (fields.elements && send_fields(thd,fields,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate the following information:
|
||||||
|
|
||||||
|
SELECT - column list
|
||||||
|
- where clause
|
||||||
|
- orderr clause
|
||||||
|
- having clause
|
||||||
|
- group by clause
|
||||||
|
- if no column spec i.e. '*', then setup all fields
|
||||||
|
|
||||||
|
And send column list fields info back to client.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables,
|
||||||
|
List<Item> &fields, List<Item> &values,
|
||||||
|
COND *conds, ORDER *order, ORDER *group,
|
||||||
|
Item *having,thr_lock_type lock_type)
|
||||||
|
{
|
||||||
|
TABLE *table;
|
||||||
|
bool hidden_group_fields;
|
||||||
|
List<Item> all_fields(fields);
|
||||||
|
DBUG_ENTER("mysql_test_select_fields");
|
||||||
|
|
||||||
|
if (!(table = open_ltable(thd,tables,lock_type)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
thd->used_tables=0; // Updated by setup_fields
|
||||||
|
if (setup_tables(tables) ||
|
||||||
|
setup_fields(thd,tables,fields,1,&all_fields,1) ||
|
||||||
|
setup_conds(thd,tables,&conds) ||
|
||||||
|
setup_order(thd,tables,fields,all_fields,order) ||
|
||||||
|
setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
if (having)
|
||||||
|
{
|
||||||
|
thd->where="having clause";
|
||||||
|
thd->allow_sum_func=1;
|
||||||
|
if (having->fix_fields(thd,tables) || thd->fatal_error)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
if (having->with_sum_func)
|
||||||
|
having->split_sum_func(all_fields);
|
||||||
|
}
|
||||||
|
if (setup_ftfuncs(thd))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Currently return only column list info only, and we are not
|
||||||
|
sending any info on where clause.
|
||||||
|
*/
|
||||||
|
if (fields.elements && send_fields(thd,fields,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check the access privileges
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool check_prepare_access(THD *thd, TABLE_LIST *tables,
|
||||||
|
uint type)
|
||||||
|
{
|
||||||
|
if (check_access(thd,type,tables->db,&tables->grant.privilege))
|
||||||
|
return 1;
|
||||||
|
if (grant_option && check_grant(thd,type,tables))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Send the prepare query results back to client
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void send_prepare_results(THD *thd)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("send_prepare_results");
|
||||||
|
enum enum_sql_command sql_command = thd->lex.sql_command;
|
||||||
|
|
||||||
|
DBUG_PRINT("enter",("command :%d, param_count :%ld",
|
||||||
|
sql_command,thd->param_count));
|
||||||
|
|
||||||
|
LEX *lex=&thd->lex;
|
||||||
|
SELECT_LEX *select_lex = lex->select;
|
||||||
|
TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
|
||||||
|
|
||||||
|
switch(sql_command) {
|
||||||
|
|
||||||
|
case SQLCOM_INSERT:
|
||||||
|
if (mysql_test_insert_fields(thd,tables, lex->field_list,
|
||||||
|
lex->many_values, lex->lock_option))
|
||||||
|
goto abort;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_UPDATE:
|
||||||
|
if (mysql_test_upd_fields(thd,tables, select_lex->item_list,
|
||||||
|
lex->value_list, select_lex->where,
|
||||||
|
lex->lock_option))
|
||||||
|
goto abort;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_DELETE:
|
||||||
|
if (mysql_test_upd_fields(thd,tables, select_lex->item_list,
|
||||||
|
lex->value_list, select_lex->where,
|
||||||
|
lex->lock_option))
|
||||||
|
goto abort;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_SELECT:
|
||||||
|
if (mysql_test_select_fields(thd,tables, select_lex->item_list,
|
||||||
|
lex->value_list, select_lex->where,
|
||||||
|
(ORDER*) select_lex->order_list.first,
|
||||||
|
(ORDER*) select_lex->group_list.first,
|
||||||
|
select_lex->having, lex->lock_option))
|
||||||
|
goto abort;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Rest fall through to default category, no parsing
|
||||||
|
for non-DML statements
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send_ok(&thd->net,thd->param_count,0);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Parse the prepare query
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void mysql_parse_prepare_query(THD *thd, char *packet, uint length)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mysql_parse_prepare_query");
|
||||||
|
|
||||||
|
mysql_log.write(thd,COM_PREPARE,"%s",packet);
|
||||||
|
mysql_init_query(thd);
|
||||||
|
thd->prepare_command=true;
|
||||||
|
|
||||||
|
if (query_cache.send_result_to_client(thd, packet, length) <= 0)
|
||||||
|
{
|
||||||
|
LEX *lex=lex_start(thd, (uchar*)packet, length);
|
||||||
|
|
||||||
|
if (!yyparse() && !thd->fatal_error)
|
||||||
|
{
|
||||||
|
send_prepare_results(thd);
|
||||||
|
query_cache_end_of_result(&thd->net);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
query_cache_abort(&thd->net);
|
||||||
|
lex_end(lex);
|
||||||
|
}
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Parse the query and send the total number of parameters
|
||||||
|
and resultset metadata information back to client (if any),
|
||||||
|
without executing the query i.e. with out any log/disk
|
||||||
|
writes. This will allow the queries to be re-executed
|
||||||
|
without re-parsing during execute.
|
||||||
|
|
||||||
|
If parameter markers are found in the query, then store
|
||||||
|
the information using Item_param along with maintaining a
|
||||||
|
list in lex->param_list, so that a fast and direct
|
||||||
|
retrieveal can be made without going through all field
|
||||||
|
items.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mysql_com_prepare(THD *thd, char *packet, uint packet_length)
|
||||||
|
{
|
||||||
|
MEM_ROOT thd_root = thd->mem_root;
|
||||||
|
DBUG_ENTER("mysql_com_prepare");
|
||||||
|
|
||||||
|
packet_length--;
|
||||||
|
|
||||||
|
while (isspace(packet[0]) && packet_length > 0)
|
||||||
|
{
|
||||||
|
packet++;
|
||||||
|
packet_length--;
|
||||||
|
}
|
||||||
|
char *pos=packet+packet_length;
|
||||||
|
while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
|
||||||
|
{
|
||||||
|
pos--;
|
||||||
|
packet_length--;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Have the prepare items to have a connection level scope or
|
||||||
|
till next prepare statement by doing all allocations using
|
||||||
|
connection level memory allocator 'con_root' from THD.
|
||||||
|
*/
|
||||||
|
free_root(&thd->con_root,MYF(0));
|
||||||
|
init_sql_alloc(&thd->con_root,8192,8192);
|
||||||
|
thd->mem_root = thd->con_root;
|
||||||
|
|
||||||
|
if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
|
||||||
|
packet_length,
|
||||||
|
thd->db_length+2)))
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
thd->query[packet_length]=0;
|
||||||
|
thd->packet.shrink(net_buffer_length);
|
||||||
|
thd->query_length = packet_length;
|
||||||
|
|
||||||
|
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||||
|
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
||||||
|
|
||||||
|
mysql_parse_prepare_query(thd,thd->query,packet_length);
|
||||||
|
|
||||||
|
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||||
|
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
|
||||||
|
|
||||||
|
thd->mem_root = thd_root; // restore main mem_root
|
||||||
|
DBUG_PRINT("exit",("prepare query ready"));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Executes previously prepared query
|
||||||
|
|
||||||
|
If there is any parameters(thd->param_count), then replace
|
||||||
|
markers with the data supplied from client, and then
|
||||||
|
execute the query
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mysql_com_execute(THD *thd)
|
||||||
|
{
|
||||||
|
MEM_ROOT thd_root=thd->mem_root;
|
||||||
|
DBUG_ENTER("mysql_com_execute");
|
||||||
|
DBUG_PRINT("enter", ("parameters : %ld", thd->param_count));
|
||||||
|
|
||||||
|
thd->mem_root = thd->con_root;
|
||||||
|
if (thd->param_count && setup_param_fields(thd, thd->lex.param_list))
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
|
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||||
|
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
Also, have checks on basic executions such as mysql_insert(),
|
||||||
|
mysql_delete(), mysql_update() and mysql_select() to not to
|
||||||
|
have re-check on setup_* and other things ..
|
||||||
|
*/
|
||||||
|
mysql_execute_command();
|
||||||
|
|
||||||
|
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||||
|
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
|
||||||
|
|
||||||
|
thd->mem_root = (MEM_ROOT )thd_root;
|
||||||
|
DBUG_PRINT("exit",("prepare-execute done!"));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Long data in pieces from client
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mysql_com_longdata(THD *thd)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mysql_com_execute");
|
||||||
|
|
||||||
|
if(thd->param_count && setup_longdata(thd,thd->lex.param_list))
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
|
send_ok(&thd->net,0,0);// ok status to client
|
||||||
|
DBUG_PRINT("exit",("longdata-buffering done!"));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
@ -126,8 +126,6 @@ static bool store_record_in_cache(JOIN_CACHE *cache);
|
|||||||
static void reset_cache(JOIN_CACHE *cache);
|
static void reset_cache(JOIN_CACHE *cache);
|
||||||
static void read_cached_record(JOIN_TAB *tab);
|
static void read_cached_record(JOIN_TAB *tab);
|
||||||
static bool cmp_buffer_with_ref(JOIN_TAB *tab);
|
static bool cmp_buffer_with_ref(JOIN_TAB *tab);
|
||||||
static int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
|
||||||
List<Item> &all_fields, ORDER *order, bool *hidden);
|
|
||||||
static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
||||||
List<Item> &all_fields,ORDER *new_order);
|
List<Item> &all_fields,ORDER *new_order);
|
||||||
static ORDER *create_distinct_group(ORDER *order, List<Item> &fields);
|
static ORDER *create_distinct_group(ORDER *order, List<Item> &fields);
|
||||||
@ -6456,7 +6454,7 @@ int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
int
|
||||||
setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
||||||
List<Item> &all_fields, ORDER *order, bool *hidden_group_fields)
|
List<Item> &all_fields, ORDER *order, bool *hidden_group_fields)
|
||||||
{
|
{
|
||||||
|
195
sql/sql_show.cc
195
sql/sql_show.cc
@ -169,6 +169,201 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** List all table types supported
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
static struct show_table_type_st sys_table_types[]= {
|
||||||
|
{"MyISAM", (char *)"YES", "Default type from 3.23 with great performance"},
|
||||||
|
{"HEAP" , (char *)"YES", "Hash based, stored in memory, useful for temporary tables"},
|
||||||
|
{"MERGE", (char *)"YES", "Collection of identical MyISAM tables"},
|
||||||
|
{"ISAM", (char*) &have_isam,"Obsolete table type"},
|
||||||
|
{"InnoDB", (char*) &have_innodb,"Supports transactions, row-level locking and foreign keys"},
|
||||||
|
{"BDB", (char*) &have_berkeley_db, "Supports transactions and page-level locking"},
|
||||||
|
};
|
||||||
|
|
||||||
|
int mysqld_show_table_types(THD *thd)
|
||||||
|
{
|
||||||
|
List<Item> field_list;
|
||||||
|
DBUG_ENTER("mysqld_show_table_types");
|
||||||
|
|
||||||
|
field_list.push_back(new Item_empty_string("Type",10));
|
||||||
|
field_list.push_back(new Item_empty_string("Support",10));
|
||||||
|
field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
|
||||||
|
|
||||||
|
if (send_fields(thd,field_list,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
const char *default_type_name=ha_table_typelib.type_names[default_table_type-1];
|
||||||
|
show_table_type_st *types = sys_table_types;
|
||||||
|
|
||||||
|
uint i;
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,types[i].type);
|
||||||
|
if (!strcasecmp(default_type_name,types[i].type))
|
||||||
|
net_store_data(&thd->packet,"DEFAULT");
|
||||||
|
else
|
||||||
|
net_store_data(&thd->packet,types[i].value);
|
||||||
|
net_store_data(&thd->packet,types[i].comment);
|
||||||
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < sizeof(sys_table_types)/sizeof(sys_table_types[0]); i++)
|
||||||
|
{
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,types[i].type);
|
||||||
|
SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) types[i].value;
|
||||||
|
|
||||||
|
if (tmp == SHOW_OPTION_NO)
|
||||||
|
net_store_data(&thd->packet,"NO");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tmp == SHOW_OPTION_YES)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(default_type_name,types[i].type))
|
||||||
|
net_store_data(&thd->packet,"DEFAULT");
|
||||||
|
else
|
||||||
|
net_store_data(&thd->packet,"YES");
|
||||||
|
}
|
||||||
|
else net_store_data(&thd->packet,"DISABLED");
|
||||||
|
}
|
||||||
|
net_store_data(&thd->packet,types[i].comment);
|
||||||
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
send_eof(&thd->net);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** List all privileges supported
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
static struct show_table_type_st sys_privileges[]= {
|
||||||
|
{"Select", (char *)"Tables", "To retrieve rows from table"},
|
||||||
|
{"Insert", (char *)"Tables", "To insert data into tables"},
|
||||||
|
{"Update", (char *)"Tables", "To update existing rows "},
|
||||||
|
{"Delete", (char *)"Tables", "To delete existing rows"},
|
||||||
|
{"Index", (char *)"Tables", "To create or drop indexes"},
|
||||||
|
{"Alter", (char *)"Tables", "To alter the table"},
|
||||||
|
{"Create", (char *)"Databases,Tables,Indexes", "To create new databases and tables"},
|
||||||
|
{"Drop", (char *)"Databases,Tables", "To drop databases and tables"},
|
||||||
|
{"Grant", (char *)"Databases,Tables", "To give to other users those privileges you possesed"},
|
||||||
|
{"References", (char *)"Databases,Tables", "To have references on tables"},
|
||||||
|
{"Reload", (char *)"Server Admin", "To reload or refresh tables, logs and privileges"},
|
||||||
|
{"Shutdown",(char *)"Server Admin", "To shutdown the server"},
|
||||||
|
{"Process", (char *)"Server Admin", "To view the plain text of currently executing queries"},
|
||||||
|
{"File", (char *)"File access on server", "To read and write files on the server"},
|
||||||
|
};
|
||||||
|
|
||||||
|
int mysqld_show_privileges(THD *thd)
|
||||||
|
{
|
||||||
|
List<Item> field_list;
|
||||||
|
DBUG_ENTER("mysqld_show_privileges");
|
||||||
|
|
||||||
|
field_list.push_back(new Item_empty_string("Privilege",10));
|
||||||
|
field_list.push_back(new Item_empty_string("Context",15));
|
||||||
|
field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
|
||||||
|
|
||||||
|
if (send_fields(thd,field_list,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
for (uint i=0; i < sizeof(sys_privileges)/sizeof(sys_privileges[0]); i++)
|
||||||
|
{
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,sys_privileges[i].type);
|
||||||
|
net_store_data(&thd->packet,sys_privileges[i].value);
|
||||||
|
net_store_data(&thd->packet,sys_privileges[i].comment);
|
||||||
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
send_eof(&thd->net);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** List all column types
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
struct show_column_type_st {
|
||||||
|
const char *type;
|
||||||
|
uint size;
|
||||||
|
char *min_value;
|
||||||
|
char *max_value;
|
||||||
|
uint precision,
|
||||||
|
uint scale,
|
||||||
|
char *nullable;
|
||||||
|
char *auto_increment;
|
||||||
|
char *unsigned_attr;
|
||||||
|
char *zerofill;
|
||||||
|
char *searchable;
|
||||||
|
char *case_sensitivity;
|
||||||
|
char *default_value;
|
||||||
|
char *comment;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
static struct show_column_type_st sys_column_types[]= {
|
||||||
|
{"tinyint",
|
||||||
|
1, "-128", "127", 0, 0, "YES", "YES",
|
||||||
|
"NO", "YES", "YES", "NO", "NULL,0",
|
||||||
|
"A very small integer"},
|
||||||
|
{"tinyint unsigned",
|
||||||
|
1, "0" , "255", 0, 0, "YES", "YES",
|
||||||
|
"YES", "YES", "YES", "NO", "NULL,0",
|
||||||
|
"A very small integer"},
|
||||||
|
};
|
||||||
|
|
||||||
|
int mysqld_show_column_types(THD *thd)
|
||||||
|
{
|
||||||
|
List<Item> field_list;
|
||||||
|
DBUG_ENTER("mysqld_show_column_types");
|
||||||
|
|
||||||
|
field_list.push_back(new Item_empty_string("Type",30));
|
||||||
|
field_list.push_back(new Item_int("Size",(longlong) 1,21));
|
||||||
|
field_list.push_back(new Item_empty_string("Min_Value",20));
|
||||||
|
field_list.push_back(new Item_empty_string("Max_Value",20));
|
||||||
|
field_list.push_back(new Item_int("Prec", 0,4));
|
||||||
|
field_list.push_back(new Item_int("Scale", 0,4));
|
||||||
|
field_list.push_back(new Item_empty_string("Nullable",4));
|
||||||
|
field_list.push_back(new Item_empty_string("Auto_Increment",4));
|
||||||
|
field_list.push_back(new Item_empty_string("Unsigned",4));
|
||||||
|
field_list.push_back(new Item_empty_string("Zerofill",4));
|
||||||
|
field_list.push_back(new Item_empty_string("Searchable",4));
|
||||||
|
field_list.push_back(new Item_empty_string("Case_Sensitive",4));
|
||||||
|
field_list.push_back(new Item_empty_string("Default",NAME_LEN));
|
||||||
|
field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
|
||||||
|
|
||||||
|
if (send_fields(thd,field_list,1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
|
||||||
|
{
|
||||||
|
thd->packet.length(0);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].type);
|
||||||
|
net_store_data(&thd->packet,(longlong)sys_column_types[i].size);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].min_value);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].max_value);
|
||||||
|
net_store_data(&thd->packet,(uint32)sys_column_types[i].precision);
|
||||||
|
net_store_data(&thd->packet,(uint32)sys_column_types[i].scale);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].nullable);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].auto_increment);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].unsigned_attr);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].zerofill);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].searchable);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].case_sensitivity);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].default_value);
|
||||||
|
net_store_data(&thd->packet,sys_column_types[i].comment);
|
||||||
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
send_eof(&thd->net);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
|
mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
|
||||||
|
@ -324,6 +324,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token TRAILING
|
%token TRAILING
|
||||||
%token TRANSACTION_SYM
|
%token TRANSACTION_SYM
|
||||||
%token TYPE_SYM
|
%token TYPE_SYM
|
||||||
|
%token TYPES_SYM
|
||||||
%token FUNC_ARG0
|
%token FUNC_ARG0
|
||||||
%token FUNC_ARG1
|
%token FUNC_ARG1
|
||||||
%token FUNC_ARG2
|
%token FUNC_ARG2
|
||||||
@ -346,6 +347,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token X509_SYM
|
%token X509_SYM
|
||||||
%token COMPRESSED_SYM
|
%token COMPRESSED_SYM
|
||||||
|
|
||||||
|
%token ERRORS
|
||||||
|
%token SQL_ERROR_COUNT
|
||||||
|
%token WARNINGS
|
||||||
|
%token SQL_WARNING_COUNT
|
||||||
|
|
||||||
%token BIGINT
|
%token BIGINT
|
||||||
%token BLOB_SYM
|
%token BLOB_SYM
|
||||||
%token CHAR_SYM
|
%token CHAR_SYM
|
||||||
@ -548,7 +554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
literal text_literal insert_ident order_ident
|
literal text_literal insert_ident order_ident
|
||||||
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
|
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
|
||||||
table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
|
table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
|
||||||
using_list subselect subselect_init
|
using_list param_marker subselect subselect_init
|
||||||
|
|
||||||
%type <item_list>
|
%type <item_list>
|
||||||
expr_list udf_expr_list when_list ident_list ident_list_arg
|
expr_list udf_expr_list when_list ident_list ident_list_arg
|
||||||
@ -1720,6 +1726,7 @@ no_and_expr:
|
|||||||
simple_expr:
|
simple_expr:
|
||||||
simple_ident
|
simple_ident
|
||||||
| literal
|
| literal
|
||||||
|
| param_marker
|
||||||
| '@' ident_or_text SET_VAR expr
|
| '@' ident_or_text SET_VAR expr
|
||||||
{ $$= new Item_func_set_user_var($2,$4);
|
{ $$= new Item_func_set_user_var($2,$4);
|
||||||
current_thd->safe_to_cache_query=0;
|
current_thd->safe_to_cache_query=0;
|
||||||
@ -2795,6 +2802,29 @@ show_param:
|
|||||||
if (!add_table_to_list($3,NULL,0))
|
if (!add_table_to_list($3,NULL,0))
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
|
| COLUMN_SYM TYPES_SYM
|
||||||
|
{
|
||||||
|
LEX *lex=Lex;
|
||||||
|
lex->sql_command= SQLCOM_SHOW_COLUMN_TYPES;
|
||||||
|
}
|
||||||
|
| TABLE_SYM TYPES_SYM
|
||||||
|
{
|
||||||
|
LEX *lex=Lex;
|
||||||
|
lex->sql_command= SQLCOM_SHOW_TABLE_TYPES;
|
||||||
|
}
|
||||||
|
| PRIVILEGES
|
||||||
|
{
|
||||||
|
LEX *lex=Lex;
|
||||||
|
lex->sql_command= SQLCOM_SHOW_PRIVILEGES;
|
||||||
|
}
|
||||||
|
| COUNT_SYM '(' '*' ')' WARNINGS
|
||||||
|
{ Lex->sql_command = SQLCOM_SHOW_WARNS_COUNT;}
|
||||||
|
| COUNT_SYM '(' '*' ')' ERRORS
|
||||||
|
{ Lex->sql_command = SQLCOM_SHOW_ERRORS_COUNT;}
|
||||||
|
| WARNINGS {Select->offset_limit=0L;} limit_clause
|
||||||
|
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
|
||||||
|
| ERRORS {Select->offset_limit=0L;} limit_clause
|
||||||
|
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
|
||||||
| STATUS_SYM wild
|
| STATUS_SYM wild
|
||||||
{ Lex->sql_command= SQLCOM_SHOW_STATUS; }
|
{ Lex->sql_command= SQLCOM_SHOW_STATUS; }
|
||||||
| opt_full PROCESSLIST_SYM
|
| opt_full PROCESSLIST_SYM
|
||||||
@ -3055,7 +3085,20 @@ text_string:
|
|||||||
Item *tmp = new Item_varbinary($1.str,$1.length,default_charset_info);
|
Item *tmp = new Item_varbinary($1.str,$1.length,default_charset_info);
|
||||||
$$= tmp ? tmp->val_str((String*) 0) : (String*) 0;
|
$$= tmp ? tmp->val_str((String*) 0) : (String*) 0;
|
||||||
};
|
};
|
||||||
|
param_marker:
|
||||||
|
'?'
|
||||||
|
{
|
||||||
|
if(current_thd->prepare_command)
|
||||||
|
{
|
||||||
|
Lex->param_list.push_back($$=new Item_param());
|
||||||
|
current_thd->param_count++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yyerror("You have an error in your SQL syntax");
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
literal:
|
literal:
|
||||||
text_literal { $$ = $1; }
|
text_literal { $$ = $1; }
|
||||||
| NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); }
|
| NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); }
|
||||||
@ -3411,6 +3454,16 @@ option_value:
|
|||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
| SQL_QUERY_CACHE_TYPE_SYM equal query_cache_type
|
| SQL_QUERY_CACHE_TYPE_SYM equal query_cache_type
|
||||||
|
| SQL_ERROR_COUNT equal ULONG_NUM
|
||||||
|
{
|
||||||
|
LEX *lex = Lex;
|
||||||
|
lex->thd->max_error_count = $3;
|
||||||
|
}
|
||||||
|
| SQL_WARNING_COUNT equal ULONG_NUM
|
||||||
|
{
|
||||||
|
LEX *lex = Lex;
|
||||||
|
lex->thd->max_warning_count = $3;
|
||||||
|
}
|
||||||
| '@' ident_or_text equal expr
|
| '@' ident_or_text equal expr
|
||||||
{
|
{
|
||||||
Item_func_set_user_var *item = new Item_func_set_user_var($2,$4);
|
Item_func_set_user_var *item = new Item_func_set_user_var($2,$4);
|
||||||
|
@ -152,6 +152,29 @@ struct show_var_st {
|
|||||||
SHOW_TYPE type;
|
SHOW_TYPE type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct show_table_type_st {
|
||||||
|
const char *type;
|
||||||
|
char *value;
|
||||||
|
const char *comment;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct show_column_type_st {
|
||||||
|
const char *type;
|
||||||
|
uint size;
|
||||||
|
const char *min_value;
|
||||||
|
const char *max_value;
|
||||||
|
uint precision;
|
||||||
|
uint scale;
|
||||||
|
const char *nullable;
|
||||||
|
const char *auto_increment;
|
||||||
|
const char *unsigned_attr;
|
||||||
|
const char *zerofill;
|
||||||
|
const char *searchable;
|
||||||
|
const char *case_sensitivity;
|
||||||
|
const char *default_value;
|
||||||
|
const char *comment;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct lex_string {
|
typedef struct lex_string {
|
||||||
char *str;
|
char *str;
|
||||||
uint length;
|
uint length;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user