diff options
author | unknown <wax@kishkin.ru> | 2003-04-02 18:15:16 +0600 |
---|---|---|
committer | unknown <wax@kishkin.ru> | 2003-04-02 18:15:16 +0600 |
commit | aee0d02abdae17a6c24dd2aa0fe9a82bafc78fd8 (patch) | |
tree | 488579564c80c09c40acdafd8ff903c433ef47c1 /sql | |
parent | 69b8b99a399da7ff0a6da857fbbb484a09a404fc (diff) | |
parent | 6feda00ddb0253dc38f3b8fdf3e0a149086daf15 (diff) | |
download | mariadb-git-aee0d02abdae17a6c24dd2aa0fe9a82bafc78fd8.tar.gz |
Auto merged
BitKeeper/etc/logging_ok:
auto-union
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.h | 1 | ||||
-rw-r--r-- | sql/item_sum.cc | 456 | ||||
-rw-r--r-- | sql/item_sum.h | 86 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/mysql_priv.h | 4 | ||||
-rw-r--r-- | sql/share/english/errmsg.txt | 11 | ||||
-rw-r--r-- | sql/sql_class.h | 66 | ||||
-rw-r--r-- | sql/sql_error.cc | 12 | ||||
-rw-r--r-- | sql/sql_lex.h | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 36 |
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 |