summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <wax@kishkin.ru>2003-04-02 18:15:16 +0600
committerunknown <wax@kishkin.ru>2003-04-02 18:15:16 +0600
commitaee0d02abdae17a6c24dd2aa0fe9a82bafc78fd8 (patch)
tree488579564c80c09c40acdafd8ff903c433ef47c1 /sql
parent69b8b99a399da7ff0a6da857fbbb484a09a404fc (diff)
parent6feda00ddb0253dc38f3b8fdf3e0a149086daf15 (diff)
downloadmariadb-git-aee0d02abdae17a6c24dd2aa0fe9a82bafc78fd8.tar.gz
Auto merged
BitKeeper/etc/logging_ok: auto-union
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h1
-rw-r--r--sql/item_sum.cc456
-rw-r--r--sql/item_sum.h86
-rw-r--r--sql/lex.h2
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/share/english/errmsg.txt11
-rw-r--r--sql/sql_class.h66
-rw-r--r--sql/sql_error.cc12
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_yacc.yy36
10 files changed, 637 insertions, 38 deletions
diff --git a/sql/field.h b/sql/field.h
index 1b7906f9fb5..7334ff66dd8 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -224,6 +224,7 @@ public:
friend class Item_sum_std;
friend class Item_sum_min;
friend class Item_sum_max;
+ friend class Item_func_group_concat;
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index e303c26262e..55a2765cba3 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1329,3 +1329,459 @@ String *Item_sum_udf_str::val_str(String *str)
}
#endif /* HAVE_DLOPEN */
+
+
+/*****************************************************************************
+ GROUP_CONCAT function
+ Syntax:
+ GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...]
+ [SEPARATOR str_const])
+ concat of values from "group by" operation
+*****************************************************************************/
+
+/*
+ function of sort for syntax:
+ GROUP_CONCAT(DISTINCT expr,...)
+*/
+
+static int group_concat_key_cmp_with_distinct(void* arg, byte* key1, byte* key2)
+{
+ Item_func_group_concat* item= (Item_func_group_concat*)arg;
+ for (int i= 0; i<item->arg_count_field; i++)
+ {
+ Item *field_item= item->expr[i];
+ Field *field= field_item->tmp_table_field();
+ if (field)
+ {
+ uint offset= field->offset();
+
+ int res= field->key_cmp(key1 + offset, key2 + offset);
+ /*
+ if key1 and key2 is not equal than field->key_cmp return offset. This function
+ must return value 1 for this case.
+ */
+ if (res)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ function of sort for syntax:
+ GROUP_CONCAT(expr,... ORDER BY col,... )
+*/
+
+static int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
+{
+ Item_func_group_concat* item= (Item_func_group_concat*)arg;
+ for (int i=0; i<item->arg_count_order; i++)
+ {
+ ORDER *order_item= item->order[i];
+ Item *item= *order_item->item;
+ Field *field= item->tmp_table_field();
+ if (field)
+ {
+ uint offset= field->offset();
+
+ bool dir= order_item->asc;
+ int res= field->key_cmp(key1 + offset, key2 + offset);
+ if (res)
+ return dir ? res : -res;
+ }
+ }
+ /*
+ We can't return 0 becouse tree class remove this item as dubl value.
+ */
+ return 1;
+}
+
+/*
+ function of sort for syntax:
+ GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... )
+*/
+
+static int group_concat_key_cmp_with_distinct_and_order(void* arg, byte* key1, byte* key2)
+{
+ Item_func_group_concat* item= (Item_func_group_concat*)arg;
+ if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
+ return 0;
+ return(group_concat_key_cmp_with_order(arg,key1,key2));
+}
+
+/*
+ create result
+ item is pointer to Item_func_group_concat
+*/
+
+static int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
+ Item_func_group_concat *group_concat_item)
+{
+ char buff[MAX_FIELD_WIDTH];
+ String tmp((char *)&buff,sizeof(buff),default_charset_info);
+ String tmp2((char *)&buff,sizeof(buff),default_charset_info);
+
+ tmp.length(0);
+
+ for (int i= 0; i < group_concat_item->arg_show_fields; i++)
+ {
+ Item *show_item= group_concat_item->expr[i];
+ if (!show_item->const_item())
+ {
+ Field *f= show_item->tmp_table_field();
+ uint offset= f->offset();
+ char *sv= f->ptr;
+ f->ptr= (char *)key + offset;
+ String *res= f->val_str(&tmp,&tmp2);
+ group_concat_item->result.append(*res);
+ f->ptr= sv;
+ }
+ else
+ {
+ String *res= show_item->val_str(&tmp);
+ if (res)
+ group_concat_item->result.append(*res);
+ }
+ }
+ if (group_concat_item->tree_mode) // Last item of tree
+ {
+ group_concat_item->show_elements++;
+ if (group_concat_item->show_elements <
+ group_concat_item->tree->elements_in_tree)
+ group_concat_item->result.append(*group_concat_item->separator);
+ }
+ else
+ {
+ group_concat_item->result.append(*group_concat_item->separator);
+ }
+ /*
+ if length of result more than group_concat_max_len - stop !
+ */
+ if (group_concat_item->result.length() >
+ group_concat_item->group_concat_max_len)
+ {
+ group_concat_item->count_cut_values++;
+ group_concat_item->result.length(group_concat_item->group_concat_max_len);
+ group_concat_item->warning_for_row= TRUE;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ Constructor of Item_func_group_concat
+ is_distinct - distinct
+ is_select - list of expression for show values
+ is_order - list of sort columns
+ is_separator - string value of separator
+*/
+
+Item_func_group_concat::Item_func_group_concat(int is_distinct,List<Item> *is_select,
+ SQL_LIST *is_order,String *is_separator):
+ Item_sum(),
+ tmp_table_param(0),
+ warning_available(false),
+ separator(is_separator),
+ tree(&tree_base),
+ table(0),
+ distinct(is_distinct),
+ tree_mode(0),
+ count_cut_values(0)
+{
+ original= 0;
+ quick_group= 0;
+ mark_as_sum_func();
+ SELECT_LEX *select_lex= current_lex->current_select->select_lex();
+ order= 0;
+
+ arg_show_fields= arg_count_field= is_select->elements;
+ arg_count_order= is_order ? is_order->elements : 0;
+ arg_count= arg_count_field;
+
+ /*
+ We need to allocate:
+ args - arg_count+arg_count_order (for possible order items in temporare
+ tables)
+ expr - arg_count_field
+ order - arg_count_order
+ */
+ args= (Item**)sql_alloc(sizeof(Item*)*(arg_count+arg_count_order+arg_count_field)+
+ sizeof(ORDER*)*arg_count_order);
+ if (!args)
+ {
+ my_error(ER_OUTOFMEMORY,MYF(0));
+ }
+ expr= args;
+ expr+= arg_count+arg_count_order;
+ if (arg_count_order)
+ {
+ order= (ORDER**)(expr + arg_count_field);
+ }
+ /*
+ fill args items of show and sort
+ */
+ int i= 0;
+ List_iterator_fast<Item> li(*is_select);
+ Item *item_select;
+
+ while ((item_select= li++))
+ {
+ args[i]= expr[i]= item_select;
+ i++;
+ }
+
+ if (order)
+ {
+ uint j= 0;
+ for (ORDER *order_item= (ORDER*)is_order->first;
+ order_item != NULL;
+ order_item= order_item->next)
+ {
+ order[j++]= order_item;
+ }
+ }
+}
+
+
+Item_func_group_concat::~Item_func_group_concat()
+{
+ /*
+ Free table and tree if they belong to this item (if item have not pointer
+ to original item from which was made copy => it own its objects )
+ */
+ if (!original)
+ {
+ if (warning_available)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
+ ((MYSQL_ERROR *)warning)->set_msg((char *)&warn_buff);
+ }
+ if (table)
+ free_tmp_table(current_thd, table);
+ if (tmp_table_param)
+ delete tmp_table_param;
+ if (tree_mode)
+ delete_tree(tree);
+ }
+}
+
+
+void Item_func_group_concat::reset()
+{
+ result.length(0);
+ result.copy();
+ null_value= TRUE;
+ warning_for_row= false;
+ if (table)
+ {
+ table->file->extra(HA_EXTRA_NO_CACHE);
+ table->file->delete_all_rows();
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ }
+ if (tree_mode)
+ reset_tree(tree);
+ add();
+}
+
+
+bool Item_func_group_concat::add()
+{
+ copy_fields(tmp_table_param);
+ copy_funcs(tmp_table_param->items_to_copy);
+
+ bool record_is_null= TRUE;
+ for (int i= 0; i < arg_show_fields; i++)
+ {
+ Item *show_item= expr[i];
+ if (!show_item->const_item())
+ {
+ Field *f= show_item->tmp_table_field();
+ if (!f->is_null())
+ record_is_null= FALSE;
+ }
+ }
+ if (record_is_null)
+ return 0;
+ null_value= FALSE;
+ if (tree_mode)
+ {
+ if (!tree_insert(tree, table->record[0], 0,tree->custom_arg))
+ return 1;
+ }
+ else
+ {
+ if (result.length() <= group_concat_max_len && !warning_for_row)
+ dump_leaf_key(table->record[0],1,
+ (Item_func_group_concat*)this);
+ }
+ return 0;
+}
+
+
+void Item_func_group_concat::reset_field()
+{
+ if (tree_mode)
+ reset_tree(tree);
+}
+
+
+bool
+Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+{
+ if (!thd->allow_sum_func)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
+ return 1;
+ }
+
+ thd->allow_sum_func= 0;
+ maybe_null= 0;
+ for (uint i= 0 ; i < arg_count ; i++)
+ {
+ if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
+ return 1;
+ maybe_null |= args[i]->maybe_null;
+ }
+ for (int i= 0 ; i < arg_count_field ; i++)
+ {
+ if (expr[i]->fix_fields(thd, tables, expr + i) || expr[i]->check_cols(1))
+ return 1;
+ maybe_null |= expr[i]->maybe_null;
+ }
+ /*
+ Fix fields for order clause in function:
+ GROUP_CONCAT(expr,... ORDER BY col,... )
+ */
+ for (int i= 0 ; i < arg_count_order ; i++)
+ {
+ ORDER *order_item= order[i];
+ Item *item=*order_item->item;
+ if (item->fix_fields(thd, tables, &item) || item->check_cols(1))
+ return 1;
+ }
+ result_field= 0;
+ null_value= 1;
+ fix_length_and_dec();
+ thd->allow_sum_func= 1;
+ if (!(tmp_table_param= new TMP_TABLE_PARAM))
+ return 1;
+ tables_list= tables;
+ fixed= 1;
+ return 0;
+}
+
+
+bool Item_func_group_concat::setup(THD *thd)
+{
+ List<Item> list;
+ SELECT_LEX *select_lex= current_lex->current_select->select_lex();
+
+ if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
+ return 1;
+ /*
+ all not constant fields are push to list and create temp table
+ */
+ for (uint i= 0; i < arg_count; i++)
+ {
+ Item *item= args[i];
+ if (list.push_back(item))
+ return 1;
+ if (item->const_item())
+ {
+ (void) item->val_int();
+ if (item->null_value)
+ always_null= 1;
+ }
+ }
+
+ List<Item> all_fields(list);
+ if (arg_count_order)
+ {
+ bool hidden_group_fields;
+ setup_group(thd, args, tables_list, list, all_fields, *order,
+ &hidden_group_fields);
+ }
+
+ count_field_types(tmp_table_param,all_fields,0);
+ /*
+ We have to create a temporary table for that we get descriptions of fields
+ (types, sizes and so on).
+ */
+ if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0,
+ 0, 0, 0,select_lex->options | thd->options)))
+ return 1;
+ table->file->extra(HA_EXTRA_NO_ROWS);
+ table->no_rows= 1;
+ qsort_cmp2 compare_key;
+
+ tree_mode= distinct || arg_count_order;
+ /*
+ choise function of sort
+ */
+ if (tree_mode)
+ {
+ if (arg_count_order)
+ {
+ if (distinct)
+ compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct_and_order;
+ else
+ compare_key= (qsort_cmp2) group_concat_key_cmp_with_order;
+ }
+ else
+ {
+ if (distinct)
+ compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct;
+ else
+ compare_key= NULL;
+ }
+ /*
+ Create a tree of sort. Tree is used for a sort and a remove dubl
+ values (according with syntax of the function). If function does't
+ contain DISTINCT and ORDER BY clauses, we don't create this tree.
+ */
+ init_tree(tree, min(thd->variables.max_heap_table_size,
+ thd->variables.sortbuff_size/16), 0,
+ table->reclength, compare_key, 0, NULL, (void*) this);
+ max_elements_in_tree= ((table->reclength) ?
+ thd->variables.max_heap_table_size/table->reclength : 1);
+ };
+ item_thd= thd;
+
+ group_concat_max_len= thd->variables.group_concat_max_len;
+
+ /*
+ Copy table and tree_mode if they belong to this item (if item have not
+ pointer to original item from which was made copy => it own its objects)
+ */
+ if (original)
+ {
+ original->table= table;
+ original->tree_mode= tree_mode;
+ }
+ return 0;
+}
+
+String* Item_func_group_concat::val_str(String* str)
+{
+ if (null_value)
+ return 0;
+ if (tree_mode)
+ {
+ show_elements= 0;
+ tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
+ left_root_right);
+ }
+ else
+ {
+ if (!warning_for_row)
+ result.length(result.length()-separator->length());
+ }
+ if (count_cut_values && !warning_available)
+ {
+ warning_available= TRUE;
+ warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CUT_VALUE_GROUP_CONCAT, NULL);
+ }
+ return &result;
+}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 74c7b11a7ba..a6a6634b920 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -28,7 +28,7 @@ class Item_sum :public Item_result_field
public:
enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
- UDF_SUM_FUNC };
+ UDF_SUM_FUNC, GROUP_CONCAT_FUNC };
Item **args,*tmp_args[2];
uint arg_count;
@@ -630,3 +630,87 @@ public:
};
#endif /* HAVE_DLOPEN */
+
+class Item_func_group_concat : public Item_sum
+{
+ THD *item_thd;
+ TMP_TABLE_PARAM *tmp_table_param;
+ uint max_elements_in_tree;
+ void *warning;
+ bool warning_available;
+ public:
+ String result;
+ String *separator;
+ uint show_elements;
+ TREE tree_base;
+ TREE *tree;
+ TABLE *table;
+ int arg_count_order;
+ int arg_count_field;
+ int arg_show_fields;
+ int distinct;
+ Item **expr;
+ ORDER **order;
+ bool tree_mode;
+ int count_cut_values;
+ ulong group_concat_max_len;
+ bool warning_for_row;
+ TABLE_LIST *tables_list;
+ bool always_null;
+ /*
+ Following is 0 normal object and pointer to original one for copy
+ (to correctly free resources)
+ */
+ Item_func_group_concat *original;
+
+ Item_func_group_concat(int is_distinct,List<Item> *is_select,
+ SQL_LIST *is_order,String *is_separator);
+
+ Item_func_group_concat(THD *thd, Item_func_group_concat &item)
+ :Item_sum(thd, item),item_thd(thd),
+ tmp_table_param(item.tmp_table_param),
+ max_elements_in_tree(item.max_elements_in_tree),
+ warning(item.warning),
+ warning_available(item.warning_available),
+ separator(item.separator),
+ show_elements(item.show_elements),
+ tree(item.tree),
+ table(item.table),
+ arg_count_order(item.arg_count_order),
+ arg_count_field(item.arg_count_field),
+ arg_show_fields(item.arg_show_fields),
+ distinct(item.distinct),
+ expr(item.expr),
+ order(item.order),
+ tree_mode(0),
+ count_cut_values(item.count_cut_values),
+ group_concat_max_len(item.group_concat_max_len),
+ warning_for_row(item.warning_for_row),
+ tables_list(item.tables_list),
+ original(&item)
+ {
+ quick_group = 0;
+ };
+ ~Item_func_group_concat();
+ enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;}
+ const char *func_name() const { return "group_concat"; }
+ enum Type type() const { return SUM_FUNC_ITEM; }
+ virtual Item_result result_type () const { return STRING_RESULT; }
+ void reset();
+ bool add();
+ void reset_field();
+ bool fix_fields(THD *, TABLE_LIST *, Item **);
+ bool setup(THD *thd);
+ virtual void update_field(int offset) {};
+ double val()
+ {
+ String *res; res=val_str(&str_value);
+ return res ? atof(res->c_ptr()) : 0.0;
+ }
+ longlong val_int()
+ {
+ String *res; res=val_str(&str_value);
+ return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
+ }
+ String* val_str(String* str);
+};
diff --git a/sql/lex.h b/sql/lex.h
index 01a289e4f7a..aab530251b8 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -335,6 +335,7 @@ static SYMBOL symbols[] = {
{ "ROWS", SYM(ROWS_SYM),0,0},
{ "RTREE", SYM(RTREE_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0},
+ { "SEPARATOR", SYM(SEPARATOR_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0},
{ "SERIAL", SYM(SERIAL_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
@@ -503,6 +504,7 @@ static SYMBOL sql_functions[] = {
{ "GEOMFROMWKB", SYM(GEOMFROMWKB),0,0},
{ "GLENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_glength)},
{ "GREATEST", SYM(GREATEST_SYM),0,0},
+ { "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM),0,0},
{ "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS),0,0},
{ "HEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_hex)},
{ "IFNULL", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_ifnull)},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 6a6f93d470d..4f31abf7609 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -547,8 +547,8 @@ int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
List<Item> &values, ulong counter);
/* sql_error.cc */
-void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
- const char *msg);
+MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
+ const char *msg);
void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
uint code, const char *format, ...);
void mysql_reset_errors(THD *thd);
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 0f48416d6db..1b5d4a23601 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -166,7 +166,7 @@
"Result string is longer than max_allowed_packet",
"The used table type doesn't support BLOB/TEXT columns",
"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s' because it is locked with LOCK TABLES",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
"Incorrect column name '%-.100s'",
"The used table handler can't index column '%-.64s'",
"All tables in the MERGE table are not identically defined",
@@ -198,7 +198,7 @@
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again",
+"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
@@ -250,8 +250,5 @@
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
-"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
-"All parts of a SPATIAL KEY must be NOT NULL"
-"COLLATION '%s' is not valid for CHARACTER SET '%s'"
-"The slave was already running"
-"The slave was already stopped"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client",
+"%d line(s) was(were) cut by group_concat()"
diff --git a/sql/sql_class.h b/sql/sql_class.h
index b196990d7c0..052da81be4e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -34,8 +34,6 @@ enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
DELAY_KEY_WRITE_ALL };
-extern char internal_table_name[2];
-
// log info errors
#define LOG_INFO_EOF -1
#define LOG_INFO_IO -2
@@ -145,9 +143,7 @@ public:
int generate_new_name(char *new_name,const char *old_name);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
- int update_log_index(LOG_INFO* linfo);
int purge_logs(THD* thd, const char* to_log);
- int purge_logs_before_date(THD* thd, time_t purge_time);
int purge_first_log(struct st_relay_log_info* rli);
bool reset_logs(THD* thd);
// if we are exiting, we also want to close the index file
@@ -174,6 +170,32 @@ public:
/* character conversion tables */
+class CONVERT;
+CONVERT *get_convert_set(const char *name_ptr);
+
+class CONVERT
+{
+ const uchar *from_map,*to_map;
+ void convert_array(const uchar *mapping,uchar *buff,uint length);
+public:
+ const char *name;
+ uint numb;
+ CONVERT(const char *name_par,uchar *from_par,uchar *to_par, uint number)
+ :from_map(from_par),to_map(to_par),name(name_par),numb(number) {}
+ friend CONVERT *get_convert_set(const char *name_ptr);
+ inline void convert(char *a,uint length)
+ {
+ convert_array(from_map, (uchar*) a,length);
+ }
+ char *store_dest(char *to, const char *from, uint length)
+ {
+ for (const char *end=from+length ; from != end ; from++)
+ *to++= to_map[(uchar) *from];
+ return to;
+ }
+ bool store(String *, const char *,uint);
+ inline uint number() { return numb; }
+};
typedef struct st_copy_info {
ha_rows records;
@@ -305,7 +327,12 @@ public:
const char *msg_arg)
:code(code_arg), level(level_arg)
{
- msg=sql_strdup(msg_arg);
+ if (msg_arg)
+ msg=sql_strdup(msg_arg);
+ }
+ inline void set_msg(const char *msg_arg)
+ {
+ msg=sql_strdup(msg_arg);
}
};
@@ -333,6 +360,10 @@ class select_result;
#define THD_SENTRY_MAGIC 0xfeedd1ff
#define THD_SENTRY_GONE 0xdeadbeef
+#ifdef EMBEDDED_LIBRARY
+typedef struct st_mysql;
+#endif
+
#define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC)
struct system_variables
@@ -365,8 +396,7 @@ struct system_variables
ulong tmp_table_size;
ulong tx_isolation;
ulong sql_mode;
- ulong default_week_format;
-
+ ulong group_concat_max_len;
/*
In slave thread we need to know in behalf of which
thread the query is being run to replicate temp tables properly
@@ -374,10 +404,9 @@ struct system_variables
ulong pseudo_thread_id;
my_bool log_warnings;
- my_bool low_priority_updates;
- my_bool new_mode;
- my_bool convert_result_charset;
+ my_bool low_priority_updates;
+ CONVERT *convert_set;
CHARSET_INFO *thd_charset;
};
@@ -424,9 +453,8 @@ public:
db - currently selected database
ip - client IP
*/
+
char *host,*user,*priv_user,*db,*ip;
- /* remote (peer) port */
- uint16 peer_port;
/* Points to info-string that will show in SHOW PROCESSLIST */
const char *proc_info;
/* points to host if host is available, otherwise points to ip */
@@ -549,7 +577,6 @@ public:
void init(void);
void change_user(void);
- void init_for_queries();
void cleanup(void);
bool store_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
@@ -657,9 +684,7 @@ public:
{
is_fatal_error= 1;
net.report_error= 1;
- DBUG_PRINT("error",("Fatal error set"));
}
- inline CHARSET_INFO *charset() { return variables.thd_charset; }
};
/*
@@ -885,11 +910,10 @@ class Table_ident :public Sql_alloc
LEX_STRING db;
LEX_STRING table;
SELECT_LEX_UNIT *sel;
- inline Table_ident(THD *thd, LEX_STRING db_arg, LEX_STRING table_arg,
- bool force)
+ inline Table_ident(LEX_STRING db_arg, LEX_STRING table_arg, bool force)
:table(table_arg), sel((SELECT_LEX_UNIT *)0)
{
- if (!force && (thd->client_capabilities & CLIENT_NO_SCHEMA))
+ if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA))
db.str=0;
else
db= db_arg;
@@ -901,8 +925,7 @@ class Table_ident :public Sql_alloc
}
inline Table_ident(SELECT_LEX_UNIT *s) : sel(s)
{
- /* We must have a table name here as this is used with add_table_to_list */
- db.str=0; table.str= internal_table_name; table.length=1;
+ db.str=0; table.str=(char *)""; table.length=0;
}
inline void change_db(char *db_name)
{
@@ -919,7 +942,6 @@ class user_var_entry
ulong length, update_query_id, used_query_id;
Item_result type;
CHARSET_INFO *var_charset;
- enum Item::coercion var_coercibility;
};
/* Class for unique (removing of duplicates) */
@@ -978,7 +1000,7 @@ class multi_update : public select_result
{
TABLE_LIST *all_tables, *update_tables, *table_being_updated;
THD *thd;
- TABLE **tmp_tables, *main_table, *table_to_update;
+ TABLE **tmp_tables, *main_table;
TMP_TABLE_PARAM *tmp_table_param;
ha_rows updated, found;
List <Item> *fields, *values;
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index c7b1814c1d7..380d42e2580 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -80,14 +80,19 @@ void mysql_reset_errors(THD *thd)
level Severity of warning (note, warning, error ...)
code Error number
msg Clear error message
+
+ RETURN
+ pointer on MYSQL_ERROR object
*/
-void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
- const char *msg)
+MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ uint code, const char *msg)
{
if (thd->query_id != thd->warn_id)
mysql_reset_errors(thd);
+ MYSQL_ERROR *err = NULL;
+
if (thd->warn_list.elements < thd->variables.max_error_count)
{
/*
@@ -96,13 +101,14 @@ void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
*/
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root);
- MYSQL_ERROR *err= new MYSQL_ERROR(code, level, msg);
+ err = new MYSQL_ERROR(code, level, msg);
if (err)
thd->warn_list.push_back(err);
my_pthread_setspecific_ptr(THR_MALLOC, old_root);
}
thd->warn_count[(uint) level]++;
thd->total_warn_count++;
+ return err;
}
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6abcd5e8fea..046b67816f1 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -478,6 +478,7 @@ typedef struct st_lex
uint slave_thd_opt;
CHARSET_INFO *charset;
char *help_arg;
+ SQL_LIST *gorder_list;
inline void uncacheable()
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f30bfbc594a..d730807464f 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -336,6 +336,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ROW_SYM
%token RTREE_SYM
%token SET
+%token SEPARATOR_SYM
%token SERIAL_SYM
%token SERIALIZABLE_SYM
%token SESSION_SYM
@@ -462,6 +463,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token GEOMFROMTEXT
%token GEOMFROMWKB
%token GEOMETRYCOLLECTION
+%token GROUP_CONCAT_SYM
%token GROUP_UNIQUE_USERS
%token HOUR_MINUTE_SYM
%token HOUR_SECOND_SYM
@@ -575,13 +577,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
opt_escape
%type <string>
- text_string
+ text_string opt_gconcat_separator
%type <num>
type int_type real_type order_dir opt_field_spec lock_option
udf_type if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists opt_var_type opt_var_ident_type
- delete_option opt_temporary all_or_any
+ delete_option opt_temporary all_or_any opt_distinct
%type <ulong_num>
ULONG_NUM raid_types merge_insert_types
@@ -2554,7 +2556,35 @@ sum_expr:
| VARIANCE_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_variance($3); }
| SUM_SYM '(' in_sum_expr ')'
- { $$=new Item_sum_sum($3); };
+ { $$=new Item_sum_sum($3); }
+ | GROUP_CONCAT_SYM '(' opt_distinct expr_list opt_gorder_clause opt_gconcat_separator ')'
+ {
+ $$=new Item_func_group_concat($3,$4,Lex->gorder_list,$6);
+ $4->empty();
+ };
+
+opt_distinct:
+ /* empty */ { $$ = 0; }
+ |DISTINCT { $$ = 1; };
+
+opt_gconcat_separator:
+ /* empty */ { $$ = new String(" ",1,default_charset_info); }
+ |SEPARATOR_SYM text_string { $$ = $2; };
+
+
+opt_gorder_clause:
+ /* empty */
+ {
+ LEX *lex=Lex;
+ lex->gorder_list = NULL;
+ }
+ | order_clause
+ {
+ LEX *lex=Lex;
+ lex->gorder_list= (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list,sizeof(st_sql_list));
+ lex->current_select->order_list.empty();
+ };
+
in_sum_expr:
opt_all