Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
22915b3a
Commit
22915b3a
authored
Mar 13, 2005
by
konstantin@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/media/sda1/mysql/mysql-5.0-926
parents
a95f09e2
983c75f0
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
628 additions
and
185 deletions
+628
-185
sql/field.cc
sql/field.cc
+18
-0
sql/field.h
sql/field.h
+7
-1
sql/item.cc
sql/item.cc
+125
-0
sql/item.h
sql/item.h
+114
-0
sql/item_sum.cc
sql/item_sum.cc
+187
-165
sql/item_sum.h
sql/item_sum.h
+63
-19
sql/sql_select.cc
sql/sql_select.cc
+111
-0
sql/sql_select.h
sql/sql_select.h
+1
-0
sql/sql_yacc.yy
sql/sql_yacc.yy
+2
-0
No files found.
sql/field.cc
View file @
22915b3a
...
@@ -7162,6 +7162,24 @@ void create_field::create_length_to_internal_length(void)
...
@@ -7162,6 +7162,24 @@ void create_field::create_length_to_internal_length(void)
}
}
void
create_field
::
init_for_tmp_table
(
enum_field_types
sql_type_arg
,
uint32
length_arg
,
uint32
decimals
,
bool
maybe_null
,
bool
is_unsigned
)
{
field_name
=
""
;
sql_type
=
sql_type_arg
;
length
=
length_arg
;;
unireg_check
=
Field
::
NONE
;
interval
=
0
;
charset
=
&
my_charset_bin
;
geom_type
=
Field
::
GEOM_GEOMETRY
;
pack_flag
=
(
FIELDFLAG_NUMBER
|
((
decimals
&
FIELDFLAG_MAX_DEC
)
<<
FIELDFLAG_DEC_SHIFT
)
|
(
maybe_null
?
FIELDFLAG_MAYBE_NULL
:
0
)
|
(
is_unsigned
?
0
:
FIELDFLAG_DECIMAL
));
}
enum_field_types
get_blob_type_from_length
(
ulong
length
)
enum_field_types
get_blob_type_from_length
(
ulong
length
)
{
{
enum_field_types
type
;
enum_field_types
type
;
...
...
sql/field.h
View file @
22915b3a
...
@@ -1340,7 +1340,8 @@ public:
...
@@ -1340,7 +1340,8 @@ public:
Create field class for CREATE TABLE
Create field class for CREATE TABLE
*/
*/
class
create_field
:
public
Sql_alloc
{
class
create_field
:
public
Sql_alloc
{
public:
public:
const
char
*
field_name
;
const
char
*
field_name
;
const
char
*
change
;
// If done with alter table
const
char
*
change
;
// If done with alter table
...
@@ -1362,6 +1363,11 @@ public:
...
@@ -1362,6 +1363,11 @@ public:
create_field
()
:
after
(
0
)
{}
create_field
()
:
after
(
0
)
{}
create_field
(
Field
*
field
,
Field
*
orig_field
);
create_field
(
Field
*
field
,
Field
*
orig_field
);
void
create_length_to_internal_length
(
void
);
void
create_length_to_internal_length
(
void
);
/* Init for a tmp table field. To be extended if need be. */
void
init_for_tmp_table
(
enum_field_types
sql_type_arg
,
uint32
max_length
,
uint32
decimals
,
bool
maybe_null
,
bool
is_unsigned
);
};
};
...
...
sql/item.cc
View file @
22915b3a
...
@@ -33,6 +33,131 @@ static void mark_as_dependent(THD *thd,
...
@@ -33,6 +33,131 @@ static void mark_as_dependent(THD *thd,
const
String
my_null_string
(
"NULL"
,
4
,
default_charset_info
);
const
String
my_null_string
(
"NULL"
,
4
,
default_charset_info
);
/****************************************************************************/
/* Hybrid_type_traits {_real} */
void
Hybrid_type_traits
::
fix_length_and_dec
(
Item
*
item
,
Item
*
arg
)
const
{
item
->
decimals
=
NOT_FIXED_DEC
;
item
->
max_length
=
item
->
float_length
(
arg
->
decimals
);
}
const
Hybrid_type_traits
*
Hybrid_type_traits
::
instance
()
{
const
static
Hybrid_type_traits
real_traits
;
return
&
real_traits
;
}
my_decimal
*
Hybrid_type_traits
::
val_decimal
(
Hybrid_type
*
val
,
my_decimal
*
to
)
const
{
double2my_decimal
(
E_DEC_FATAL_ERROR
,
val
->
real
,
val
->
dec_buf
);
return
val
->
dec_buf
;
}
String
*
Hybrid_type_traits
::
val_str
(
Hybrid_type
*
val
,
String
*
to
,
uint8
decimals
)
const
{
to
->
set
(
val
->
real
,
decimals
,
&
my_charset_bin
);
return
to
;
}
/* Hybrid_type_traits_decimal */
const
Hybrid_type_traits_decimal
*
Hybrid_type_traits_decimal
::
instance
()
{
const
static
Hybrid_type_traits_decimal
decimal_traits
;
return
&
decimal_traits
;
}
void
Hybrid_type_traits_decimal
::
fix_length_and_dec
(
Item
*
item
,
Item
*
arg
)
const
{
item
->
decimals
=
arg
->
decimals
;
item
->
max_length
=
min
(
arg
->
max_length
+
DECIMAL_LONGLONG_DIGITS
,
DECIMAL_MAX_LENGTH
);
}
void
Hybrid_type_traits_decimal
::
set_zero
(
Hybrid_type
*
val
)
const
{
my_decimal_set_zero
(
&
val
->
dec_buf
[
0
]);
val
->
used_dec_buf_no
=
0
;
}
void
Hybrid_type_traits_decimal
::
add
(
Hybrid_type
*
val
,
Field
*
f
)
const
{
my_decimal_add
(
E_DEC_FATAL_ERROR
,
&
val
->
dec_buf
[
val
->
used_dec_buf_no
^
1
],
&
val
->
dec_buf
[
val
->
used_dec_buf_no
],
f
->
val_decimal
(
&
val
->
dec_buf
[
2
]));
val
->
used_dec_buf_no
^=
1
;
}
void
Hybrid_type_traits_decimal
::
div
(
Hybrid_type
*
val
,
ulonglong
u
)
const
{
int2my_decimal
(
E_DEC_FATAL_ERROR
,
u
,
TRUE
,
&
val
->
dec_buf
[
2
]);
/* XXX: what is '4' for scale? */
my_decimal_div
(
E_DEC_FATAL_ERROR
,
&
val
->
dec_buf
[
val
->
used_dec_buf_no
^
1
],
&
val
->
dec_buf
[
val
->
used_dec_buf_no
],
&
val
->
dec_buf
[
2
],
4
);
val
->
used_dec_buf_no
^=
1
;
}
longlong
Hybrid_type_traits_decimal
::
val_int
(
Hybrid_type
*
val
,
bool
unsigned_flag
)
const
{
longlong
result
;
my_decimal2int
(
E_DEC_FATAL_ERROR
,
&
val
->
dec_buf
[
val
->
used_dec_buf_no
],
unsigned_flag
,
&
result
);
return
result
;
}
double
Hybrid_type_traits_decimal
::
val_real
(
Hybrid_type
*
val
)
const
{
my_decimal2double
(
E_DEC_FATAL_ERROR
,
&
val
->
dec_buf
[
val
->
used_dec_buf_no
],
&
val
->
real
);
return
val
->
real
;
}
String
*
Hybrid_type_traits_decimal
::
val_str
(
Hybrid_type
*
val
,
String
*
to
,
uint8
decimals
)
const
{
my_decimal_round
(
E_DEC_FATAL_ERROR
,
&
val
->
dec_buf
[
val
->
used_dec_buf_no
],
decimals
,
FALSE
,
&
val
->
dec_buf
[
2
]);
my_decimal2string
(
E_DEC_FATAL_ERROR
,
&
val
->
dec_buf
[
2
],
0
,
0
,
0
,
to
);
return
to
;
}
/* Hybrid_type_traits_integer */
const
Hybrid_type_traits_integer
*
Hybrid_type_traits_integer
::
instance
()
{
const
static
Hybrid_type_traits_integer
integer_traits
;
return
&
integer_traits
;
}
void
Hybrid_type_traits_integer
::
fix_length_and_dec
(
Item
*
item
,
Item
*
arg
)
const
{
item
->
decimals
=
0
;
item
->
max_length
=
21
;
item
->
unsigned_flag
=
0
;
}
/*****************************************************************************
/*****************************************************************************
** Item functions
** Item functions
*****************************************************************************/
*****************************************************************************/
...
...
sql/item.h
View file @
22915b3a
...
@@ -106,6 +106,120 @@ public:
...
@@ -106,6 +106,120 @@ public:
}
}
};
};
/*************************************************************************/
/*
A framework to easily handle different return types for hybrid items
(hybrid item is an item whose operand can be of any type, e.g. integer,
real, decimal).
*/
struct
Hybrid_type_traits
;
struct
Hybrid_type
{
longlong
integer
;
double
real
;
/*
Use two decimal buffers interchangeably to speed up += operation
which has no native support in decimal library.
Hybrid_type+= arg is implemented as dec_buf[1]= dec_buf[0] + arg.
The third decimal is used as a handy temporary storage.
*/
my_decimal
dec_buf
[
3
];
int
used_dec_buf_no
;
/*
Traits moved to a separate class to
a) be able to easily change object traits in runtime
b) they work as a differentiator for the union above
*/
const
Hybrid_type_traits
*
traits
;
Hybrid_type
()
{}
/* XXX: add traits->copy() when needed */
Hybrid_type
(
const
Hybrid_type
&
rhs
)
:
traits
(
rhs
.
traits
)
{}
};
/* Hybryd_type_traits interface + default implementation for REAL_RESULT */
struct
Hybrid_type_traits
{
virtual
Item_result
type
()
const
{
return
REAL_RESULT
;
}
virtual
void
fix_length_and_dec
(
Item
*
item
,
Item
*
arg
)
const
;
/* Hybrid_type operations. */
virtual
void
set_zero
(
Hybrid_type
*
val
)
const
{
val
->
real
=
0.0
;
}
virtual
void
add
(
Hybrid_type
*
val
,
Field
*
f
)
const
{
val
->
real
+=
f
->
val_real
();
}
virtual
void
div
(
Hybrid_type
*
val
,
ulonglong
u
)
const
{
val
->
real
/=
ulonglong2double
(
u
);
}
virtual
longlong
val_int
(
Hybrid_type
*
val
,
bool
unsigned_flag
)
const
{
return
(
longlong
)
val
->
real
;
}
virtual
double
val_real
(
Hybrid_type
*
val
)
const
{
return
val
->
real
;
}
virtual
my_decimal
*
val_decimal
(
Hybrid_type
*
val
,
my_decimal
*
buf
)
const
;
virtual
String
*
val_str
(
Hybrid_type
*
val
,
String
*
buf
,
uint8
decimals
)
const
;
static
const
Hybrid_type_traits
*
instance
();
};
struct
Hybrid_type_traits_decimal
:
public
Hybrid_type_traits
{
virtual
Item_result
type
()
const
{
return
DECIMAL_RESULT
;
}
virtual
void
fix_length_and_dec
(
Item
*
arg
,
Item
*
item
)
const
;
/* Hybrid_type operations. */
virtual
void
set_zero
(
Hybrid_type
*
val
)
const
;
virtual
void
add
(
Hybrid_type
*
val
,
Field
*
f
)
const
;
virtual
void
div
(
Hybrid_type
*
val
,
ulonglong
u
)
const
;
virtual
longlong
val_int
(
Hybrid_type
*
val
,
bool
unsigned_flag
)
const
;
virtual
double
val_real
(
Hybrid_type
*
val
)
const
;
virtual
my_decimal
*
val_decimal
(
Hybrid_type
*
val
,
my_decimal
*
buf
)
const
{
return
&
val
->
dec_buf
[
val
->
used_dec_buf_no
];
}
virtual
String
*
val_str
(
Hybrid_type
*
val
,
String
*
buf
,
uint8
decimals
)
const
;
static
const
Hybrid_type_traits_decimal
*
instance
();
};
struct
Hybrid_type_traits_integer
:
public
Hybrid_type_traits
{
virtual
Item_result
type
()
const
{
return
INT_RESULT
;
}
virtual
void
fix_length_and_dec
(
Item
*
arg
,
Item
*
item
)
const
;
/* Hybrid_type operations. */
virtual
void
set_zero
(
Hybrid_type
*
val
)
const
{
val
->
integer
=
0
;
}
virtual
void
add
(
Hybrid_type
*
val
,
Field
*
f
)
const
{
val
->
integer
+=
f
->
val_int
();
}
virtual
void
div
(
Hybrid_type
*
val
,
ulonglong
u
)
const
{
val
->
integer
/=
(
longlong
)
u
;
}
virtual
longlong
val_int
(
Hybrid_type
*
val
,
bool
unsigned_flag
)
const
{
return
val
->
integer
;
}
virtual
double
val_real
(
Hybrid_type
*
val
)
const
{
return
(
double
)
val
->
integer
;
}
virtual
my_decimal
*
val_decimal
(
Hybrid_type
*
val
,
my_decimal
*
buf
)
const
{
int2my_decimal
(
E_DEC_FATAL_ERROR
,
val
->
integer
,
0
,
&
val
->
dec_buf
[
2
]);
return
&
val
->
dec_buf
[
2
];
}
virtual
String
*
val_str
(
Hybrid_type
*
val
,
String
*
buf
,
uint8
decimals
)
const
{
buf
->
set
(
val
->
integer
,
&
my_charset_bin
);
return
buf
;}
static
const
Hybrid_type_traits_integer
*
instance
();
};
/*************************************************************************/
typedef
bool
(
Item
::*
Item_processor
)(
byte
*
arg
);
typedef
bool
(
Item
::*
Item_processor
)(
byte
*
arg
);
typedef
Item
*
(
Item
::*
Item_transformer
)
(
byte
*
arg
);
typedef
Item
*
(
Item
::*
Item_transformer
)
(
byte
*
arg
);
...
...
sql/item_sum.cc
View file @
22915b3a
...
@@ -456,11 +456,30 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
...
@@ -456,11 +456,30 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
return
val_decimal_from_real
(
val
);
return
val_decimal_from_real
(
val
);
}
}
/***************************************************************************/
/* Item_sum_sum_distinct */
C_MODE_START
/* Declarations for auxilary C-callbacks */
static
int
simple_raw_key_cmp
(
void
*
arg
,
const
void
*
key1
,
const
void
*
key2
)
{
return
memcmp
(
key1
,
key2
,
*
(
uint
*
)
arg
);
}
static
int
item_sum_distinct_walk
(
void
*
element
,
element_count
num_of_dups
,
void
*
item
)
{
return
((
Item_sum_distinct
*
)
(
item
))
->
unique_walk_function
(
element
);
}
C_MODE_END
Item_sum_sum_distinct
::
Item_sum_sum_distinct
(
Item
*
item
)
/* Item_sum_distinct */
:
Item_sum_sum
(
item
),
tree
(
0
)
Item_sum_distinct
::
Item_sum_distinct
(
Item
*
item_arg
)
:
Item_sum_num
(
item_arg
),
tree
(
0
)
{
{
/*
/*
quick_group is an optimizer hint, which means that GROUP BY can be
quick_group is an optimizer hint, which means that GROUP BY can be
...
@@ -472,239 +491,242 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
...
@@ -472,239 +491,242 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
}
}
Item_sum_
sum_distinct
::
Item_sum_sum_distinct
(
THD
*
thd
,
Item_sum_
distinct
::
Item_sum_distinct
(
THD
*
thd
,
Item_sum_distinct
*
original
)
Item_sum_sum_distinct
*
original
)
:
Item_sum_num
(
thd
,
original
),
val
(
original
->
val
),
tree
(
0
),
:
Item_sum_sum
(
thd
,
original
),
tree
(
0
),
dec_bin_buff
(
original
->
dec_bin_buff
)
table_field_type
(
original
->
table_field_type
)
{
{
quick_group
=
0
;
quick_group
=
0
;
}
}
void
Item_sum_sum_distinct
::
fix_length_and_dec
()
/*
Behaves like an Integer except to fix_length_and_dec().
Additionally div() converts val with this traits to a val with true
decimal traits along with conversion of integer value to decimal value.
This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer
values.
*/
struct
Hybrid_type_traits_fast_decimal
:
public
Hybrid_type_traits_integer
{
{
Item_sum_sum
::
fix_length_and_dec
();
virtual
Item_result
type
()
const
{
return
DECIMAL_RESULT
;
}
if
(
hybrid_type
==
DECIMAL_RESULT
)
virtual
void
fix_length_and_dec
(
Item
*
item
,
Item
*
arg
)
const
{
Hybrid_type_traits_decimal
::
instance
()
->
fix_length_and_dec
(
item
,
arg
);
}
virtual
void
div
(
Hybrid_type
*
val
,
ulonglong
u
)
const
{
{
dec_bin_buff
=
(
byte
*
)
int2my_decimal
(
E_DEC_FATAL_ERROR
,
val
->
integer
,
0
,
val
->
dec_buf
);
sql_alloc
(
my_decimal_get_binary_size
(
args
[
0
]
->
max_length
,
val
->
used_dec_buf_no
=
0
;
args
[
0
]
->
decimals
));
val
->
traits
=
Hybrid_type_traits_decimal
::
instance
();
val
->
traits
->
div
(
val
,
u
);
}
}
}
static
const
Hybrid_type_traits_fast_decimal
*
instance
()
{
static
const
Hybrid_type_traits_fast_decimal
fast_decimal_traits
;
return
&
fast_decimal_traits
;
}
};
Item
*
void
Item_sum_distinct
::
fix_length_and_dec
()
Item_sum_sum_distinct
::
copy_or_same
(
THD
*
thd
)
{
{
return
new
(
thd
->
mem_root
)
Item_sum_sum_distinct
(
thd
,
this
);
DBUG_ASSERT
(
args
[
0
]
->
fixed
);
}
C_MODE_START
table_field_type
=
args
[
0
]
->
field_type
();
static
int
simple_raw_key_cmp
(
void
*
arg
,
const
void
*
key1
,
const
void
*
key2
)
/* Adjust tmp table type according to the chosen aggregation type */
{
switch
(
args
[
0
]
->
result_type
())
{
return
memcmp
(
key1
,
key2
,
*
(
uint
*
)
arg
);
case
STRING_RESULT
:
case
REAL_RESULT
:
val
.
traits
=
Hybrid_type_traits
::
instance
();
if
(
table_field_type
!=
MYSQL_TYPE_FLOAT
)
table_field_type
=
MYSQL_TYPE_DOUBLE
;
break
;
case
INT_RESULT
:
/*
Preserving int8, int16, int32 field types gives ~10% performance boost
as the size of result tree becomes significantly smaller.
Another speed up we gain by using longlong for intermediate
calculations. The range of int64 is enough to hold sum 2^32 distinct
integers each <= 2^32.
*/
if
(
table_field_type
==
MYSQL_TYPE_INT24
||
table_field_type
>=
MYSQL_TYPE_TINY
&&
table_field_type
<=
MYSQL_TYPE_LONG
)
{
val
.
traits
=
Hybrid_type_traits_fast_decimal
::
instance
();
break
;
}
table_field_type
=
MYSQL_TYPE_LONGLONG
;
/* fallthrough */
case
DECIMAL_RESULT
:
val
.
traits
=
Hybrid_type_traits_decimal
::
instance
();
if
(
table_field_type
!=
MYSQL_TYPE_LONGLONG
)
table_field_type
=
MYSQL_TYPE_NEWDECIMAL
;
break
;
case
ROW_RESULT
:
default:
DBUG_ASSERT
(
0
);
}
val
.
traits
->
fix_length_and_dec
(
this
,
args
[
0
]);
}
}
C_MODE_END
bool
Item_sum_
sum_
distinct
::
setup
(
THD
*
thd
)
bool
Item_sum_distinct
::
setup
(
THD
*
thd
)
{
{
DBUG_ENTER
(
"Item_sum_sum_distinct::setup"
);
List
<
create_field
>
field_list
;
SELECT_LEX
*
select_lex
=
thd
->
lex
->
current_select
;
create_field
field_def
;
/* field definition */
/* what does it mean??? */
if
(
select_lex
->
linkage
==
GLOBAL_OPTIONS_TYPE
)
DBUG_ENTER
(
"Item_sum_distinct::setup"
);
DBUG_RETURN
(
1
);
DBUG_ASSERT
(
tree
==
0
);
/* setup can not be called twice */
DBUG_ASSERT
(
tree
==
0
);
/* setup can not be called twice */
/*
/*
Uniques handles all unique elements in a tree until they can't fit in.
Virtual table and the tree are created anew on each re-execution of
Then thee tree is dumped to the temporary file.
PS/SP. Hence all further allocations are performed in the runtime
See class Unique for details
.
mem_root
.
*/
*/
if
(
field_list
.
push_back
(
&
field_def
))
return
TRUE
;
null_value
=
maybe_null
=
1
;
null_value
=
maybe_null
=
1
;
/*
quick_group
=
0
;
TODO: if underlying item result fits in 4 bytes we can take advantage
of it and have tree of long/ulong. It gives 10% performance boost
DBUG_ASSERT
(
args
[
0
]
->
fixed
);
*/
field_def
.
init_for_tmp_table
(
table_field_type
,
args
[
0
]
->
max_length
,
args
[
0
]
->
decimals
,
args
[
0
]
->
maybe_null
,
args
[
0
]
->
unsigned_flag
);
if
(
!
(
table
=
create_virtual_tmp_table
(
thd
,
field_list
)))
return
TRUE
;
/* XXX: check that the case of CHAR(0) works OK */
tree_key_length
=
table
->
s
->
reclength
-
table
->
s
->
null_bytes
;
/*
/*
It's safe to use key_length here as even if we do copy_or_same()
Unique handles all unique elements in a tree until they can't fit
the new item will just share the old items key_length, which will not
in. Then the tree is dumped to the temporary file. We can use
change or disappear during the life time of this item.
simple_raw_key_cmp because the table contains numbers only; decimals
are converted to binary representation as well.
*/
*/
key_length
=
((
hybrid_type
==
DECIMAL_RESULT
)
?
tree
=
new
Unique
(
simple_raw_key_cmp
,
&
tree_key_length
,
tree_key_length
,
my_decimal_get_binary_size
(
args
[
0
]
->
max_length
,
args
[
0
]
->
decimals
)
:
sizeof
(
double
));
tree
=
new
Unique
(
simple_raw_key_cmp
,
&
key_length
,
key_length
,
thd
->
variables
.
max_heap_table_size
);
thd
->
variables
.
max_heap_table_size
);
DBUG_PRINT
(
"info"
,
(
"tree 0x%lx, key length %d"
,
(
ulong
)
tree
,
key_length
));
DBUG_RETURN
(
tree
==
0
);
}
void
Item_sum_sum_distinct
::
clear
()
{
DBUG_ENTER
(
"Item_sum_sum_distinct::clear"
);
DBUG_ASSERT
(
tree
!=
0
);
/* we always have a tree */
null_value
=
1
;
tree
->
reset
();
DBUG_VOID_RETURN
;
}
void
Item_sum_sum_distinct
::
cleanup
()
DBUG_RETURN
(
tree
==
0
);
{
Item_sum_num
::
cleanup
();
delete
tree
;
tree
=
0
;
}
}
bool
Item_sum_
sum_
distinct
::
add
()
bool
Item_sum_distinct
::
add
()
{
{
DBUG_ENTER
(
"Item_sum_sum_distinct::add"
);
args
[
0
]
->
save_in_field
(
table
->
field
[
0
],
FALSE
);
if
(
hybrid_type
==
DECIMAL_RESULT
)
if
(
!
table
->
field
[
0
]
->
is_null
()
)
{
{
my_decimal
value
,
*
val
=
args
[
0
]
->
val_decimal
(
&
value
);
DBUG_ASSERT
(
tree
);
if
(
!
args
[
0
]
->
null_value
)
null_value
=
0
;
{
/*
DBUG_ASSERT
(
tree
!=
0
);
'0' values are also stored in the tree. This doesn't matter
null_value
=
0
;
for SUM(DISTINCT), but is important for AVG(DISTINCT)
my_decimal2binary
(
E_DEC_FATAL_ERROR
,
val
,
(
char
*
)
dec_bin_buff
,
*/
args
[
0
]
->
max_length
,
args
[
0
]
->
decimals
);
return
tree
->
unique_add
(
table
->
field
[
0
]
->
ptr
);
DBUG_RETURN
(
tree
->
unique_add
(
dec_bin_buff
));
}
}
else
{
/* args[0]->val() may reset args[0]->null_value */
double
val
=
args
[
0
]
->
val_real
();
if
(
!
args
[
0
]
->
null_value
)
{
DBUG_ASSERT
(
tree
!=
0
);
null_value
=
0
;
DBUG_PRINT
(
"info"
,
(
"real: %lg, tree 0x%lx"
,
val
,
(
ulong
)
tree
));
if
(
val
)
DBUG_RETURN
(
tree
->
unique_add
(
&
val
));
}
else
DBUG_PRINT
(
"info"
,
(
"real: NULL"
));
}
}
DBUG_RETURN
(
0
)
;
return
0
;
}
}
void
Item_sum_sum_distinct
::
add_real
(
double
val
)
bool
Item_sum_distinct
::
unique_walk_function
(
void
*
element
)
{
{
DBUG_ENTER
(
"Item_sum_sum_distinct::add_real"
);
memcpy
(
table
->
field
[
0
]
->
ptr
,
element
,
tree_key_length
);
sum
+=
val
;
++
count
;
DBUG_PRINT
(
"info"
,
(
"sum %lg, val %lg"
,
sum
,
val
)
);
val
.
traits
->
add
(
&
val
,
table
->
field
[
0
]
);
DBUG_VOID_RETURN
;
return
0
;
}
}
void
Item_sum_
sum_distinct
::
add_decimal
(
byte
*
val
)
void
Item_sum_
distinct
::
clear
(
)
{
{
binary2my_decimal
(
E_DEC_FATAL_ERROR
,
(
char
*
)
val
,
&
tmp_dec
,
DBUG_ENTER
(
"Item_sum_distinct::clear"
);
args
[
0
]
->
max_length
,
args
[
0
]
->
decimals
);
DBUG_ASSERT
(
tree
!=
0
);
/* we always have a tree */
my_decimal_add
(
E_DEC_FATAL_ERROR
,
dec_buffs
+
(
curr_dec_buff
^
1
),
null_value
=
1
;
&
tmp_dec
,
dec_buffs
+
curr_dec_buff
);
tree
->
reset
(
);
curr_dec_buff
^=
1
;
DBUG_VOID_RETURN
;
}
}
C_MODE_START
void
Item_sum_distinct
::
cleanup
()
{
static
int
sum_sum_distinct_real
(
void
*
element
,
element_count
num_of_dups
,
Item_sum_num
::
cleanup
();
void
*
item_sum_sum_distinct
)
delete
tree
;
{
tree
=
0
;
((
Item_sum_sum_distinct
*
)
table
=
0
;
(
item_sum_sum_distinct
))
->
add_real
(
*
(
double
*
)
element
);
return
0
;
}
}
static
int
sum_sum_distinct_decimal
(
void
*
element
,
element_count
num_of_dups
,
Item_sum_distinct
::~
Item_sum_distinct
()
void
*
item_sum_sum_distinct
)
{
{
delete
tree
;
((
Item_sum_sum_distinct
*
)
/* no need to free the table */
(
item_sum_sum_distinct
))
->
add_decimal
((
byte
*
)
element
);
return
0
;
}
}
C_MODE_END
double
Item_sum_sum_distinct
::
val_real
()
void
Item_sum_distinct
::
calculate_val_and_count
()
{
{
DBUG_ENTER
(
"Item_sum_sum_distinct::val"
);
count
=
0
;
val
.
traits
->
set_zero
(
&
val
);
/*
/*
We don't have a tree only if 'setup()' hasn't been called;
We don't have a tree only if 'setup()' hasn't been called;
this is the case of sql_select.cc:return_zero_rows.
this is the case of sql_select.cc:return_zero_rows.
*/
*/
if
(
hybrid_type
==
DECIMAL_RESULT
)
if
(
tree
)
{
{
/* Item_sum_sum_distinct::val_decimal do not use argument */
table
->
field
[
0
]
->
set_notnull
();
my_decimal
*
val
=
val_decimal
(
0
);
tree
->
walk
(
item_sum_distinct_walk
,
(
void
*
)
this
);
if
(
!
null_value
)
my_decimal2double
(
E_DEC_FATAL_ERROR
,
val
,
&
sum
);
}
else
{
sum
=
0.0
;
DBUG_PRINT
(
"info"
,
(
"tree 0x%lx"
,
(
ulong
)
tree
));
if
(
tree
)
tree
->
walk
(
sum_sum_distinct_real
,
(
void
*
)
this
);
}
}
DBUG_RETURN
(
sum
);
}
}
my_decimal
*
Item_sum_sum_distinct
::
val_decimal
(
my_decimal
*
fake
)
double
Item_sum_distinct
::
val_real
(
)
{
{
if
(
hybrid_type
==
DECIMAL_RESULT
)
calculate_val_and_count
();
{
return
val
.
traits
->
val_real
(
&
val
);
my_decimal_set_zero
(
dec_buffs
);
curr_dec_buff
=
0
;
if
(
tree
)
tree
->
walk
(
sum_sum_distinct_decimal
,
(
void
*
)
this
);
}
else
{
double
real
=
val_real
();
curr_dec_buff
=
0
;
double2my_decimal
(
E_DEC_FATAL_ERROR
,
real
,
dec_buffs
);
}
return
(
dec_buffs
+
curr_dec_buff
);
}
}
longlong
Item_sum_sum_distinct
::
val_int
(
)
my_decimal
*
Item_sum_distinct
::
val_decimal
(
my_decimal
*
to
)
{
{
longlong
result
;
calculate_val_and_count
();
if
(
hybrid_type
==
DECIMAL_RESULT
)
if
(
null_value
)
{
return
0
;
/* Item_sum_sum_distinct::val_decimal do not use argument */
return
val
.
traits
->
val_decimal
(
&
val
,
to
);
my_decimal
*
val
=
val_decimal
(
0
);
if
(
!
null_value
)
my_decimal2int
(
E_DEC_FATAL_ERROR
,
val
,
unsigned_flag
,
&
result
);
}
else
result
=
(
longlong
)
val_real
();
return
result
;
}
}
String
*
Item_sum_sum_distinct
::
val_str
(
String
*
str
)
longlong
Item_sum_distinct
::
val_int
(
)
{
{
DBUG_ASSERT
(
fixed
==
1
);
calculate_val_and_count
();
if
(
hybrid_type
==
DECIMAL_RESULT
)
return
val
.
traits
->
val_int
(
&
val
,
unsigned_flag
);
return
val_string_from_decimal
(
str
);
return
val_string_from_real
(
str
);
}
}
/* end of Item_sum_sum_distinct */
String
*
Item_sum_distinct
::
val_str
(
String
*
str
)
{
calculate_val_and_count
();
if
(
null_value
)
return
0
;
return
val
.
traits
->
val_str
(
&
val
,
str
,
decimals
);
}
/* end of Item_sum_distinct */
/* Item_sum_avg_distinct */
void
Item_sum_avg_distinct
::
calculate_val_and_count
()
{
Item_sum_distinct
::
calculate_val_and_count
();
if
(
count
)
val
.
traits
->
div
(
&
val
,
count
);
}
Item
*
Item_sum_count
::
copy_or_same
(
THD
*
thd
)
Item
*
Item_sum_count
::
copy_or_same
(
THD
*
thd
)
{
{
...
...
sql/item_sum.h
View file @
22915b3a
...
@@ -30,8 +30,8 @@ class Item_sum :public Item_result_field
...
@@ -30,8 +30,8 @@ class Item_sum :public Item_result_field
public:
public:
enum
Sumfunctype
enum
Sumfunctype
{
COUNT_FUNC
,
COUNT_DISTINCT_FUNC
,
SUM_FUNC
,
SUM_DISTINCT_FUNC
,
AVG_FUNC
,
{
COUNT_FUNC
,
COUNT_DISTINCT_FUNC
,
SUM_FUNC
,
SUM_DISTINCT_FUNC
,
AVG_FUNC
,
MIN_FUNC
,
MAX_FUNC
,
UNIQUE_USERS_FUNC
,
STD_FUNC
,
VARIANCE
_FUNC
,
AVG_DISTINCT_FUNC
,
MIN_FUNC
,
MAX_FUNC
,
UNIQUE_USERS_FUNC
,
STD
_FUNC
,
SUM_BIT_FUNC
,
UDF_SUM_FUNC
,
GROUP_CONCAT_FUNC
VARIANCE_FUNC
,
SUM_BIT_FUNC
,
UDF_SUM_FUNC
,
GROUP_CONCAT_FUNC
};
};
Item
**
args
,
*
tmp_args
[
2
];
Item
**
args
,
*
tmp_args
[
2
];
...
@@ -68,6 +68,9 @@ public:
...
@@ -68,6 +68,9 @@ public:
a temporary table. Similar to reset(), but must also store value in
a temporary table. Similar to reset(), but must also store value in
result_field. Like reset() it is supposed to reset start value to
result_field. Like reset() it is supposed to reset start value to
default.
default.
This set of methods (reult_field(), reset_field, update_field()) of
Item_sum is used only if quick_group is not null. Otherwise
copy_or_same() is used to obtain a copy of this item.
*/
*/
virtual
void
reset_field
()
=
0
;
virtual
void
reset_field
()
=
0
;
/*
/*
...
@@ -161,26 +164,28 @@ public:
...
@@ -161,26 +164,28 @@ public:
};
};
/*
Item_sum_sum_distinct - SELECT SUM(DISTINCT expr) FROM ...
/* Common class for SUM(DISTINCT), AVG(DISTINCT) */
support. See also: MySQL manual, chapter 'Adding New Functions To MySQL'
and comments in item_sum.cc.
*/
class
Unique
;
class
Unique
;
class
Item_sum_
sum_distinct
:
public
Item_sum_s
um
class
Item_sum_
distinct
:
public
Item_sum_n
um
{
{
protected:
/* storage for the summation result */
ulonglong
count
;
Hybrid_type
val
;
/* storage for unique elements */
Unique
*
tree
;
Unique
*
tree
;
byte
*
dec_bin_buff
;
TABLE
*
table
;
my_decimal
tmp_dec
;
enum
enum_field_types
table_field_type
;
uint
key_length
;
uint
tree_
key_length
;
pr
ivate
:
pr
otected
:
Item_sum_
sum_distinct
(
THD
*
thd
,
Item_su
m_sum_distinct
*
item
);
Item_sum_
distinct
(
THD
*
thd
,
Ite
m_sum_distinct
*
item
);
public:
public:
Item_sum_
sum_
distinct
(
Item
*
item_par
);
Item_sum_distinct
(
Item
*
item_par
);
~
Item_sum_
sum_distinct
()
{}
~
Item_sum_
distinct
();
bool
setup
(
THD
*
thd
);
bool
setup
(
THD
*
thd
);
void
clear
();
void
clear
();
void
cleanup
();
void
cleanup
();
...
@@ -190,15 +195,54 @@ public:
...
@@ -190,15 +195,54 @@ public:
longlong
val_int
();
longlong
val_int
();
String
*
val_str
(
String
*
str
);
String
*
val_str
(
String
*
str
);
void
add_real
(
double
val
);
/* XXX: does it need make_unique? */
void
add_decimal
(
byte
*
val
);
enum
Sumfunctype
sum_func
()
const
{
return
SUM_DISTINCT_FUNC
;
}
enum
Sumfunctype
sum_func
()
const
{
return
SUM_DISTINCT_FUNC
;
}
void
reset_field
()
{}
// not used
void
reset_field
()
{}
// not used
void
update_field
()
{}
// not used
void
update_field
()
{}
// not used
const
char
*
func_name
()
const
{
return
"sum_distinct"
;
}
const
char
*
func_name
()
const
{
return
"sum_distinct"
;
}
Item
*
copy_or_same
(
THD
*
thd
);
virtual
void
no_rows_in_result
()
{}
virtual
void
no_rows_in_result
()
{}
void
fix_length_and_dec
();
void
fix_length_and_dec
();
enum
Item_result
result_type
()
const
{
return
val
.
traits
->
type
();
}
virtual
void
calculate_val_and_count
();
virtual
bool
unique_walk_function
(
void
*
elem
);
};
/*
Item_sum_sum_distinct - implementation of SUM(DISTINCT expr).
See also: MySQL manual, chapter 'Adding New Functions To MySQL'
and comments in item_sum.cc.
*/
class
Item_sum_sum_distinct
:
public
Item_sum_distinct
{
private:
Item_sum_sum_distinct
(
THD
*
thd
,
Item_sum_sum_distinct
*
item
)
:
Item_sum_distinct
(
thd
,
item
)
{}
public:
Item_sum_sum_distinct
(
Item
*
item_arg
)
:
Item_sum_distinct
(
item_arg
)
{}
enum
Sumfunctype
sum_func
()
const
{
return
SUM_DISTINCT_FUNC
;
}
const
char
*
func_name
()
const
{
return
"sum_distinct"
;
}
Item
*
copy_or_same
(
THD
*
thd
)
{
return
new
Item_sum_sum_distinct
(
thd
,
this
);
}
};
/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */
class
Item_sum_avg_distinct
:
public
Item_sum_distinct
{
private:
Item_sum_avg_distinct
(
THD
*
thd
,
Item_sum_avg_distinct
*
original
)
:
Item_sum_distinct
(
thd
,
original
)
{}
public:
Item_sum_avg_distinct
(
Item
*
item_arg
)
:
Item_sum_distinct
(
item_arg
)
{}
virtual
void
calculate_val_and_count
();
enum
Sumfunctype
sum_func
()
const
{
return
AVG_DISTINCT_FUNC
;
}
const
char
*
func_name
()
const
{
return
"avg_distinct"
;
}
Item
*
copy_or_same
(
THD
*
thd
)
{
return
new
Item_sum_avg_distinct
(
thd
,
this
);
}
};
};
...
...
sql/sql_select.cc
View file @
22915b3a
...
@@ -8359,6 +8359,117 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
...
@@ -8359,6 +8359,117 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
}
/****************************************************************************/
/*
Create a reduced TABLE object with properly set up Field list from a
list of field definitions.
SYNOPSIS
create_virtual_tmp_table()
thd connection handle
field_list list of column definitions
DESCRIPTION
The created table doesn't have a table handler assotiated with
it, has no keys, no group/distinct, no copy_funcs array.
The sole purpose of this TABLE object is to use the power of Field
class to read/write data to/from table->record[0]. Then one can store
the record in any container (RB tree, hash, etc).
The table is created in THD mem_root, so are the table's fields.
Consequently, if you don't BLOB fields, you don't need to free it.
RETURN
0 if out of memory, TABLE object in case of success
*/
TABLE
*
create_virtual_tmp_table
(
THD
*
thd
,
List
<
create_field
>
&
field_list
)
{
uint
field_count
=
field_list
.
elements
;
Field
**
field
;
create_field
*
cdef
;
/* column definition */
uint
record_length
=
0
;
uint
null_count
=
0
;
/* number of columns which may be null */
uint
null_pack_length
;
/* NULL representation array length */
TABLE_SHARE
*
s
;
/* Create the table and list of all fields */
TABLE
*
table
=
(
TABLE
*
)
thd
->
calloc
(
sizeof
(
*
table
));
field
=
(
Field
**
)
thd
->
alloc
((
field_count
+
1
)
*
sizeof
(
Field
*
));
if
(
!
table
||
!
field
)
return
0
;
table
->
field
=
field
;
table
->
s
=
s
=
&
table
->
share_not_to_be_used
;
s
->
fields
=
field_count
;
/* Create all fields and calculate the total length of record */
List_iterator_fast
<
create_field
>
it
(
field_list
);
while
((
cdef
=
it
++
))
{
*
field
=
make_field
(
0
,
cdef
->
length
,
(
uchar
*
)
(
f_maybe_null
(
cdef
->
pack_flag
)
?
""
:
0
),
f_maybe_null
(
cdef
->
pack_flag
)
?
1
:
0
,
cdef
->
pack_flag
,
cdef
->
sql_type
,
cdef
->
charset
,
cdef
->
geom_type
,
cdef
->
unireg_check
,
cdef
->
interval
,
cdef
->
field_name
,
table
);
if
(
!*
field
)
goto
error
;
record_length
+=
(
**
field
).
pack_length
();
if
(
!
((
**
field
).
flags
&
NOT_NULL_FLAG
))
++
null_count
;
++
field
;
}
*
field
=
NULL
;
/* mark the end of the list */
null_pack_length
=
(
null_count
+
7
)
/
8
;
s
->
reclength
=
record_length
+
null_pack_length
;
s
->
rec_buff_length
=
ALIGN_SIZE
(
s
->
reclength
+
1
);
table
->
record
[
0
]
=
(
byte
*
)
thd
->
alloc
(
s
->
rec_buff_length
);
if
(
!
table
->
record
[
0
])
goto
error
;
if
(
null_pack_length
)
{
table
->
null_flags
=
(
uchar
*
)
table
->
record
[
0
];
s
->
null_fields
=
null_count
;
s
->
null_bytes
=
null_pack_length
;
}
table
->
in_use
=
thd
;
/* field->reset() may access table->in_use */
{
/* Set up field pointers */
byte
*
null_pos
=
table
->
record
[
0
];
byte
*
field_pos
=
null_pos
+
s
->
null_bytes
;
uint
null_bit
=
1
;
for
(
field
=
table
->
field
;
*
field
;
++
field
)
{
Field
*
cur_field
=
*
field
;
if
((
cur_field
->
flags
&
NOT_NULL_FLAG
))
cur_field
->
move_field
((
char
*
)
field_pos
);
else
{
cur_field
->
move_field
((
char
*
)
field_pos
,
(
uchar
*
)
null_pos
,
null_bit
);
null_bit
<<=
1
;
if
(
null_bit
==
(
1
<<
8
))
{
++
null_pos
;
null_bit
=
1
;
}
}
cur_field
->
reset
();
field_pos
+=
cur_field
->
pack_length
();
}
}
return
table
;
error:
for
(
field
=
table
->
field
;
*
field
;
++
field
)
delete
*
field
;
/* just invokes field destructor */
return
0
;
}
static
bool
open_tmp_table
(
TABLE
*
table
)
static
bool
open_tmp_table
(
TABLE
*
table
)
{
{
int
error
;
int
error
;
...
...
sql/sql_select.h
View file @
22915b3a
...
@@ -387,6 +387,7 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
...
@@ -387,6 +387,7 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER
*
group
,
bool
distinct
,
bool
save_sum_fields
,
ORDER
*
group
,
bool
distinct
,
bool
save_sum_fields
,
ulong
select_options
,
ha_rows
rows_limit
,
ulong
select_options
,
ha_rows
rows_limit
,
char
*
alias
);
char
*
alias
);
TABLE
*
create_virtual_tmp_table
(
THD
*
thd
,
List
<
create_field
>
&
field_list
);
void
free_tmp_table
(
THD
*
thd
,
TABLE
*
entry
);
void
free_tmp_table
(
THD
*
thd
,
TABLE
*
entry
);
void
count_field_types
(
TMP_TABLE_PARAM
*
param
,
List
<
Item
>
&
fields
,
void
count_field_types
(
TMP_TABLE_PARAM
*
param
,
List
<
Item
>
&
fields
,
bool
reset_with_sum_func
);
bool
reset_with_sum_func
);
...
...
sql/sql_yacc.yy
View file @
22915b3a
...
@@ -4754,6 +4754,8 @@ udf_expr:
...
@@ -4754,6 +4754,8 @@ udf_expr:
sum_expr:
sum_expr:
AVG_SYM '(' in_sum_expr ')'
AVG_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_avg($3); }
{ $$=new Item_sum_avg($3); }
| AVG_SYM '(' DISTINCT in_sum_expr ')'
{ $$=new Item_sum_avg_distinct($4); }
| BIT_AND '(' in_sum_expr ')'
| BIT_AND '(' in_sum_expr ')'
{ $$=new Item_sum_and($3); }
{ $$=new Item_sum_and($3); }
| BIT_OR '(' in_sum_expr ')'
| BIT_OR '(' in_sum_expr ')'
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment