Merge work:/home/bk/mysql-4.0 into donna.mysql.fi:/home/my/bk/mysql-4.0
This commit is contained in:
commit
fe983ca7b3
@ -108,7 +108,11 @@ extern int NEAR my_errno; /* Last error in mysys */
|
|||||||
|
|
||||||
/* root_alloc flags */
|
/* root_alloc flags */
|
||||||
#define MY_KEEP_PREALLOC 1
|
#define MY_KEEP_PREALLOC 1
|
||||||
|
#define MY_MARK_BLOCKS_FREE 2 /* do not my_free() blocks,
|
||||||
|
just move used into free list
|
||||||
|
and mark all blocks as fully free
|
||||||
|
*/
|
||||||
|
|
||||||
/* defines when allocating data */
|
/* defines when allocating data */
|
||||||
|
|
||||||
#ifdef SAFEMALLOC
|
#ifdef SAFEMALLOC
|
||||||
|
@ -62,6 +62,9 @@ void init_tree(TREE *tree,uint default_alloc_size, int element_size,
|
|||||||
qsort_cmp2 compare, my_bool with_delete,
|
qsort_cmp2 compare, my_bool with_delete,
|
||||||
void (*free_element)(void*));
|
void (*free_element)(void*));
|
||||||
void delete_tree(TREE*);
|
void delete_tree(TREE*);
|
||||||
|
void reset_tree(TREE*);
|
||||||
|
/* similar to delete tree, except we do not my_free() blocks in mem_root
|
||||||
|
*/
|
||||||
#define is_tree_inited(tree) ((tree)->root != 0)
|
#define is_tree_inited(tree) ((tree)->root != 0)
|
||||||
|
|
||||||
/* Functions on leafs */
|
/* Functions on leafs */
|
||||||
|
@ -463,7 +463,7 @@ start_master()
|
|||||||
--core \
|
--core \
|
||||||
--tmpdir=$MYSQL_TMP_DIR \
|
--tmpdir=$MYSQL_TMP_DIR \
|
||||||
--language=english \
|
--language=english \
|
||||||
--innobase_data_file_path=ibdata1:50M \
|
--innodb_data_file_path=ibdata1:50M \
|
||||||
$SMALL_SERVER \
|
$SMALL_SERVER \
|
||||||
$EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT"
|
$EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT"
|
||||||
fi
|
fi
|
||||||
|
76
mysql-test/r/count_distinct2.result
Normal file
76
mysql-test/r/count_distinct2.result
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
n1
|
||||||
|
1
|
||||||
|
2
|
||||||
|
NULL
|
||||||
|
count(distinct n1)
|
||||||
|
2
|
||||||
|
n2
|
||||||
|
11
|
||||||
|
12
|
||||||
|
13
|
||||||
|
NULL
|
||||||
|
count(distinct n2)
|
||||||
|
3
|
||||||
|
s
|
||||||
|
one
|
||||||
|
two
|
||||||
|
NULL
|
||||||
|
count(distinct s)
|
||||||
|
2
|
||||||
|
vs
|
||||||
|
eleven
|
||||||
|
twevle
|
||||||
|
thirteen
|
||||||
|
NULL
|
||||||
|
count(distinct vs)
|
||||||
|
3
|
||||||
|
t
|
||||||
|
eleven
|
||||||
|
twelve
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
NULL
|
||||||
|
count(distinct t)
|
||||||
|
4
|
||||||
|
n1 n2
|
||||||
|
1 11
|
||||||
|
2 11
|
||||||
|
2 12
|
||||||
|
2 13
|
||||||
|
NULL 13
|
||||||
|
2 NULL
|
||||||
|
count(distinct n1,n2)
|
||||||
|
4
|
||||||
|
n1 s
|
||||||
|
1 one
|
||||||
|
2 two
|
||||||
|
NULL two
|
||||||
|
2 NULL
|
||||||
|
count(distinct n1,s)
|
||||||
|
2
|
||||||
|
s n1 vs
|
||||||
|
one 1 eleven
|
||||||
|
two 2 eleven
|
||||||
|
two 2 twevle
|
||||||
|
two 2 thirteen
|
||||||
|
two NULL thirteen
|
||||||
|
NULL 2 thirteen
|
||||||
|
two 2 NULL
|
||||||
|
count(distinct s,n1,vs)
|
||||||
|
4
|
||||||
|
s t
|
||||||
|
one eleven
|
||||||
|
two eleven
|
||||||
|
two twelve
|
||||||
|
two foo
|
||||||
|
two bar
|
||||||
|
NULL bar
|
||||||
|
two NULL
|
||||||
|
count(distinct s,t)
|
||||||
|
5
|
||||||
|
count(distinct n1) count(distinct n2)
|
||||||
|
2 3
|
||||||
|
count(distinct n2) n1
|
||||||
|
1 NULL
|
||||||
|
1 1
|
||||||
|
3 2
|
45
mysql-test/t/count_distinct2.test
Normal file
45
mysql-test/t/count_distinct2.test
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
create table t1(n1 int, n2 int, s char(20), vs varchar(20), t text);
|
||||||
|
insert into t1 values (1,11, 'one','eleven', 'eleven'),
|
||||||
|
(1,11, 'one','eleven', 'eleven'),
|
||||||
|
(2,11, 'two','eleven', 'eleven'),
|
||||||
|
(2,12, 'two','twevle', 'twelve'),
|
||||||
|
(2,13, 'two','thirteen', 'foo'),
|
||||||
|
(2,13, 'two','thirteen', 'foo'),
|
||||||
|
(2,13, 'two','thirteen', 'bar'),
|
||||||
|
(NULL,13, 'two','thirteen', 'bar'),
|
||||||
|
(2,NULL, 'two','thirteen', 'bar'),
|
||||||
|
(2,13, NULL,'thirteen', 'bar'),
|
||||||
|
(2,13, 'two',NULL, 'bar'),
|
||||||
|
(2,13, 'two','thirteen', NULL);
|
||||||
|
|
||||||
|
select distinct n1 from t1;
|
||||||
|
select count(distinct n1) from t1;
|
||||||
|
|
||||||
|
select distinct n2 from t1;
|
||||||
|
select count(distinct n2) from t1;
|
||||||
|
|
||||||
|
select distinct s from t1;
|
||||||
|
select count(distinct s) from t1;
|
||||||
|
|
||||||
|
select distinct vs from t1;
|
||||||
|
select count(distinct vs) from t1;
|
||||||
|
|
||||||
|
select distinct t from t1;
|
||||||
|
select count(distinct t) from t1;
|
||||||
|
|
||||||
|
select distinct n1,n2 from t1;
|
||||||
|
select count(distinct n1,n2) from t1;
|
||||||
|
|
||||||
|
select distinct n1,s from t1;
|
||||||
|
select count(distinct n1,s) from t1;
|
||||||
|
|
||||||
|
select distinct s,n1,vs from t1;
|
||||||
|
select count(distinct s,n1,vs) from t1;
|
||||||
|
|
||||||
|
select distinct s,t from t1;
|
||||||
|
select count(distinct s,t) from t1;
|
||||||
|
|
||||||
|
select count(distinct n1), count(distinct n2) from t1;
|
||||||
|
|
||||||
|
select count(distinct n2), n1 from t1 group by n1;
|
||||||
|
drop table t1;
|
@ -100,7 +100,41 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deallocate everything used by alloc_root */
|
static inline void mark_blocks_free(MEM_ROOT* root)
|
||||||
|
{
|
||||||
|
reg1 USED_MEM *next,*last = 0;
|
||||||
|
|
||||||
|
/* iterate through (partially) free blocks, mark them fully free */
|
||||||
|
for(next = root->free; next; next = next->next )
|
||||||
|
{
|
||||||
|
last = next;
|
||||||
|
next->left = next->size - ALIGN_SIZE(sizeof(USED_MEM));
|
||||||
|
}
|
||||||
|
/* if free block list was not empty, point the next of the
|
||||||
|
last free block to the beginning of the used list */
|
||||||
|
next = root->used; /* a little optimization to avoid dereferencing root
|
||||||
|
twice - we will shortly start iterating through used
|
||||||
|
list */
|
||||||
|
if(last)
|
||||||
|
last->next = next;
|
||||||
|
else /* if free list is empty, just point it to the current used*/
|
||||||
|
root->free = next;
|
||||||
|
|
||||||
|
/* now go through the current used list, and mark each block
|
||||||
|
as fully free. Note that because of our optimization, we do not
|
||||||
|
need to initialize next here - see above
|
||||||
|
*/
|
||||||
|
for(;next; next = next->next)
|
||||||
|
next->left = next->size - ALIGN_SIZE(sizeof(USED_MEM));
|
||||||
|
|
||||||
|
/* Now everything is set - we just need to indicate that nothing is used
|
||||||
|
anymore
|
||||||
|
*/
|
||||||
|
root->used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deallocate everything used by alloc_root or just move
|
||||||
|
used blocks to free list if called with MY_USED_TO_FREE */
|
||||||
|
|
||||||
void free_root(MEM_ROOT *root, myf MyFlags)
|
void free_root(MEM_ROOT *root, myf MyFlags)
|
||||||
{
|
{
|
||||||
@ -109,6 +143,11 @@ void free_root(MEM_ROOT *root, myf MyFlags)
|
|||||||
|
|
||||||
if (!root)
|
if (!root)
|
||||||
DBUG_VOID_RETURN; /* purecov: inspected */
|
DBUG_VOID_RETURN; /* purecov: inspected */
|
||||||
|
if(MyFlags & MY_MARK_BLOCKS_FREE)
|
||||||
|
{
|
||||||
|
mark_blocks_free(root);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
if (!(MyFlags & MY_KEEP_PREALLOC))
|
if (!(MyFlags & MY_KEEP_PREALLOC))
|
||||||
root->pre_alloc=0;
|
root->pre_alloc=0;
|
||||||
|
|
||||||
|
18
mysys/tree.c
18
mysys/tree.c
@ -103,9 +103,9 @@ void init_tree(TREE *tree, uint default_alloc_size, int size,
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_tree(TREE *tree)
|
static void free_tree(TREE *tree, myf free_flags)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("delete_tree");
|
DBUG_ENTER("free_tree");
|
||||||
DBUG_PRINT("enter",("tree: %lx",tree));
|
DBUG_PRINT("enter",("tree: %lx",tree));
|
||||||
|
|
||||||
if (tree->root) /* If initialized */
|
if (tree->root) /* If initialized */
|
||||||
@ -116,7 +116,7 @@ void delete_tree(TREE *tree)
|
|||||||
{
|
{
|
||||||
if (tree->free)
|
if (tree->free)
|
||||||
delete_tree_element(tree,tree->root);
|
delete_tree_element(tree,tree->root);
|
||||||
free_root(&tree->mem_root,MYF(0));
|
free_root(&tree->mem_root, free_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tree->root= &tree->null_element;
|
tree->root= &tree->null_element;
|
||||||
@ -125,6 +125,18 @@ void delete_tree(TREE *tree)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void delete_tree(TREE* tree)
|
||||||
|
{
|
||||||
|
free_tree(tree, MYF(0)); /* my_free() mem_root if applicable */
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_tree(TREE* tree)
|
||||||
|
{
|
||||||
|
free_tree(tree, MYF(MY_MARK_BLOCKS_FREE));
|
||||||
|
/* do not my_free() mem_root if applicable, just mark blocks as free */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void delete_tree_element(TREE *tree, TREE_ELEMENT *element)
|
static void delete_tree_element(TREE *tree, TREE_ELEMENT *element)
|
||||||
{
|
{
|
||||||
if (element != &tree->null_element)
|
if (element != &tree->null_element)
|
||||||
|
@ -810,12 +810,13 @@ int composite_key_cmp(void* arg, byte* key1, byte* key2)
|
|||||||
for(; field < field_end; ++field)
|
for(; field < field_end; ++field)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int len = (*field)->field_length;
|
Field* f = *field;
|
||||||
|
int len = f->field_length;
|
||||||
switch((*field)->type())
|
switch((*field)->type())
|
||||||
{
|
{
|
||||||
case FIELD_TYPE_STRING:
|
case FIELD_TYPE_STRING:
|
||||||
case FIELD_TYPE_VAR_STRING:
|
case FIELD_TYPE_VAR_STRING:
|
||||||
res = my_sortcmp(key1, key2, len);
|
res = f->key_cmp(key1, key2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res = memcmp(key1, key2, len);
|
res = memcmp(key1, key2, len);
|
||||||
@ -879,20 +880,22 @@ bool Item_sum_count_distinct::setup(THD *thd)
|
|||||||
// to use a simpler key compare method that can take advantage
|
// to use a simpler key compare method that can take advantage
|
||||||
// of not having to worry about other fields
|
// of not having to worry about other fields
|
||||||
{
|
{
|
||||||
switch(table->field[0]->type())
|
Field* field = table->field[0];
|
||||||
|
switch(field->type())
|
||||||
{
|
{
|
||||||
// if we have a string, we must take care of charsets
|
// if we have a string, we must take care of charsets
|
||||||
// and case sensitivity
|
// and case sensitivity
|
||||||
case FIELD_TYPE_STRING:
|
case FIELD_TYPE_STRING:
|
||||||
case FIELD_TYPE_VAR_STRING:
|
case FIELD_TYPE_VAR_STRING:
|
||||||
compare_key = (qsort_cmp2)simple_str_key_cmp;
|
compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp:
|
||||||
|
simple_str_key_cmp);
|
||||||
break;
|
break;
|
||||||
default: // since at this point we cannot have blobs
|
default: // since at this point we cannot have blobs
|
||||||
// anything else can be compared with memcmp
|
// anything else can be compared with memcmp
|
||||||
compare_key = (qsort_cmp2)simple_raw_key_cmp;
|
compare_key = (qsort_cmp2)simple_raw_key_cmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmp_arg = (void*)(key_len = table->field[0]->field_length);
|
cmp_arg = (void*)(key_len = field->field_length);
|
||||||
rec_offset = 1;
|
rec_offset = 1;
|
||||||
}
|
}
|
||||||
else // too bad, cannot cheat - there is more than one field
|
else // too bad, cannot cheat - there is more than one field
|
||||||
@ -908,7 +911,8 @@ bool Item_sum_count_distinct::setup(THD *thd)
|
|||||||
rec_offset = table->reclength - key_len;
|
rec_offset = table->reclength - key_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_tree(&tree, 0, key_len, compare_key, 0, 0);
|
init_tree(&tree, min(max_heap_table_size, sortbuff_size/16),
|
||||||
|
key_len, compare_key, 0, 0);
|
||||||
tree.cmp_arg = cmp_arg;
|
tree.cmp_arg = cmp_arg;
|
||||||
use_tree = 1;
|
use_tree = 1;
|
||||||
}
|
}
|
||||||
@ -919,11 +923,14 @@ bool Item_sum_count_distinct::setup(THD *thd)
|
|||||||
|
|
||||||
void Item_sum_count_distinct::reset()
|
void Item_sum_count_distinct::reset()
|
||||||
{
|
{
|
||||||
table->file->extra(HA_EXTRA_NO_CACHE);
|
|
||||||
table->file->delete_all_rows();
|
|
||||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
|
||||||
if(use_tree)
|
if(use_tree)
|
||||||
delete_tree(&tree);
|
reset_tree(&tree);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
table->file->extra(HA_EXTRA_NO_CACHE);
|
||||||
|
table->file->delete_all_rows();
|
||||||
|
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||||
|
}
|
||||||
(void) add();
|
(void) add();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user