summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/Makefile.am1
-rw-r--r--sql/field.cc8
-rw-r--r--sql/field.h4
-rw-r--r--sql/item.cc139
-rw-r--r--sql/item.h34
-rw-r--r--sql/item_sum.cc5
-rw-r--r--sql/lex.h4
-rw-r--r--sql/mysql_priv.h28
-rw-r--r--sql/net_pkg.cc11
-rw-r--r--sql/sql_base.cc188
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_class.h36
-rw-r--r--sql/sql_error.cc219
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.h7
-rw-r--r--sql/sql_list.h121
-rw-r--r--sql/sql_parse.cc54
-rw-r--r--sql/sql_prepare.cc709
-rw-r--r--sql/sql_select.cc4
-rw-r--r--sql/sql_show.cc195
-rw-r--r--sql/sql_yacc.yy57
-rw-r--r--sql/structs.h23
22 files changed, 1794 insertions, 58 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index bd626ea10b7..81fe927ce5a 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -67,6 +67,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
mysqld.cc password.c hash_filo.cc hostname.cc \
convert.cc sql_parse.cc sql_yacc.yy \
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 \
procedure.cc item_uniq.cc sql_test.cc \
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
diff --git a/sql/field.cc b/sql/field.cc
index 1561f1831de..8b1073d32f3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -279,8 +279,10 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
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->col_name=field_name;
+ field->col_name=field->org_col_name=field_name;
field->length=field_length;
field->type=type();
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)
{
+ field->db_name=table->table_cache_key ? table->table_cache_key : "";
+ field->org_table_name=table->real_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->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
diff --git a/sql/field.h b/sql/field.h
index f84b54271ce..5b9723654d9 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1038,7 +1038,9 @@ public:
class Send_field {
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;
enum_field_types type;
Send_field() {}
diff --git a/sql/item.cc b/sql/item.cc
index 45564bcd98e..d01a06e5eba 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -287,6 +287,140 @@ String *Item_null::val_str(String *str)
{ 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()
{
String *res=item->val_str(&str_value);
@@ -373,7 +507,10 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
void Item::init_make_field(Send_field *tmp_field,
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->col_name=name;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
diff --git a/sql/item.h b/sql/item.h
index 8e8b44a5006..e6debdf2afc 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -155,6 +155,40 @@ public:
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
{
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index a1ffae2ed82..6ef968c33f7 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -60,8 +60,9 @@ void Item_sum::make_field(Send_field *tmp_field)
result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE :
FIELD_TYPE_VAR_STRING);
}
- tmp_field->table_name=(char*)"";
- tmp_field->col_name=name;
+ tmp_field->db_name=(char*)"";
+ 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)
diff --git a/sql/lex.h b/sql/lex.h
index dd1a69f9c83..da0a71a135e 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -129,6 +129,7 @@ static SYMBOL symbols[] = {
{ "DROP", SYM(DROP),0,0},
{ "DUMPFILE", SYM(DUMPFILE),0,0},
{ "DYNAMIC", SYM(DYNAMIC_SYM),0,0},
+ { "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),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_CACHE", SYM(SQL_CACHE_SYM), 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_OFF", SYM(SQL_LOG_OFF),0,0},
{ "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0},
@@ -366,6 +368,7 @@ static SYMBOL symbols[] = {
{ "TRUNCATE", SYM(TRUNCATE_SYM),0,0},
{ "TO", SYM(TO_SYM),0,0},
{ "TYPE", SYM(TYPE_SYM),0,0},
+ { "TYPES", SYM(TYPES_SYM),0,0},
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM),0,0},
{ "UNION", SYM(UNION_SYM),0,0},
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
@@ -381,6 +384,7 @@ static SYMBOL symbols[] = {
{ "VARIABLES", SYM(VARIABLES),0,0},
{ "VARYING", SYM(VARYING),0,0},
{ "VARBINARY", SYM(VARBINARY),0,0},
+ { "WARNINGS", SYM(WARNINGS),0,0},
{ "WITH", SYM(WITH),0,0},
{ "WORK", SYM(WORK_SYM),0,0},
{ "WRITE", SYM(WRITE_SYM),0,0},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 268a452095e..011b7823dd0 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -287,6 +287,8 @@ inline THD *_current_thd(void)
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
#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_rm_db(THD *thd,char *db,bool if_exists, bool silent);
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);
int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
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 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 */
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_open_tables(THD *thd,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(THD *thd, const char *wild, show_var_st *variables);
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 */
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 struct show_var_st init_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 enum_tx_isolation default_tx_isolation;
extern char glob_hostname[FN_REFLEN];
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
index a201651fc2f..fa3abc68bfa 100644
--- a/sql/net_pkg.cc
+++ b/sql/net_pkg.cc
@@ -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 (thd && thd->bootstrap)
@@ -82,7 +83,14 @@ void send_error(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);
DBUG_VOID_RETURN;
}
@@ -123,6 +131,7 @@ net_printf(NET *net, uint errcode, ...)
length=sizeof(net->last_error)-1; /* purecov: inspected */
va_end(args);
+ push_error(errcode, text_pos);
if (net->vio == 0)
{
if (thd && thd->bootstrap)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index c9ef64b6da9..92606716c63 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -179,56 +179,58 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
DBUG_RETURN(open_list);
}
-
-/******************************************************************************
-** 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
-******************************************************************************/
+/*
+ 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)
+send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag)
{
List_iterator_fast<Item> it(list);
Item *item;
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 *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++))
{
char *pos;
Send_field field;
item->make_field(&field);
+
packet->length(0);
- if (convert)
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
- if (convert->store(packet,field.table_name,
+ 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))
- goto err;
+ return 1;
+ }
+ else
+ {
+ if (convert->store(packet,field.table_name,
+ (uint) strlen(field.table_name)) ||
+ convert->store(packet,field.col_name,
+ (uint) strlen(field.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))
- goto err; /* purecov: inspected */
+
pos= (char*) packet->ptr()+packet->length();
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 (net_store_null(packet))
- goto err;
+ return 1;
}
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()))
break; /* purecov: inspected */
}
- send_eof(&thd->net,1);
- DBUG_RETURN(0);
- err:
+ 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 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 */
- DBUG_RETURN(1); /* purecov: inspected */
+ return 1; /* purecov: inspected */
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 86e4e6896e6..f91c508e8af 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -140,6 +140,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
command=COM_CONNECT;
set_query_id=1;
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 :
HA_POS_ERROR);
db_access=NO_ACCESS;
@@ -147,6 +148,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
/* Initialize sub structures */
bzero((char*) &mem_root,sizeof(mem_root));
bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
+ bzero((char*) &con_root,sizeof(con_root));
user_connect=(USER_CONN *)0;
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
@@ -223,6 +225,7 @@ THD::~THD()
safeFree(db);
safeFree(ip);
free_root(&mem_root,MYF(0));
+ free_root(&con_root,MYF(0));
free_root(&transaction.mem_root,MYF(0));
mysys_var=0; // Safety (shouldn't be needed)
#ifdef SIGNAL_WITH_VIO_CLOSE
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8a1a299ceee..016df485245 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -289,7 +289,30 @@ public:
i_string_pair():key(0),val(0) { }
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;
@@ -308,6 +331,7 @@ public:
NET net; // client connection descriptor
LEX lex; // parse tree descriptor
MEM_ROOT mem_root; // 1 command-life memory
+ MEM_ROOT con_root; // connection-life memory
HASH user_vars; // hash for user variables
String packet; // buffer used for network I/O
struct sockaddr_in remote; // client socket address
@@ -410,7 +434,8 @@ public:
max_join_size, sent_row_count, examined_row_count;
table_map used_tables;
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;
pthread_t real_id;
uint current_tablenr,tmp_table,cond_count,col_access;
@@ -428,8 +453,13 @@ public:
bool query_error, bootstrap, cleanup_done;
bool safe_to_cache_query;
bool volatile killed;
- // TRUE when having fix field called
- bool having_fix_field;
+ bool having_fix_field; //TRUE when having fix field called
+ 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
that are currently reading it needs to be adjusted. To do that
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
new file mode 100644
index 00000000000..13466f454c5
--- /dev/null
+++ b/sql/sql_error.cc
@@ -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);
+}
+
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c181e299d05..c3aeca1fff8 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -44,7 +44,7 @@ static void unlink_blobs(register TABLE *table);
Resets form->time_stamp if a timestamp value is set
*/
-static int
+int
check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
List<Item> &values, ulong counter)
{
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index ee0209f9329..ca824b3eab8 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -57,8 +57,10 @@ enum enum_sql_command {
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
- SQLCOM_EMPTY_QUERY,
- SQLCOM_END
+ SQLCOM_END, SQLCOM_SHOW_WARNS, SQLCOM_SHOW_WARNS_COUNT,
+ 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,
@@ -318,6 +320,7 @@ typedef struct st_lex {
List<Item> *insert_list,field_list,value_list;
List<List_item> many_values;
List<Set_option> option_list;
+ List<Item> param_list;
SQL_LIST proc_list, auxilliary_table_list;
TYPELIB *interval;
create_field *last_field;
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 542eef623f0..541db4ec166 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -122,11 +122,14 @@ public:
last= &first;
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_ref() { return first != &end_of_list ? &first->info : 0; }
inline bool is_empty() { return first == &end_of_list ; }
inline list_node *last_ref() { return &end_of_list; }
friend class base_list_iterator;
+ friend class error_list;
protected:
void after(void *info,list_node *node)
@@ -204,6 +207,7 @@ public:
{
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) {}
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(); }
+};
+
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a5d8aa3185e..70f50483114 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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_merge_table_access(THD *thd, char *db, 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 refresh_status(void);
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",
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"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;
@@ -486,7 +486,7 @@ check_connections(THD *thd)
{
/* buff[] needs to big enough to hold the server_version variable */
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)
client_flags|=CLIENT_TRANSACTIONS;
@@ -957,7 +957,21 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->password=test(passwd[0]);
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:
{
packet_length--; // Remove end null
@@ -1380,6 +1394,26 @@ mysql_execute_command(void)
res = purge_master_logs(thd, lex->to_log);
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:
{
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 :
thd->priv_user,lex->verbose);
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:
res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars);
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->sent_row_count= thd->examined_row_count= 0;
thd->safe_to_cache_query= 1;
+ thd->param_count=0;
+ thd->prepare_command=false;
+ thd->lex.param_list.empty();
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
new file mode 100644
index 00000000000..d5896901935
--- /dev/null
+++ b/sql/sql_prepare.cc
@@ -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> &params);
+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> &params);
+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> &params)
+{
+ 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> &params)
+{
+ 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;
+}
+
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c10174a7b71..4737e068d3e 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -126,8 +126,6 @@ static bool store_record_in_cache(JOIN_CACHE *cache);
static void reset_cache(JOIN_CACHE *cache);
static void read_cached_record(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,
List<Item> &all_fields,ORDER *new_order);
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,
List<Item> &all_fields, ORDER *order, bool *hidden_group_fields)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1421eac168f..48d6bc7471f 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -169,6 +169,201 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
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
mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 25d8dbbab16..d140cd4dcdd 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -324,6 +324,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token TRAILING
%token TRANSACTION_SYM
%token TYPE_SYM
+%token TYPES_SYM
%token FUNC_ARG0
%token FUNC_ARG1
%token FUNC_ARG2
@@ -346,6 +347,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token X509_SYM
%token COMPRESSED_SYM
+%token ERRORS
+%token SQL_ERROR_COUNT
+%token WARNINGS
+%token SQL_WARNING_COUNT
+
%token BIGINT
%token BLOB_SYM
%token CHAR_SYM
@@ -548,7 +554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
literal text_literal insert_ident order_ident
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
- using_list subselect subselect_init
+ using_list param_marker subselect subselect_init
%type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg
@@ -1720,6 +1726,7 @@ no_and_expr:
simple_expr:
simple_ident
| literal
+ | param_marker
| '@' ident_or_text SET_VAR expr
{ $$= new Item_func_set_user_var($2,$4);
current_thd->safe_to_cache_query=0;
@@ -2795,6 +2802,29 @@ show_param:
if (!add_table_to_list($3,NULL,0))
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
{ Lex->sql_command= SQLCOM_SHOW_STATUS; }
| opt_full PROCESSLIST_SYM
@@ -3055,7 +3085,20 @@ text_string:
Item *tmp = new Item_varbinary($1.str,$1.length,default_charset_info);
$$= 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:
text_literal { $$ = $1; }
| NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); }
@@ -3411,6 +3454,16 @@ option_value:
YYABORT;
}
| 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
{
Item_func_set_user_var *item = new Item_func_set_user_var($2,$4);
diff --git a/sql/structs.h b/sql/structs.h
index 75280b34715..c4cb6c82209 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -152,6 +152,29 @@ struct show_var_st {
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 {
char *str;
uint length;