Commit 9addd5f7 authored by unknown's avatar unknown

Merge poseidon.ndb.mysql.com:/home/tomas/mysql-4.1

into poseidon.ndb.mysql.com:/home/tomas/mysql-4.1-ndb-merge

parents e6145414 1073271b
This diff is collapsed.
drop table if exists t1;
CREATE TABLE t1 (a INT);
EXPLAIN
SELECT *
INTO OUTFILE '/tmp/t1.txt'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\r\n'
FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
DROP TABLE t1;
...@@ -901,6 +901,8 @@ set group_concat_max_len=10; ...@@ -901,6 +901,8 @@ set group_concat_max_len=10;
select group_concat(a) FROM t1 group by b; select group_concat(a) FROM t1 group by b;
group_concat(a) group_concat(a)
1234567890 1234567890
Warnings:
Warning 1260 1 line(s) were cut by GROUP_CONCAT()
set group_concat_max_len=1024; set group_concat_max_len=1024;
select group_concat(a) FROM t1 group by b; select group_concat(a) FROM t1 group by b;
group_concat(a) group_concat(a)
......
...@@ -240,3 +240,40 @@ SELECT t1.A_ID, GROUP_CONCAT(t2.B_DESC) AS B_DESC FROM t1 LEFT JOIN t2 ON t1.A_I ...@@ -240,3 +240,40 @@ SELECT t1.A_ID, GROUP_CONCAT(t2.B_DESC) AS B_DESC FROM t1 LEFT JOIN t2 ON t1.A_I
DROP TABLE t1; DROP TABLE t1;
DROP TABLE t2; DROP TABLE t2;
#
# blobs
#
create table t1 (a int, b text);
insert into t1 values (1, 'bb'), (1, 'ccc'), (1, 'a'), (1, 'bb'), (1, 'ccc');
insert into t1 values (2, 'BB'), (2, 'CCC'), (2, 'A'), (2, 'BB'), (2, 'CCC');
select group_concat(b) from t1 group by a;
select group_concat(distinct b) from t1 group by a;
select group_concat(b order by b) from t1 group by a;
select group_concat(distinct b order by b) from t1 group by a;
set local group_concat_max_len=4;
select group_concat(b) from t1 group by a;
select group_concat(distinct b) from t1 group by a;
select group_concat(b order by b) from t1 group by a;
select group_concat(distinct b order by b) from t1 group by a;
#
# long blobs
#
insert into t1 values (1, concat(repeat('1', 300), '2')),
(1, concat(repeat('1', 300), '2')), (1, concat(repeat('0', 300), '1')),
(2, concat(repeat('1', 300), '2')), (2, concat(repeat('1', 300), '2')),
(2, concat(repeat('0', 300), '1'));
set local group_concat_max_len=1024;
select group_concat(b) from t1 group by a;
select group_concat(distinct b) from t1 group by a;
select group_concat(b order by b) from t1 group by a;
select group_concat(distinct b order by b) from t1 group by a;
set local group_concat_max_len=400;
select group_concat(b) from t1 group by a;
select group_concat(distinct b) from t1 group by a;
select group_concat(b order by b) from t1 group by a;
select group_concat(distinct b order by b) from t1 group by a;
drop table t1;
...@@ -2,9 +2,12 @@ ...@@ -2,9 +2,12 @@
# test of into outfile|dumpfile # test of into outfile|dumpfile
# #
--disable_warnings
drop table if exists t1;
--enable_warnings
# We need to check that we have 'file' privilege. # We need to check that we have 'file' privilege.
#drop table if exists t1;
#create table t1 (`a` blob); #create table t1 (`a` blob);
#insert into t1 values("hello world"),("Hello mars"),(NULL); #insert into t1 values("hello world"),("Hello mars"),(NULL);
#select * into outfile "/tmp/select-test.1" from t1; #select * into outfile "/tmp/select-test.1" from t1;
...@@ -26,3 +29,15 @@ ...@@ -26,3 +29,15 @@
#INSERT INTO t VALUES ('2002-12-20 12:01:20','',1,"aaa","bbb"); #INSERT INTO t VALUES ('2002-12-20 12:01:20','',1,"aaa","bbb");
#select * from t into outfile "check"; #select * from t into outfile "check";
#drop table if exists t; #drop table if exists t;
#
# Bug #5382: 'explain select into outfile' crashes the server
#
CREATE TABLE t1 (a INT);
EXPLAIN
SELECT *
INTO OUTFILE '/tmp/t1.txt'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\r\n'
FROM t1;
DROP TABLE t1;
...@@ -1871,16 +1871,20 @@ bool Item_func_group_concat::add() ...@@ -1871,16 +1871,20 @@ bool Item_func_group_concat::add()
} }
null_value= FALSE; null_value= FALSE;
TREE_ELEMENT *el= 0; // Only for safety
if (tree_mode) if (tree_mode)
{ el= tree_insert(tree, table->record[0], 0, tree->custom_arg);
if (!tree_insert(tree, table->record[0], 0, tree->custom_arg)) /*
return 1; If the row is not a duplicate (el->count == 1)
} we can dump the row here in case of GROUP_CONCAT(DISTINCT...)
else instead of doing tree traverse later.
{ */
if (result.length() <= group_concat_max_len && !warning_for_row) if (result.length() <= group_concat_max_len &&
!warning_for_row &&
(!tree_mode || (el->count == 1 && distinct && !arg_count_order)))
dump_leaf_key(table->record[0], 1, this); dump_leaf_key(table->record[0], 1, this);
}
return 0; return 0;
} }
...@@ -1926,6 +1930,8 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -1926,6 +1930,8 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
thd->allow_sum_func= 1; thd->allow_sum_func= 1;
if (!(tmp_table_param= new TMP_TABLE_PARAM)) if (!(tmp_table_param= new TMP_TABLE_PARAM))
return 1; return 1;
/* We'll convert all blobs to varchar fields in the temporary table */
tmp_table_param->convert_blob_length= group_concat_max_len;
tables_list= tables; tables_list= tables;
fixed= 1; fixed= 1;
return 0; return 0;
...@@ -2023,8 +2029,6 @@ bool Item_func_group_concat::setup(THD *thd) ...@@ -2023,8 +2029,6 @@ bool Item_func_group_concat::setup(THD *thd)
} }
else else
{ {
compare_key= NULL;
if (distinct)
compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct; compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct;
} }
/* /*
...@@ -2068,6 +2072,12 @@ String* Item_func_group_concat::val_str(String* str) ...@@ -2068,6 +2072,12 @@ String* Item_func_group_concat::val_str(String* str)
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (null_value) if (null_value)
return 0; return 0;
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);
}
if (result.length()) if (result.length())
return &result; return &result;
if (tree_mode) if (tree_mode)
...@@ -2075,12 +2085,6 @@ String* Item_func_group_concat::val_str(String* str) ...@@ -2075,12 +2085,6 @@ String* Item_func_group_concat::val_str(String* str)
tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this, tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
left_root_right); left_root_right);
} }
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; return &result;
} }
......
...@@ -521,7 +521,7 @@ int mysql_union(THD *thd, LEX *lex, select_result *result, ...@@ -521,7 +521,7 @@ int mysql_union(THD *thd, LEX *lex, select_result *result,
int mysql_handle_derived(LEX *lex); int mysql_handle_derived(LEX *lex);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field, Item ***copy_func, Field **from_field,
bool group,bool modify_item); bool group, bool modify_item, uint convert_blob_length);
int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
List<create_field> &fields, List<create_field> &fields,
List<Key> &keys, uint &db_options, List<Key> &keys, uint &db_options,
......
...@@ -1250,10 +1250,12 @@ public: ...@@ -1250,10 +1250,12 @@ public:
uint group_parts,group_length,group_null_parts; uint group_parts,group_length,group_null_parts;
uint quick_group; uint quick_group;
bool using_indirect_summary_function; bool using_indirect_summary_function;
/* If >0 convert all blob fields to varchar(convert_blob_length) */
uint convert_blob_length;
TMP_TABLE_PARAM() TMP_TABLE_PARAM()
:copy_funcs_it(copy_funcs), copy_field(0), group_parts(0), :copy_funcs_it(copy_funcs), copy_field(0), group_parts(0),
group_length(0), group_null_parts(0) group_length(0), group_null_parts(0), convert_blob_length(0)
{} {}
~TMP_TABLE_PARAM() ~TMP_TABLE_PARAM()
{ {
......
...@@ -4583,21 +4583,28 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) ...@@ -4583,21 +4583,28 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
the record in the original table. the record in the original table.
If modify_item is 0 then fill_record() will update If modify_item is 0 then fill_record() will update
the temporary table the temporary table
convert_blob_length If >0 create a varstring(convert_blob_length) field
instead of blob.
RETURN RETURN
0 on error 0 on error
new_created field new_created field
*/ */
static Field* create_tmp_field_from_field(THD *thd,
Field* org_field, static Field* create_tmp_field_from_field(THD *thd, Field* org_field,
Item *item, Item *item, TABLE *table,
TABLE *table, bool modify_item,
bool modify_item) uint convert_blob_length)
{ {
Field *new_field; Field *new_field;
// The following should always be true if (convert_blob_length && org_field->flags & BLOB_FLAG)
if ((new_field= org_field->new_field(&thd->mem_root,table))) new_field= new Field_varstring(convert_blob_length, org_field->maybe_null(),
org_field->field_name, table,
org_field->charset());
else
new_field= org_field->new_field(&thd->mem_root, table);
if (new_field)
{ {
if (modify_item) if (modify_item)
((Item_field *)item)->result_field= new_field; ((Item_field *)item)->result_field= new_field;
...@@ -4628,16 +4635,16 @@ static Field* create_tmp_field_from_field(THD *thd, ...@@ -4628,16 +4635,16 @@ static Field* create_tmp_field_from_field(THD *thd,
the record in the original table. the record in the original table.
If modify_item is 0 then fill_record() will update If modify_item is 0 then fill_record() will update
the temporary table the temporary table
convert_blob_length If >0 create a varstring(convert_blob_length) field
instead of blob.
RETURN RETURN
0 on error 0 on error
new_created field new_created field
*/ */
static Field* create_tmp_field_from_item(THD *thd, static Field* create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
Item *item, Item ***copy_func, bool modify_item,
TABLE *table, uint convert_blob_length)
Item ***copy_func,
bool modify_item)
{ {
bool maybe_null=item->maybe_null; bool maybe_null=item->maybe_null;
Field *new_field; Field *new_field;
...@@ -4654,13 +4661,18 @@ static Field* create_tmp_field_from_item(THD *thd, ...@@ -4654,13 +4661,18 @@ static Field* create_tmp_field_from_item(THD *thd,
break; break;
case STRING_RESULT: case STRING_RESULT:
if (item->max_length > 255) if (item->max_length > 255)
new_field= new Field_blob(item->max_length, maybe_null, {
if (convert_blob_length)
new_field= new Field_varstring(convert_blob_length, maybe_null,
item->name, table, item->name, table,
item->collation.collation); item->collation.collation);
else else
new_field= new Field_string(item->max_length, maybe_null, new_field= new Field_blob(item->max_length, maybe_null, item->name,
item->name, table, table, item->collation.collation);
item->collation.collation); }
else
new_field= new Field_string(item->max_length, maybe_null, item->name,
table, item->collation.collation);
break; break;
case ROW_RESULT: case ROW_RESULT:
default: default:
...@@ -4697,6 +4709,8 @@ static Field* create_tmp_field_from_item(THD *thd, ...@@ -4697,6 +4709,8 @@ static Field* create_tmp_field_from_item(THD *thd,
the record in the original table. the record in the original table.
If modify_item is 0 then fill_record() will update If modify_item is 0 then fill_record() will update
the temporary table the temporary table
convert_blob_length If >0 create a varstring(convert_blob_length) field
instead of blob.
RETURN RETURN
0 on error 0 on error
...@@ -4705,7 +4719,7 @@ static Field* create_tmp_field_from_item(THD *thd, ...@@ -4705,7 +4719,7 @@ static Field* create_tmp_field_from_item(THD *thd,
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field, Item ***copy_func, Field **from_field,
bool group, bool modify_item) bool group, bool modify_item, uint convert_blob_length)
{ {
switch (type) { switch (type) {
case Item::SUM_FUNC_ITEM: case Item::SUM_FUNC_ITEM:
...@@ -4740,8 +4754,15 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, ...@@ -4740,8 +4754,15 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
item->name,table,item->unsigned_flag); item->name,table,item->unsigned_flag);
case STRING_RESULT: case STRING_RESULT:
if (item_sum->max_length > 255) if (item_sum->max_length > 255)
return new Field_blob(item_sum->max_length,maybe_null, {
item->name,table,item->collation.collation); if (convert_blob_length)
return new Field_varstring(convert_blob_length, maybe_null,
item->name, table,
item->collation.collation);
else
return new Field_blob(item_sum->max_length, maybe_null, item->name,
table, item->collation.collation);
}
return new Field_string(item_sum->max_length,maybe_null, return new Field_string(item_sum->max_length,maybe_null,
item->name,table,item->collation.collation); item->name,table,item->collation.collation);
case ROW_RESULT: case ROW_RESULT:
...@@ -4758,8 +4779,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, ...@@ -4758,8 +4779,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::DEFAULT_VALUE_ITEM: case Item::DEFAULT_VALUE_ITEM:
{ {
Item_field *field= (Item_field*) item; Item_field *field= (Item_field*) item;
return create_tmp_field_from_field(thd, (*from_field= field->field), return create_tmp_field_from_field(thd, (*from_field= field->field), item,
item, table, modify_item); table, modify_item, convert_blob_length);
} }
case Item::FUNC_ITEM: case Item::FUNC_ITEM:
case Item::COND_ITEM: case Item::COND_ITEM:
...@@ -4774,14 +4795,16 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, ...@@ -4774,14 +4795,16 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::REF_ITEM: case Item::REF_ITEM:
case Item::NULL_ITEM: case Item::NULL_ITEM:
case Item::VARBIN_ITEM: case Item::VARBIN_ITEM:
return create_tmp_field_from_item(thd, item, table, return create_tmp_field_from_item(thd, item, table, copy_func, modify_item,
copy_func, modify_item); convert_blob_length);
case Item::TYPE_HOLDER: case Item::TYPE_HOLDER:
{ {
Field *example= ((Item_type_holder *)item)->example(); Field *example= ((Item_type_holder *)item)->example();
if (example) if (example)
return create_tmp_field_from_field(thd, example, item, table, 0); return create_tmp_field_from_field(thd, example, item, table, 0,
return create_tmp_field_from_item(thd, item, table, copy_func, 0); convert_blob_length);
return create_tmp_field_from_item(thd, item, table, copy_func, 0,
convert_blob_length);
} }
default: // Dosen't have to be stored default: // Dosen't have to be stored
return 0; return 0;
...@@ -4945,8 +4968,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -4945,8 +4968,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!arg->const_item()) if (!arg->const_item())
{ {
Field *new_field= Field *new_field=
create_tmp_field(thd, table,arg,arg->type(),&copy_func, create_tmp_field(thd, table, arg, arg->type(), &copy_func,
tmp_from_field, group != 0,not_all_columns); tmp_from_field, group != 0,not_all_columns,
param->convert_blob_length);
if (!new_field) if (!new_field)
goto err; // Should be OOM goto err; // Should be OOM
tmp_from_field++; tmp_from_field++;
...@@ -4982,9 +5006,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -4982,9 +5006,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
We here distinguish between UNION and multi-table-updates by the fact We here distinguish between UNION and multi-table-updates by the fact
that in the later case group is set to the row pointer. that in the later case group is set to the row pointer.
*/ */
Field *new_field=create_tmp_field(thd, table, item,type, &copy_func, Field *new_field= create_tmp_field(thd, table, item, type, &copy_func,
tmp_from_field, group != 0, tmp_from_field, group != 0,
not_all_columns || group !=0); not_all_columns || group !=0,
param->convert_blob_length);
if (!new_field) if (!new_field)
{ {
if (thd->is_fatal_error) if (thd->is_fatal_error)
......
...@@ -1378,7 +1378,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, ...@@ -1378,7 +1378,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
field=item->tmp_table_field(&tmp_table); field=item->tmp_table_field(&tmp_table);
else else
field=create_tmp_field(thd, &tmp_table, item, item->type(), field=create_tmp_field(thd, &tmp_table, item, item->type(),
(Item ***) 0, &tmp_field,0,0); (Item ***) 0, &tmp_field, 0, 0, 0);
if (!field || if (!field ||
!(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
((Item_field *)item)->field : ((Item_field *)item)->field :
......
...@@ -3870,16 +3870,12 @@ select_var_ident: '@' ident_or_text ...@@ -3870,16 +3870,12 @@ select_var_ident: '@' ident_or_text
into: into:
INTO OUTFILE TEXT_STRING_sys INTO OUTFILE TEXT_STRING_sys
{ {
LEX *lex=Lex; LEX *lex= Lex;
if (!lex->describe)
{
lex->uncacheable(UNCACHEABLE_SIDEEFFECT); lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($3.str,0))) if (!(lex->exchange= new sql_exchange($3.str, 0)) ||
YYABORT; !(lex->result= new select_export(lex->exchange)))
if (!(lex->result= new select_export(lex->exchange)))
YYABORT; YYABORT;
} }
}
opt_field_term opt_line_term opt_field_term opt_line_term
| INTO DUMPFILE TEXT_STRING_sys | INTO DUMPFILE TEXT_STRING_sys
{ {
...@@ -4721,15 +4717,28 @@ field_term_list: ...@@ -4721,15 +4717,28 @@ field_term_list:
| field_term; | field_term;
field_term: field_term:
TERMINATED BY text_string { Lex->exchange->field_term= $3;} TERMINATED BY text_string
{
DBUG_ASSERT(Lex->exchange);
Lex->exchange->field_term= $3;
}
| OPTIONALLY ENCLOSED BY text_string | OPTIONALLY ENCLOSED BY text_string
{ {
LEX *lex=Lex; LEX *lex= Lex;
DBUG_ASSERT(lex->exchange);
lex->exchange->enclosed= $4; lex->exchange->enclosed= $4;
lex->exchange->opt_enclosed=1; lex->exchange->opt_enclosed= 1;
} }
| ENCLOSED BY text_string { Lex->exchange->enclosed= $3;} | ENCLOSED BY text_string
| ESCAPED BY text_string { Lex->exchange->escaped= $3;}; {
DBUG_ASSERT(Lex->exchange);
Lex->exchange->enclosed= $3;
}
| ESCAPED BY text_string
{
DBUG_ASSERT(Lex->exchange);
Lex->exchange->escaped= $3;
};
opt_line_term: opt_line_term:
/* empty */ /* empty */
...@@ -4740,13 +4749,24 @@ line_term_list: ...@@ -4740,13 +4749,24 @@ line_term_list:
| line_term; | line_term;
line_term: line_term:
TERMINATED BY text_string { Lex->exchange->line_term= $3;} TERMINATED BY text_string
| STARTING BY text_string { Lex->exchange->line_start= $3;}; {
DBUG_ASSERT(Lex->exchange);
Lex->exchange->line_term= $3;
}
| STARTING BY text_string
{
DBUG_ASSERT(Lex->exchange);
Lex->exchange->line_start= $3;
};
opt_ignore_lines: opt_ignore_lines:
/* empty */ /* empty */
| IGNORE_SYM NUM LINES | IGNORE_SYM NUM LINES
{ Lex->exchange->skip_lines=atol($2.str); }; {
DBUG_ASSERT(Lex->exchange);
Lex->exchange->skip_lines= atol($2.str);
};
/* Common definitions */ /* Common definitions */
......
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