Commit f08b12ca authored by unknown's avatar unknown

Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-4.1

into sanja.is.com.ua:/home/bell/mysql/bk/work-4.1


mysql-test/t/func_gconcat.test:
  Auto merged
sql/item.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
parents 01af9a83 5535bce5
...@@ -285,15 +285,21 @@ insert into t2 values (1, 5), (2, 4), (3, 3), (3,3); ...@@ -285,15 +285,21 @@ insert into t2 values (1, 5), (2, 4), (3, 3), (3,3);
select group_concat(c) from t1; select group_concat(c) from t1;
group_concat(c) group_concat(c)
2,3,4,5 2,3,4,5
select group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1; select t1.a, group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1 group by 1;
grp a grp
5,4,3,2 1 2
select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1; 2 4,3
grp 3 5
5,4,3,2 select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1 group by 1;
select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1; a grp
grp 1 2
2,4,3,5 2 4,3
3 5
select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1 group by 1;
a grp
1 2
2 4,3
3 5
select a,c,(select group_concat(c order by a) from t2 where a=t1.a) as grp from t1 order by grp; select a,c,(select group_concat(c order by a) from t2 where a=t1.a) as grp from t1 order by grp;
a c grp a c grp
3 5 3,3 3 5 3,3
......
...@@ -1899,3 +1899,46 @@ select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL ( ...@@ -1899,3 +1899,46 @@ select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (
a C a C
1 1 1 1
drop table t1,t2; drop table t1,t2;
CREATE TABLE `t1` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`));
CREATE TABLE `t2` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`));
insert into t1 values (1,1),(1,2),(2,1),(2,2);
insert into t2 values (1,2),(2,2);
select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid);
aid bid
1 1
2 1
alter table t2 drop primary key;
alter table t2 add key KEY1 (aid, bid);
select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid);
aid bid
1 1
2 1
alter table t2 drop key KEY1;
alter table t2 add primary key (bid, aid);
select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid);
aid bid
1 1
2 1
drop table t1,t2;
CREATE TABLE t1 (howmanyvalues bigint, avalue int);
INSERT INTO t1 VALUES (1, 1),(2, 1),(2, 2),(3, 1),(3, 2),(3, 3),(4, 1),(4, 2),(4, 3),(4, 4);
SELECT howmanyvalues, count(*) from t1 group by howmanyvalues;
howmanyvalues count(*)
1 1
2 2
3 3
4 4
SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.howmanyvalues) as mycount from t1 a group by a.howmanyvalues;
howmanyvalues mycount
1 1
2 2
3 3
4 4
CREATE INDEX t1_howmanyvalues_idx ON t1 (howmanyvalues);
SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues+1 = a.howmanyvalues+1) as mycount from t1 a group by a.howmanyvalues;
howmanyvalues mycount
1 1
2 2
3 3
4 4
drop table t1;
...@@ -168,10 +168,10 @@ insert into t1 values (1, 2), (2, 3), (2, 4), (3, 5); ...@@ -168,10 +168,10 @@ insert into t1 values (1, 2), (2, 3), (2, 4), (3, 5);
create table t2 (a int, c int); create table t2 (a int, c int);
insert into t2 values (1, 5), (2, 4), (3, 3), (3,3); insert into t2 values (1, 5), (2, 4), (3, 3), (3,3);
select group_concat(c) from t1; select group_concat(c) from t1;
select group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1; select t1.a, group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1 group by 1;
select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1; select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1 group by 1;
select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1; select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1 group by 1;
# The following returns random results as we are sorting on blob addresses # The following returns random results as we are sorting on blob addresses
# select group_concat(c order by (select group_concat(c order by a) from t2 where t2.a=t1.a)) as grp from t1; # select group_concat(c order by (select group_concat(c order by a) from t2 where t2.a=t1.a)) as grp from t1;
......
...@@ -1222,3 +1222,30 @@ CREATE TABLE `t2` ( `b` int(11) default NULL, `a` int(11) default NULL) ENGINE=M ...@@ -1222,3 +1222,30 @@ CREATE TABLE `t2` ( `b` int(11) default NULL, `a` int(11) default NULL) ENGINE=M
insert into t2 values (1,2); insert into t2 values (1,2);
select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (SELECT count(*) FROM t2 t001 WHERE t001.a=1); select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (SELECT count(*) FROM t2 t001 WHERE t001.a=1);
drop table t1,t2; drop table t1,t2;
#
# Optimized IN with compound index
#
CREATE TABLE `t1` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`));
CREATE TABLE `t2` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`));
insert into t1 values (1,1),(1,2),(2,1),(2,2);
insert into t2 values (1,2),(2,2);
select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid);
alter table t2 drop primary key;
alter table t2 add key KEY1 (aid, bid);
select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid);
alter table t2 drop key KEY1;
alter table t2 add primary key (bid, aid);
select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid);
drop table t1,t2;
#
# resolving fields of grouped outer SELECT
#
CREATE TABLE t1 (howmanyvalues bigint, avalue int);
INSERT INTO t1 VALUES (1, 1),(2, 1),(2, 2),(3, 1),(3, 2),(3, 3),(4, 1),(4, 2),(4, 3),(4, 4);
SELECT howmanyvalues, count(*) from t1 group by howmanyvalues;
SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.howmanyvalues) as mycount from t1 a group by a.howmanyvalues;
CREATE INDEX t1_howmanyvalues_idx ON t1 (howmanyvalues);
SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues+1 = a.howmanyvalues+1) as mycount from t1 a group by a.howmanyvalues;
drop table t1;
...@@ -60,10 +60,10 @@ Item::Item(): ...@@ -60,10 +60,10 @@ Item::Item():
*/ */
if (thd->lex->current_select) if (thd->lex->current_select)
{ {
SELECT_LEX_NODE::enum_parsing_place place= enum_parsing_place place=
thd->lex->current_select->parsing_place; thd->lex->current_select->parsing_place;
if (place == SELECT_LEX_NODE::SELECT_LIST || if (place == SELECT_LIST ||
place == SELECT_LEX_NODE::IN_HAVING) place == IN_HAVING)
thd->lex->current_select->select_n_having_items++; thd->lex->current_select->select_n_having_items++;
} }
} }
...@@ -1233,12 +1233,25 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -1233,12 +1233,25 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
table_list= (last= sl)->get_table_list(); table_list= (last= sl)->get_table_list();
if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
{ {
// it is primary INSERT st_select_lex => skip first table resolving /*
it is primary INSERT st_select_lex => skip first table
resolving
*/
table_list= table_list->next; table_list= table_list->next;
} }
Item_subselect *prev_subselect_item= prev_unit->item; Item_subselect *prev_subselect_item= prev_unit->item;
if ((tmp= find_field_in_tables(thd, this, enum_parsing_place place=
prev_subselect_item->parsing_place;
/*
check table fields only if subquery used somewhere out of HAVING
or SELECT list or outer SELECT do not use groupping (i.e. tables
are accessable)
*/
if (((place != IN_HAVING &&
place != SELECT_LIST) ||
(sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
(tmp= find_field_in_tables(thd, this,
table_list, &where, table_list, &where,
0)) != not_found_field) 0)) != not_found_field)
{ {
...@@ -1906,7 +1919,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) ...@@ -1906,7 +1919,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
// it is primary INSERT st_select_lex => skip first table resolving // it is primary INSERT st_select_lex => skip first table resolving
table_list= table_list->next; table_list= table_list->next;
} }
if ((tmp= find_field_in_tables(thd, this, enum_parsing_place place=
prev_subselect_item->parsing_place;
/*
check table fields only if subquery used somewhere out of HAVING
or SELECT list or outer SELECT do not use groupping (i.e. tables
are accessable)
*/
if (((place != IN_HAVING &&
place != SELECT_LIST) ||
(sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
(tmp= find_field_in_tables(thd, this,
table_list, &where, table_list, &where,
0)) != not_found_field) 0)) != not_found_field)
{ {
...@@ -1914,7 +1937,6 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) ...@@ -1914,7 +1937,6 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
prev_subselect_item->const_item_cache= 0; prev_subselect_item->const_item_cache= 0;
break; break;
} }
// Reference is not found => depend from outer (or just error) // Reference is not found => depend from outer (or just error)
prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
prev_subselect_item->const_item_cache= 0; prev_subselect_item->const_item_cache= 0;
......
...@@ -63,12 +63,14 @@ void Item_subselect::init(st_select_lex *select_lex, ...@@ -63,12 +63,14 @@ void Item_subselect::init(st_select_lex *select_lex,
=> we do not copy old_engine here => we do not copy old_engine here
*/ */
engine= unit->item->engine; engine= unit->item->engine;
parsing_place= unit->item->parsing_place;
unit->item->engine= 0; unit->item->engine= 0;
unit->item= this; unit->item= this;
engine->change_item(this, result); engine->change_item(this, result);
} }
else else
{ {
parsing_place= unit->outer_select()->parsing_place;
if (select_lex->next_select()) if (select_lex->next_select())
engine= new subselect_union_engine(unit, result, this); engine= new subselect_union_engine(unit, result, this);
else else
...@@ -76,7 +78,7 @@ void Item_subselect::init(st_select_lex *select_lex, ...@@ -76,7 +78,7 @@ void Item_subselect::init(st_select_lex *select_lex,
} }
{ {
SELECT_LEX *upper= unit->outer_select(); SELECT_LEX *upper= unit->outer_select();
if (upper->parsing_place == SELECT_LEX_NODE::IN_HAVING) if (upper->parsing_place == IN_HAVING)
upper->subquery_in_having= 1; upper->subquery_in_having= 1;
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -1243,13 +1245,15 @@ int subselect_uniquesubquery_engine::exec() ...@@ -1243,13 +1245,15 @@ int subselect_uniquesubquery_engine::exec()
DBUG_ENTER("subselect_uniquesubquery_engine::exec"); DBUG_ENTER("subselect_uniquesubquery_engine::exec");
int error; int error;
TABLE *table= tab->table; TABLE *table= tab->table;
if ((tab->ref.key_err= (*tab->ref.key_copy)->copy())) for (store_key **copy=tab->ref.key_copy ; *copy ; copy++)
{
if (tab->ref.key_err= (*copy)->copy())
{ {
table->status= STATUS_NOT_FOUND; table->status= STATUS_NOT_FOUND;
error= -1; DBUG_RETURN(1);
} }
else }
{
if (!table->file->inited) if (!table->file->inited)
table->file->ha_index_init(tab->ref.key); table->file->ha_index_init(tab->ref.key);
error= table->file->index_read(table->record[0], error= table->file->index_read(table->record[0],
...@@ -1265,7 +1269,7 @@ int subselect_uniquesubquery_engine::exec() ...@@ -1265,7 +1269,7 @@ int subselect_uniquesubquery_engine::exec()
(!cond || cond->val_int()) ? 1 : (!cond || cond->val_int()) ? 1 :
0); 0);
} }
}
DBUG_RETURN(error != 0); DBUG_RETURN(error != 0);
} }
...@@ -1293,13 +1297,15 @@ int subselect_indexsubquery_engine::exec() ...@@ -1293,13 +1297,15 @@ int subselect_indexsubquery_engine::exec()
((Item_in_subselect *) item)->was_null= 0; ((Item_in_subselect *) item)->was_null= 0;
} }
if ((*tab->ref.key_copy) && (tab->ref.key_err= (*tab->ref.key_copy)->copy())) for (store_key **copy=tab->ref.key_copy ; *copy ; copy++)
{
if (tab->ref.key_err= (*copy)->copy())
{ {
table->status= STATUS_NOT_FOUND; table->status= STATUS_NOT_FOUND;
error= -1; DBUG_RETURN(1);
} }
else }
{
if (!table->file->inited) if (!table->file->inited)
table->file->ha_index_init(tab->ref.key); table->file->ha_index_init(tab->ref.key);
error= table->file->index_read(table->record[0], error= table->file->index_read(table->record[0],
...@@ -1344,7 +1350,6 @@ int subselect_indexsubquery_engine::exec() ...@@ -1344,7 +1350,6 @@ int subselect_indexsubquery_engine::exec()
} }
} }
} }
}
DBUG_RETURN(error != 0); DBUG_RETURN(error != 0);
} }
......
...@@ -50,6 +50,8 @@ class Item_subselect :public Item_result_field ...@@ -50,6 +50,8 @@ class Item_subselect :public Item_result_field
table_map used_tables_cache; table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */ /* allowed number of columns (1 for single value subqueries) */
uint max_columns; uint max_columns;
/* where subquery is placed */
enum_parsing_place parsing_place;
/* work with 'substitution' */ /* work with 'substitution' */
bool have_to_be_excluded; bool have_to_be_excluded;
/* cache of constant state */ /* cache of constant state */
......
...@@ -293,6 +293,13 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); ...@@ -293,6 +293,13 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
*/ */
#define MAX_DATE_REP_LENGTH 30 #define MAX_DATE_REP_LENGTH 30
enum enum_parsing_place
{
NO_MATTER,
IN_HAVING,
SELECT_LIST
};
struct st_table; struct st_table;
class THD; class THD;
class Statement; class Statement;
......
...@@ -1017,7 +1017,7 @@ void st_select_lex::init_query() ...@@ -1017,7 +1017,7 @@ void st_select_lex::init_query()
select_n_having_items= 0; select_n_having_items= 0;
prep_where= 0; prep_where= 0;
subquery_in_having= explicit_limit= 0; subquery_in_having= explicit_limit= 0;
parsing_place= SELECT_LEX_NODE::NO_MATTER; parsing_place= NO_MATTER;
} }
void st_select_lex::init_select() void st_select_lex::init_select()
......
...@@ -220,12 +220,6 @@ class st_select_lex_node { ...@@ -220,12 +220,6 @@ class st_select_lex_node {
*master, *slave, /* vertical links */ *master, *slave, /* vertical links */
*link_next, **link_prev; /* list of whole SELECT_LEX */ *link_next, **link_prev; /* list of whole SELECT_LEX */
public: public:
enum enum_parsing_place
{
NO_MATTER,
IN_HAVING,
SELECT_LIST
};
ulong options; ulong options;
/* /*
......
...@@ -1113,11 +1113,11 @@ create_select: ...@@ -1113,11 +1113,11 @@ create_select:
lex->sql_command= SQLCOM_REPLACE_SELECT; lex->sql_command= SQLCOM_REPLACE_SELECT;
lex->current_select->table_list.save_and_clear(&lex->save_list); lex->current_select->table_list.save_and_clear(&lex->save_list);
mysql_init_select(lex); mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST; lex->current_select->parsing_place= SELECT_LIST;
} }
select_options select_item_list select_options select_item_list
{ {
Select->parsing_place= SELECT_LEX_NODE::NO_MATTER; Select->parsing_place= NO_MATTER;
} }
opt_select_from opt_select_from
{ Lex->current_select->table_list.push_front(&Lex->save_list); } { Lex->current_select->table_list.push_front(&Lex->save_list); }
...@@ -2370,11 +2370,11 @@ select_part2: ...@@ -2370,11 +2370,11 @@ select_part2:
lex->lock_option= TL_READ; lex->lock_option= TL_READ;
if (sel->linkage != UNION_TYPE) if (sel->linkage != UNION_TYPE)
mysql_init_select(lex); mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST; lex->current_select->parsing_place= SELECT_LIST;
} }
select_options select_item_list select_options select_item_list
{ {
Select->parsing_place= SELECT_LEX_NODE::NO_MATTER; Select->parsing_place= NO_MATTER;
} }
select_into select_lock_type; select_into select_lock_type;
...@@ -3438,11 +3438,11 @@ select_derived: ...@@ -3438,11 +3438,11 @@ select_derived:
YYABORT; YYABORT;
mysql_init_select(lex); mysql_init_select(lex);
lex->current_select->linkage= DERIVED_TABLE_TYPE; lex->current_select->linkage= DERIVED_TABLE_TYPE;
lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST; lex->current_select->parsing_place= SELECT_LIST;
} }
select_options select_item_list select_options select_item_list
{ {
Select->parsing_place= SELECT_LEX_NODE::NO_MATTER; Select->parsing_place= NO_MATTER;
} }
opt_select_from union_opt opt_select_from union_opt
; ;
...@@ -3572,13 +3572,13 @@ having_clause: ...@@ -3572,13 +3572,13 @@ having_clause:
/* empty */ /* empty */
| HAVING | HAVING
{ {
Select->parsing_place= SELECT_LEX_NODE::IN_HAVING; Select->parsing_place= IN_HAVING;
} }
expr expr
{ {
SELECT_LEX *sel= Select; SELECT_LEX *sel= Select;
sel->having= $3; sel->having= $3;
sel->parsing_place= SELECT_LEX_NODE::NO_MATTER; sel->parsing_place= NO_MATTER;
if ($3) if ($3)
$3->top_level_item(); $3->top_level_item();
} }
...@@ -4813,7 +4813,7 @@ simple_ident: ...@@ -4813,7 +4813,7 @@ simple_ident:
ident ident
{ {
SELECT_LEX *sel=Select; SELECT_LEX *sel=Select;
$$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ? sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_field(NullS,NullS,$1.str) :
(Item*) new Item_ref(0,0, NullS,NullS,$1.str); (Item*) new Item_ref(0,0, NullS,NullS,$1.str);
...@@ -4829,7 +4829,7 @@ simple_ident: ...@@ -4829,7 +4829,7 @@ simple_ident:
ER(ER_TABLENAME_NOT_ALLOWED_HERE), ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $1.str, thd->where); MYF(0), $1.str, thd->where);
} }
$$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ? sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_field(NullS,$1.str,$3.str) :
(Item*) new Item_ref(0,0,NullS,$1.str,$3.str); (Item*) new Item_ref(0,0,NullS,$1.str,$3.str);
...@@ -4845,7 +4845,7 @@ simple_ident: ...@@ -4845,7 +4845,7 @@ simple_ident:
ER(ER_TABLENAME_NOT_ALLOWED_HERE), ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $2.str, thd->where); MYF(0), $2.str, thd->where);
} }
$$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ? sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_field(NullS,$2.str,$4.str) :
(Item*) new Item_ref(0,0,NullS,$2.str,$4.str); (Item*) new Item_ref(0,0,NullS,$2.str,$4.str);
...@@ -4861,7 +4861,7 @@ simple_ident: ...@@ -4861,7 +4861,7 @@ simple_ident:
ER(ER_TABLENAME_NOT_ALLOWED_HERE), ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $3.str, thd->where); MYF(0), $3.str, thd->where);
} }
$$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ? sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field((YYTHD->client_capabilities & (Item*) new Item_field((YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str), CLIENT_NO_SCHEMA ? NullS : $1.str),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment