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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
0e8544cd
Commit
0e8544cd
authored
Aug 23, 2022
by
Alexander Barkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-29355 Backport templatized INET6 implementation from 10.7 to 10.6
parent
4feb9df1
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
2174 additions
and
2112 deletions
+2174
-2112
plugin/type_inet/item_inetfunc.cc
plugin/type_inet/item_inetfunc.cc
+21
-6
plugin/type_inet/mysql-test/type_inet/type_inet6.result
plugin/type_inet/mysql-test/type_inet/type_inet6.result
+28
-0
plugin/type_inet/mysql-test/type_inet/type_inet6.test
plugin/type_inet/mysql-test/type_inet/type_inet6.test
+15
-0
plugin/type_inet/plugin.cc
plugin/type_inet/plugin.cc
+2
-6
plugin/type_inet/sql_type_inet.cc
plugin/type_inet/sql_type_inet.cc
+5
-1200
plugin/type_inet/sql_type_inet.h
plugin/type_inet/sql_type_inet.h
+12
-900
sql/sql_string.h
sql/sql_string.h
+5
-0
sql/sql_type_fixedbin.h
sql/sql_type_fixedbin.h
+1913
-0
sql/sql_type_fixedbin_storage.h
sql/sql_type_fixedbin_storage.h
+173
-0
No files found.
plugin/type_inet/item_inetfunc.cc
View file @
0e8544cd
...
...
@@ -158,7 +158,7 @@ String *Item_func_inet6_aton::val_str(String *buffer)
return
buffer
;
}
Inet6_null
ipv6
(
*
tmp
.
string
());
Inet6
Bundle
::
Fbt
_null
ipv6
(
*
tmp
.
string
());
if
(
!
ipv6
.
is_null
())
{
ipv6
.
to_binary
(
buffer
);
...
...
@@ -197,7 +197,7 @@ String *Item_func_inet6_ntoa::val_str_ascii(String *buffer)
return
buffer
;
}
Inet6_null
ipv6
(
static_cast
<
const
Binary_string
&>
(
*
tmp
.
string
()));
Inet6
Bundle
::
Fbt
_null
ipv6
(
static_cast
<
const
Binary_string
&>
(
*
tmp
.
string
()));
if
(
!
ipv6
.
is_null
())
{
ipv6
.
to_string
(
buffer
);
...
...
@@ -221,6 +221,22 @@ longlong Item_func_is_ipv4::val_int()
return
!
tmp
.
is_null
()
&&
!
Inet4_null
(
*
tmp
.
string
()).
is_null
();
}
class
IP6
:
public
Inet6Bundle
::
Fbt_null
{
public:
IP6
(
Item
*
arg
)
:
Inet6Bundle
::
Fbt_null
(
arg
)
{}
bool
is_v4compat
()
const
{
static_assert
(
sizeof
(
in6_addr
)
==
IN6_ADDR_SIZE
,
"unexpected in6_addr size"
);
return
IN6_IS_ADDR_V4COMPAT
((
struct
in6_addr
*
)
m_buffer
);
}
bool
is_v4mapped
()
const
{
static_assert
(
sizeof
(
in6_addr
)
==
IN6_ADDR_SIZE
,
"unexpected in6_addr size"
);
return
IN6_IS_ADDR_V4MAPPED
((
struct
in6_addr
*
)
m_buffer
);
}
};
/**
Checks if the passed string represents an IPv6-address.
...
...
@@ -230,17 +246,16 @@ longlong Item_func_is_ipv6::val_int()
{
DBUG_ASSERT
(
fixed
());
String_ptr_and_buffer
<
STRING_BUFFER_USUAL_SIZE
>
tmp
(
args
[
0
]);
return
!
tmp
.
is_null
()
&&
!
Inet6_null
(
*
tmp
.
string
()).
is_null
();
return
!
tmp
.
is_null
()
&&
!
Inet6
Bundle
::
Fbt
_null
(
*
tmp
.
string
()).
is_null
();
}
/**
Checks if the passed IPv6-address is an IPv4-compat IPv6-address.
*/
longlong
Item_func_is_ipv4_compat
::
val_int
()
{
I
net6_null
ip6
(
args
[
0
]);
I
P6
ip6
(
args
[
0
]);
return
!
ip6
.
is_null
()
&&
ip6
.
is_v4compat
();
}
...
...
@@ -251,6 +266,6 @@ longlong Item_func_is_ipv4_compat::val_int()
longlong
Item_func_is_ipv4_mapped
::
val_int
()
{
I
net6_null
ip6
(
args
[
0
]);
I
P6
ip6
(
args
[
0
]);
return
!
ip6
.
is_null
()
&&
ip6
.
is_v4mapped
();
}
plugin/type_inet/mysql-test/type_inet/type_inet6.result
View file @
0e8544cd
...
...
@@ -2229,3 +2229,31 @@ SELECT * FROM t1 WHERE d >= ALL (SELECT * FROM t1);
d
12::
DROP TABLE t1;
#
# MDEV-27015 Assertion `!is_null()' failed in FixedBinTypeBundle<FbtImpl>::Fbt FixedBinTypeBundle<FbtImpl>::Field_fbt::to_fbt()
#
CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a INET6(6) DEFAULT '::10');
INSERT INTO t1(id) VALUES (1), (2), (3), (4);
INSERT INTO t1 VALUES (5,'::5'), (6,'::6');
SELECT * FROM t1 ORDER BY a;
id a
5 ::5
6 ::6
1 ::10
2 ::10
3 ::10
4 ::10
CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a;
CREATE TABLE t2 SELECT * FROM v1;
SELECT * FROM v1 ORDER BY a;
a m
::5 5
::6 6
::10 1
SELECT * FROM t2 ORDER BY a;
a m
::5 5
::6 6
::10 1
DROP VIEW v1;
DROP TABLE t1, t2;
plugin/type_inet/mysql-test/type_inet/type_inet6.test
View file @
0e8544cd
...
...
@@ -1641,3 +1641,18 @@ SELECT * FROM t1 ORDER BY d;
SELECT
*
FROM
t1
WHERE
d
<=
ALL
(
SELECT
*
FROM
t1
);
SELECT
*
FROM
t1
WHERE
d
>=
ALL
(
SELECT
*
FROM
t1
);
DROP
TABLE
t1
;
--
echo
#
--
echo
# MDEV-27015 Assertion `!is_null()' failed in FixedBinTypeBundle<FbtImpl>::Fbt FixedBinTypeBundle<FbtImpl>::Field_fbt::to_fbt()
--
echo
#
CREATE
TABLE
t1
(
id
int
NOT
NULL
PRIMARY
KEY
,
a
INET6
(
6
)
DEFAULT
'::10'
);
INSERT
INTO
t1
(
id
)
VALUES
(
1
),
(
2
),
(
3
),
(
4
);
INSERT
INTO
t1
VALUES
(
5
,
'::5'
),
(
6
,
'::6'
);
SELECT
*
FROM
t1
ORDER
BY
a
;
CREATE
VIEW
v1
(
a
,
m
)
AS
SELECT
a
,
MIN
(
id
)
FROM
t1
GROUP
BY
a
;
CREATE
TABLE
t2
SELECT
*
FROM
v1
;
SELECT
*
FROM
v1
ORDER
BY
a
;
SELECT
*
FROM
t2
ORDER
BY
a
;
DROP
VIEW
v1
;
DROP
TABLE
t1
,
t2
;
plugin/type_inet/plugin.cc
View file @
0e8544cd
/* Copyright (c) 2019 MariaDB Corporation
/* Copyright (c) 2019
,2021
MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
...
...
@@ -21,14 +21,10 @@
#include <mysql/plugin_data_type.h>
#include <mysql/plugin_function.h>
Type_handler_inet6
type_handler_inet6
;
static
struct
st_mariadb_data_type
plugin_descriptor_type_inet6
=
{
MariaDB_DATA_TYPE_INTERFACE_VERSION
,
&
type_handler_inet6
Inet6Bundle
::
type_handler_fbt
()
};
...
...
plugin/type_inet/sql_type_inet.cc
View file @
0e8544cd
/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2014 MariaDB Foundation
Copyright (c) 2019 MariaDB Corporation
Copyright (c) 2019
,2022
MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
...
...
@@ -168,7 +168,7 @@ bool Inet4::ascii_to_ipv4(const char *str, size_t str_length)
IPv4-part differently on different platforms.
*/
bool
Inet6
::
ascii_to_
ipv6
(
const
char
*
str
,
size_t
str_length
)
bool
Inet6
::
ascii_to_
fbt
(
const
char
*
str
,
size_t
str_length
)
{
if
(
str_length
<
2
)
{
...
...
@@ -507,1203 +507,8 @@ size_t Inet6::to_string(char *dst, size_t dstsize) const
return
(
size_t
)
(
p
-
dst
);
}
bool
Inet6
::
fix_fields_maybe_null_on_conversion_to_inet6
(
Item
*
item
)
{
if
(
item
->
maybe_null
())
return
true
;
if
(
item
->
type_handler
()
==
&
type_handler_inet6
)
return
false
;
if
(
!
item
->
const_item
()
||
item
->
is_expensive
())
return
true
;
return
Inet6_null
(
item
,
false
).
is_null
();
}
bool
Inet6
::
make_from_item
(
Item
*
item
,
bool
warn
)
{
if
(
item
->
type_handler
()
==
&
type_handler_inet6
)
{
Native
tmp
(
m_buffer
,
sizeof
(
m_buffer
));
bool
rc
=
item
->
val_native
(
current_thd
,
&
tmp
);
if
(
rc
)
return
true
;
DBUG_ASSERT
(
tmp
.
length
()
==
sizeof
(
m_buffer
));
if
(
tmp
.
ptr
()
!=
m_buffer
)
memcpy
(
m_buffer
,
tmp
.
ptr
(),
sizeof
(
m_buffer
));
return
false
;
}
StringBufferInet6
tmp
;
String
*
str
=
item
->
val_str
(
&
tmp
);
return
str
?
make_from_character_or_binary_string
(
str
,
warn
)
:
true
;
}
bool
Inet6
::
make_from_character_or_binary_string
(
const
String
*
str
,
bool
warn
)
{
static
Name
name
=
type_handler_inet6
.
name
();
if
(
str
->
charset
()
!=
&
my_charset_bin
)
{
bool
rc
=
character_string_to_ipv6
(
str
->
ptr
(),
str
->
length
(),
str
->
charset
());
if
(
rc
&&
warn
)
current_thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
.
ptr
(),
ErrConvString
(
str
).
ptr
());
return
rc
;
}
if
(
str
->
length
()
!=
sizeof
(
m_buffer
))
{
if
(
warn
)
current_thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
.
ptr
(),
ErrConvString
(
str
).
ptr
());
return
true
;
}
DBUG_ASSERT
(
str
->
ptr
()
!=
m_buffer
);
memcpy
(
m_buffer
,
str
->
ptr
(),
sizeof
(
m_buffer
));
return
false
;
};
/********************************************************************/
class
cmp_item_inet6
:
public
cmp_item_scalar
{
Inet6
m_native
;
public:
cmp_item_inet6
()
:
cmp_item_scalar
(),
m_native
(
Inet6_zero
())
{
}
void
store_value
(
Item
*
item
)
override
{
m_native
=
Inet6
(
item
,
&
m_null_value
);
}
int
cmp_not_null
(
const
Value
*
val
)
override
{
DBUG_ASSERT
(
!
val
->
is_null
());
DBUG_ASSERT
(
val
->
is_string
());
Inet6_null
tmp
(
val
->
m_string
);
DBUG_ASSERT
(
!
tmp
.
is_null
());
return
m_native
.
cmp
(
tmp
);
}
int
cmp
(
Item
*
arg
)
override
{
Inet6_null
tmp
(
arg
);
return
m_null_value
||
tmp
.
is_null
()
?
UNKNOWN
:
m_native
.
cmp
(
tmp
)
!=
0
;
}
int
compare
(
cmp_item
*
ci
)
override
{
cmp_item_inet6
*
tmp
=
static_cast
<
cmp_item_inet6
*>
(
ci
);
DBUG_ASSERT
(
!
m_null_value
);
DBUG_ASSERT
(
!
tmp
->
m_null_value
);
return
m_native
.
cmp
(
tmp
->
m_native
);
}
cmp_item
*
make_same
(
THD
*
thd
)
override
{
return
new
(
thd
->
mem_root
)
cmp_item_inet6
();
}
};
class
Field_inet6
:
public
Field
{
static
void
set_min_value
(
char
*
ptr
)
{
memset
(
ptr
,
0
,
Inet6
::
binary_length
());
}
static
void
set_max_value
(
char
*
ptr
)
{
memset
(
ptr
,
0xFF
,
Inet6
::
binary_length
());
}
void
store_warning
(
const
ErrConv
&
str
,
Sql_condition
::
enum_warning_level
level
)
{
static
const
Name
type_name
=
type_handler_inet6
.
name
();
if
(
get_thd
()
->
count_cuted_fields
<=
CHECK_FIELD_EXPRESSION
)
return
;
const
TABLE_SHARE
*
s
=
table
->
s
;
get_thd
()
->
push_warning_truncated_value_for_field
(
level
,
type_name
.
ptr
(),
str
.
ptr
(),
s
?
s
->
db
.
str
:
nullptr
,
s
?
s
->
table_name
.
str
:
nullptr
,
field_name
.
str
);
}
int
set_null_with_warn
(
const
ErrConv
&
str
)
{
store_warning
(
str
,
Sql_condition
::
WARN_LEVEL_WARN
);
set_null
();
return
1
;
}
int
set_min_value_with_warn
(
const
ErrConv
&
str
)
{
store_warning
(
str
,
Sql_condition
::
WARN_LEVEL_WARN
);
set_min_value
((
char
*
)
ptr
);
return
1
;
}
int
set_max_value_with_warn
(
const
ErrConv
&
str
)
{
store_warning
(
str
,
Sql_condition
::
WARN_LEVEL_WARN
);
set_max_value
((
char
*
)
ptr
);
return
1
;
}
int
store_inet6_null_with_warn
(
const
Inet6_null
&
inet6
,
const
ErrConvString
&
err
)
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
if
(
inet6
.
is_null
())
return
maybe_null
()
?
set_null_with_warn
(
err
)
:
set_min_value_with_warn
(
err
);
inet6
.
to_binary
((
char
*
)
ptr
,
Inet6
::
binary_length
());
return
0
;
}
public:
Field_inet6
(
const
LEX_CSTRING
*
field_name_arg
,
const
Record_addr
&
rec
)
:
Field
(
rec
.
ptr
(),
Inet6
::
max_char_length
(),
rec
.
null_ptr
(),
rec
.
null_bit
(),
Field
::
NONE
,
field_name_arg
)
{
flags
|=
BINARY_FLAG
|
UNSIGNED_FLAG
;
}
const
Type_handler
*
type_handler
()
const
override
{
return
&
type_handler_inet6
;
}
uint32
max_display_length
()
const
override
{
return
field_length
;
}
bool
str_needs_quotes
()
const
override
{
return
true
;
}
const
DTCollation
&
dtcollation
()
const
override
{
static
DTCollation_numeric
c
;
return
c
;
}
CHARSET_INFO
*
charset
(
void
)
const
override
{
return
&
my_charset_numeric
;
}
const
CHARSET_INFO
*
sort_charset
(
void
)
const
override
{
return
&
my_charset_bin
;
}
/**
This makes client-server protocol convert the value according
to @@character_set_client.
*/
bool
binary
()
const
override
{
return
false
;
}
enum
ha_base_keytype
key_type
()
const
override
{
return
HA_KEYTYPE_BINARY
;
}
bool
is_equal
(
const
Column_definition
&
new_field
)
const
override
{
return
new_field
.
type_handler
()
==
type_handler
();
}
bool
eq_def
(
const
Field
*
field
)
const
override
{
return
Field
::
eq_def
(
field
);
}
double
pos_in_interval
(
Field
*
min
,
Field
*
max
)
override
{
return
pos_in_interval_val_str
(
min
,
max
,
0
);
}
int
cmp
(
const
uchar
*
a
,
const
uchar
*
b
)
const
override
{
return
memcmp
(
a
,
b
,
pack_length
());
}
void
sort_string
(
uchar
*
to
,
uint
length
)
override
{
DBUG_ASSERT
(
length
==
pack_length
());
memcpy
(
to
,
ptr
,
length
);
}
uint32
pack_length
()
const
override
{
return
Inet6
::
binary_length
();
}
uint
pack_length_from_metadata
(
uint
field_metadata
)
const
override
{
return
Inet6
::
binary_length
();
}
void
sql_type
(
String
&
str
)
const
override
{
static
Name
name
=
type_handler_inet6
.
name
();
str
.
set_ascii
(
name
.
ptr
(),
name
.
length
());
}
void
make_send_field
(
Send_field
*
to
)
override
{
Field
::
make_send_field
(
to
);
to
->
set_data_type_name
(
type_handler_inet6
.
name
().
lex_cstring
());
}
bool
validate_value_in_record
(
THD
*
thd
,
const
uchar
*
record
)
const
override
{
return
false
;
}
String
*
val_str
(
String
*
val_buffer
,
String
*
val_ptr
__attribute__
((
unused
)))
override
{
DBUG_ASSERT
(
marked_for_read
());
Inet6_null
tmp
((
const
char
*
)
ptr
,
pack_length
());
return
tmp
.
to_string
(
val_buffer
)
?
NULL
:
val_buffer
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
DBUG_ASSERT
(
marked_for_read
());
my_decimal_set_zero
(
to
);
return
to
;
}
longlong
val_int
()
override
{
DBUG_ASSERT
(
marked_for_read
());
return
0
;
}
double
val_real
()
override
{
DBUG_ASSERT
(
marked_for_read
());
return
0
;
}
bool
get_date
(
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
DBUG_ASSERT
(
marked_for_read
());
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_bool
(
void
)
override
{
DBUG_ASSERT
(
marked_for_read
());
return
!
Inet6
::
only_zero_bytes
((
const
char
*
)
ptr
,
Inet6
::
binary_length
());
}
int
store_native
(
const
Native
&
value
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
DBUG_ASSERT
(
value
.
length
()
==
Inet6
::
binary_length
());
memcpy
(
ptr
,
value
.
ptr
(),
value
.
length
());
return
0
;
}
int
store
(
const
char
*
str
,
size_t
length
,
CHARSET_INFO
*
cs
)
override
{
return
cs
==
&
my_charset_bin
?
store_binary
(
str
,
length
)
:
store_text
(
str
,
length
,
cs
);
}
int
store_text
(
const
char
*
str
,
size_t
length
,
CHARSET_INFO
*
cs
)
override
{
return
store_inet6_null_with_warn
(
Inet6_null
(
str
,
length
,
cs
),
ErrConvString
(
str
,
length
,
cs
));
}
int
store_binary
(
const
char
*
str
,
size_t
length
)
override
{
return
store_inet6_null_with_warn
(
Inet6_null
(
str
,
length
),
ErrConvString
(
str
,
length
,
&
my_charset_bin
));
}
int
store_hex_hybrid
(
const
char
*
str
,
size_t
length
)
override
{
return
Field_inet6
::
store_binary
(
str
,
length
);
}
int
store_decimal
(
const
my_decimal
*
num
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvDecimal
(
num
));
}
int
store
(
longlong
nr
,
bool
unsigned_flag
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvInteger
(
Longlong_hybrid
(
nr
,
unsigned_flag
)));
}
int
store
(
double
nr
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvDouble
(
nr
));
}
int
store_time_dec
(
const
MYSQL_TIME
*
ltime
,
uint
dec
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvTime
(
ltime
));
}
/*** Field conversion routines ***/
int
store_field
(
Field
*
from
)
override
{
// INSERT INTO t1 (inet6_field) SELECT different_field_type FROM t2;
return
from
->
save_in_field
(
this
);
}
int
save_in_field
(
Field
*
to
)
override
{
// INSERT INTO t2 (different_field_type) SELECT inet6_field FROM t1;
if
(
to
->
charset
()
==
&
my_charset_bin
&&
dynamic_cast
<
const
Type_handler_general_purpose_string
*>
(
to
->
type_handler
()))
{
NativeBufferInet6
res
;
val_native
(
&
res
);
return
to
->
store
(
res
.
ptr
(),
res
.
length
(),
&
my_charset_bin
);
}
return
save_in_field_str
(
to
);
}
Copy_func
*
get_copy_func
(
const
Field
*
from
)
const
override
{
// ALTER to INET6 from another field
return
do_field_string
;
}
Copy_func
*
get_copy_func_to
(
const
Field
*
to
)
const
override
{
if
(
type_handler
()
==
to
->
type_handler
())
{
// ALTER from INET6 to INET6
DBUG_ASSERT
(
pack_length
()
==
to
->
pack_length
());
DBUG_ASSERT
(
charset
()
==
to
->
charset
());
DBUG_ASSERT
(
sort_charset
()
==
to
->
sort_charset
());
return
Field
::
do_field_eq
;
}
// ALTER from INET6 to another data type
if
(
to
->
charset
()
==
&
my_charset_bin
&&
dynamic_cast
<
const
Type_handler_general_purpose_string
*>
(
to
->
type_handler
()))
{
/*
ALTER from INET6 to a binary string type, e.g.:
BINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
*/
return
do_field_inet6_native_to_binary
;
}
return
do_field_string
;
}
static
void
do_field_inet6_native_to_binary
(
Copy_field
*
copy
)
{
NativeBufferInet6
res
;
copy
->
from_field
->
val_native
(
&
res
);
copy
->
to_field
->
store
(
res
.
ptr
(),
res
.
length
(),
&
my_charset_bin
);
}
bool
memcpy_field_possible
(
const
Field
*
from
)
const
override
{
// INSERT INTO t1 (inet6_field) SELECT field2 FROM t2;
return
type_handler
()
==
from
->
type_handler
();
}
enum_conv_type
rpl_conv_type_from
(
const
Conv_source
&
source
,
const
Relay_log_info
*
rli
,
const
Conv_param
&
param
)
const
override
{
if
(
type_handler
()
==
source
.
type_handler
()
||
(
source
.
type_handler
()
==
&
type_handler_string
&&
source
.
type_handler
()
->
max_display_length_for_field
(
source
)
==
Inet6
::
binary_length
()))
return
rpl_conv_type_from_same_data_type
(
source
.
metadata
(),
rli
,
param
);
return
CONV_TYPE_IMPOSSIBLE
;
}
/*** Optimizer routines ***/
bool
test_if_equality_guarantees_uniqueness
(
const
Item
*
const_item
)
const
override
{
/*
This condition:
WHERE inet6_field=const
should return a single distinct value only,
as comparison is done according to INET6.
*/
return
true
;
}
bool
can_be_substituted_to_equal_item
(
const
Context
&
ctx
,
const
Item_equal
*
item_equal
)
override
{
switch
(
ctx
.
subst_constraint
())
{
case
ANY_SUBST
:
return
ctx
.
compare_type_handler
()
==
item_equal
->
compare_type_handler
();
case
IDENTITY_SUBST
:
return
true
;
}
return
false
;
}
Item
*
get_equal_const_item
(
THD
*
thd
,
const
Context
&
ctx
,
Item
*
const_item
)
override
;
bool
can_optimize_keypart_ref
(
const
Item_bool_func
*
cond
,
const
Item
*
item
)
const
override
{
/*
Mixing of two different non-traditional types is currently prevented.
This may change in the future. For example, INET4 and INET6
data types can be made comparable.
But we allow mixing INET6 to a data type directly inherited from
a traditional type, e.g. INET6=VARCHAR/JSON.
*/
DBUG_ASSERT
(
item
->
type_handler
()
->
type_handler_base_or_self
()
->
is_traditional_scalar_type
()
||
item
->
type_handler
()
==
type_handler
());
return
true
;
}
/**
Test if Field can use range optimizer for a standard comparison operation:
<=, <, =, <=>, >, >=
Note, this method does not cover spatial operations.
*/
bool
can_optimize_range
(
const
Item_bool_func
*
cond
,
const
Item
*
item
,
bool
is_eq_func
)
const
override
{
// See the DBUG_ASSERT comment in can_optimize_keypart_ref()
DBUG_ASSERT
(
item
->
type_handler
()
->
type_handler_base_or_self
()
->
is_traditional_scalar_type
()
||
item
->
type_handler
()
==
type_handler
());
return
true
;
}
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
prm
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
override
{
DBUG_ENTER
(
"Field_inet6::get_mm_leaf"
);
if
(
!
can_optimize_scalar_range
(
prm
,
key_part
,
cond
,
op
,
value
))
DBUG_RETURN
(
0
);
int
err
=
value
->
save_in_field_no_warnings
(
this
,
1
);
if
((
op
!=
SCALAR_CMP_EQUAL
&&
is_real_null
())
||
err
<
0
)
DBUG_RETURN
(
&
null_element
);
if
(
err
>
0
)
{
if
(
op
==
SCALAR_CMP_EQ
||
op
==
SCALAR_CMP_EQUAL
)
DBUG_RETURN
(
new
(
prm
->
mem_root
)
SEL_ARG_IMPOSSIBLE
(
this
));
DBUG_RETURN
(
NULL
);
/* Cannot infer anything */
}
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
}
bool
can_optimize_hash_join
(
const
Item_bool_func
*
cond
,
const
Item
*
item
)
const
override
{
return
can_optimize_keypart_ref
(
cond
,
item
);
}
bool
can_optimize_group_min_max
(
const
Item_bool_func
*
cond
,
const
Item
*
const_item
)
const
override
{
return
true
;
}
uint
row_pack_length
()
const
override
{
return
pack_length
();
}
Binlog_type_info
binlog_type_info
()
const
override
{
DBUG_ASSERT
(
type
()
==
binlog_type
());
return
Binlog_type_info_fixed_string
(
Field_inet6
::
binlog_type
(),
Inet6
::
binary_length
(),
&
my_charset_bin
);
}
uchar
*
pack
(
uchar
*
to
,
const
uchar
*
from
,
uint
max_length
)
override
{
DBUG_PRINT
(
"debug"
,
(
"Packing field '%s'"
,
field_name
.
str
));
return
StringPack
(
&
my_charset_bin
,
Inet6
::
binary_length
()).
pack
(
to
,
from
,
max_length
);
}
const
uchar
*
unpack
(
uchar
*
to
,
const
uchar
*
from
,
const
uchar
*
from_end
,
uint
param_data
)
override
{
return
StringPack
(
&
my_charset_bin
,
Inet6
::
binary_length
()).
unpack
(
to
,
from
,
from_end
,
param_data
);
}
uint
max_packed_col_length
(
uint
max_length
)
override
{
return
StringPack
::
max_packed_col_length
(
max_length
);
}
uint
packed_col_length
(
const
uchar
*
data_ptr
,
uint
length
)
override
{
return
StringPack
::
packed_col_length
(
data_ptr
,
length
);
}
/**********/
uint
size_of
()
const
override
{
return
sizeof
(
*
this
);
}
};
class
Item_typecast_inet6
:
public
Item_func
{
public:
Item_typecast_inet6
(
THD
*
thd
,
Item
*
a
)
:
Item_func
(
thd
,
a
)
{}
const
Type_handler
*
type_handler
()
const
override
{
return
&
type_handler_inet6
;
}
enum
Functype
functype
()
const
override
{
return
CHAR_TYPECAST_FUNC
;
}
bool
eq
(
const
Item
*
item
,
bool
binary_cmp
)
const
override
{
if
(
this
==
item
)
return
true
;
if
(
item
->
type
()
!=
FUNC_ITEM
||
functype
()
!=
((
Item_func
*
)
item
)
->
functype
())
return
false
;
if
(
type_handler
()
!=
item
->
type_handler
())
return
false
;
Item_typecast_inet6
*
cast
=
(
Item_typecast_inet6
*
)
item
;
return
args
[
0
]
->
eq
(
cast
->
args
[
0
],
binary_cmp
);
}
LEX_CSTRING
func_name_cstring
()
const
override
{
static
LEX_CSTRING
name
=
{
STRING_WITH_LEN
(
"cast_as_inet6"
)
};
return
name
;
}
void
print
(
String
*
str
,
enum_query_type
query_type
)
override
{
str
->
append
(
STRING_WITH_LEN
(
"cast("
));
args
[
0
]
->
print
(
str
,
query_type
);
str
->
append
(
STRING_WITH_LEN
(
" as inet6)"
));
}
bool
fix_length_and_dec
()
override
{
Type_std_attributes
::
operator
=
(
Type_std_attributes_inet6
());
if
(
Inet6
::
fix_fields_maybe_null_on_conversion_to_inet6
(
args
[
0
]))
set_maybe_null
();
return
false
;
}
String
*
val_str
(
String
*
to
)
override
{
Inet6_null
tmp
(
args
[
0
]);
return
(
null_value
=
tmp
.
is_null
()
||
tmp
.
to_string
(
to
))
?
NULL
:
to
;
}
longlong
val_int
()
override
{
return
0
;
}
double
val_real
()
override
{
return
0
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
override
{
Inet6_null
tmp
(
args
[
0
]);
return
null_value
=
tmp
.
is_null
()
||
tmp
.
to_native
(
to
);
}
Item
*
get_copy
(
THD
*
thd
)
override
{
return
get_item_copy
<
Item_typecast_inet6
>
(
thd
,
this
);
}
};
class
Item_cache_inet6
:
public
Item_cache
{
NativeBufferInet6
m_value
;
public:
Item_cache_inet6
(
THD
*
thd
)
:
Item_cache
(
thd
,
&
type_handler_inet6
)
{
}
Item
*
get_copy
(
THD
*
thd
)
{
return
get_item_copy
<
Item_cache_inet6
>
(
thd
,
this
);
}
bool
cache_value
()
{
if
(
!
example
)
return
false
;
value_cached
=
true
;
/*
Merge comments: in 10.7 this code migrated to
Item_cache_fbt in to sql/sql_type_fixedbin.h
*/
null_value_inside
=
null_value
=
example
->
val_native_with_conversion_result
(
current_thd
,
&
m_value
,
type_handler
());
return
true
;
}
String
*
val_str
(
String
*
to
)
{
if
(
!
has_value
())
return
NULL
;
Inet6_null
tmp
(
m_value
.
ptr
(),
m_value
.
length
());
return
tmp
.
is_null
()
||
tmp
.
to_string
(
to
)
?
NULL
:
to
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
{
if
(
!
has_value
())
return
NULL
;
my_decimal_set_zero
(
to
);
return
to
;
}
longlong
val_int
()
{
if
(
!
has_value
())
return
0
;
return
0
;
}
double
val_real
()
{
if
(
!
has_value
())
return
0
;
return
0
;
}
longlong
val_datetime_packed
(
THD
*
thd
)
{
DBUG_ASSERT
(
0
);
if
(
!
has_value
())
return
0
;
return
0
;
}
longlong
val_time_packed
(
THD
*
thd
)
{
DBUG_ASSERT
(
0
);
if
(
!
has_value
())
return
0
;
return
0
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
{
if
(
!
has_value
())
return
true
;
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
{
if
(
!
has_value
())
return
true
;
return
to
->
copy
(
m_value
.
ptr
(),
m_value
.
length
());
}
};
class
Item_literal_inet6
:
public
Item_literal
{
Inet6
m_value
;
public:
Item_literal_inet6
(
THD
*
thd
)
:
Item_literal
(
thd
),
m_value
(
Inet6_zero
())
{
}
Item_literal_inet6
(
THD
*
thd
,
const
Inet6
&
value
)
:
Item_literal
(
thd
),
m_value
(
value
)
{
}
const
Type_handler
*
type_handler
()
const
override
{
return
&
type_handler_inet6
;
}
longlong
val_int
()
override
{
return
0
;
}
double
val_real
()
override
{
return
0
;
}
String
*
val_str
(
String
*
to
)
override
{
return
m_value
.
to_string
(
to
)
?
NULL
:
to
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
override
{
return
m_value
.
to_native
(
to
);
}
void
print
(
String
*
str
,
enum_query_type
query_type
)
override
{
StringBufferInet6
tmp
;
m_value
.
to_string
(
&
tmp
);
str
->
append
(
STRING_WITH_LEN
(
"INET6'"
));
str
->
append
(
tmp
);
str
->
append
(
'\''
);
}
Item
*
get_copy
(
THD
*
thd
)
override
{
return
get_item_copy
<
Item_literal_inet6
>
(
thd
,
this
);
}
// Non-overriding methods
void
set_value
(
const
Inet6
&
value
)
{
m_value
=
value
;
}
};
class
Item_copy_inet6
:
public
Item_copy
{
NativeBufferInet6
m_value
;
public:
Item_copy_inet6
(
THD
*
thd
,
Item
*
item_arg
)
:
Item_copy
(
thd
,
item_arg
)
{}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
override
{
if
(
null_value
)
return
true
;
return
to
->
copy
(
m_value
.
ptr
(),
m_value
.
length
());
}
String
*
val_str
(
String
*
to
)
override
{
if
(
null_value
)
return
NULL
;
Inet6_null
tmp
(
m_value
.
ptr
(),
m_value
.
length
());
return
tmp
.
is_null
()
||
tmp
.
to_string
(
to
)
?
NULL
:
to
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
double
val_real
()
override
{
return
0
;
}
longlong
val_int
()
override
{
return
0
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
null_value
;
}
void
copy
()
override
{
null_value
=
item
->
val_native
(
current_thd
,
&
m_value
);
DBUG_ASSERT
(
null_value
==
item
->
null_value
);
}
int
save_in_field
(
Field
*
field
,
bool
no_conversions
)
override
{
return
Item
::
save_in_field
(
field
,
no_conversions
);
}
Item
*
get_copy
(
THD
*
thd
)
override
{
return
get_item_copy
<
Item_copy_inet6
>
(
thd
,
this
);
}
};
class
in_inet6
:
public
in_vector
{
Inet6
m_value
;
static
int
cmp_inet6
(
void
*
cmp_arg
,
Inet6
*
a
,
Inet6
*
b
)
{
return
a
->
cmp
(
*
b
);
}
public:
in_inet6
(
THD
*
thd
,
uint
elements
)
:
in_vector
(
thd
,
elements
,
sizeof
(
Inet6
),
(
qsort2_cmp
)
cmp_inet6
,
0
),
m_value
(
Inet6_zero
())
{
}
const
Type_handler
*
type_handler
()
const
override
{
return
&
type_handler_inet6
;
}
void
set
(
uint
pos
,
Item
*
item
)
override
{
Inet6
*
buff
=
&
((
Inet6
*
)
base
)[
pos
];
Inet6_null
value
(
item
);
if
(
value
.
is_null
())
*
buff
=
Inet6_zero
();
else
*
buff
=
value
;
}
uchar
*
get_value
(
Item
*
item
)
override
{
Inet6_null
value
(
item
);
if
(
value
.
is_null
())
return
0
;
m_value
=
value
;
return
(
uchar
*
)
&
m_value
;
}
Item
*
create_item
(
THD
*
thd
)
override
{
return
new
(
thd
->
mem_root
)
Item_literal_inet6
(
thd
);
}
void
value_to_item
(
uint
pos
,
Item
*
item
)
override
{
const
Inet6
&
buff
=
(((
Inet6
*
)
base
)[
pos
]);
static_cast
<
Item_literal_inet6
*>
(
item
)
->
set_value
(
buff
);
}
};
class
Item_char_typecast_func_handler_inet6_to_binary
:
public
Item_handled_func
::
Handler_str
{
public:
const
Type_handler
*
return_type_handler
(
const
Item_handled_func
*
item
)
const
override
{
if
(
item
->
max_length
>
MAX_FIELD_VARCHARLENGTH
)
return
Type_handler
::
blob_type_handler
(
item
->
max_length
);
if
(
item
->
max_length
>
255
)
return
&
type_handler_varchar
;
return
&
type_handler_string
;
}
bool
fix_length_and_dec
(
Item_handled_func
*
xitem
)
const
override
{
return
false
;
}
String
*
val_str
(
Item_handled_func
*
item
,
String
*
to
)
const
override
{
DBUG_ASSERT
(
dynamic_cast
<
const
Item_char_typecast
*>
(
item
));
return
static_cast
<
Item_char_typecast
*>
(
item
)
->
val_str_binary_from_native
(
to
);
}
};
static
Item_char_typecast_func_handler_inet6_to_binary
item_char_typecast_func_handler_inet6_to_binary
;
bool
Type_handler_inet6
::
Item_char_typecast_fix_length_and_dec
(
Item_char_typecast
*
item
)
const
{
if
(
item
->
cast_charset
()
==
&
my_charset_bin
)
{
item
->
fix_length_and_dec_native_to_binary
(
Inet6
::
binary_length
());
item
->
set_func_handler
(
&
item_char_typecast_func_handler_inet6_to_binary
);
return
false
;
}
item
->
fix_length_and_dec_str
();
return
false
;
}
bool
Type_handler_inet6
::
character_or_binary_string_to_native
(
THD
*
thd
,
const
String
*
str
,
Native
*
to
)
const
{
if
(
str
->
charset
()
==
&
my_charset_bin
)
{
// Convert from a binary string
if
(
str
->
length
()
!=
Inet6
::
binary_length
()
||
to
->
copy
(
str
->
ptr
(),
str
->
length
()))
{
thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
return
true
;
}
return
false
;
}
// Convert from a character string
Inet6_null
tmp
(
*
str
);
if
(
tmp
.
is_null
())
thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
return
tmp
.
is_null
()
||
tmp
.
to_native
(
to
);
}
bool
Type_handler_inet6
::
Item_save_in_value
(
THD
*
thd
,
Item
*
item
,
st_value
*
value
)
const
{
value
->
m_type
=
DYN_COL_STRING
;
String
*
str
=
item
->
val_str
(
&
value
->
m_string
);
if
(
str
!=
&
value
->
m_string
&&
!
item
->
null_value
)
{
// "item" returned a non-NULL value
if
(
Inet6_null
(
*
str
).
is_null
())
{
/*
The value was not-null, but conversion to INET6 failed:
SELECT a, DECODE_ORACLE(inet6col, 'garbage', '<NULL>', '::01', '01')
FROM t1;
*/
thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
value
->
m_type
=
DYN_COL_NULL
;
return
true
;
}
// "item" returned a non-NULL value, and it was a valid INET6
value
->
m_string
.
set
(
str
->
ptr
(),
str
->
length
(),
str
->
charset
());
}
return
check_null
(
item
,
value
);
}
void
Type_handler_inet6
::
Item_param_setup_conversion
(
THD
*
thd
,
Item_param
*
param
)
const
{
param
->
setup_conversion_string
(
thd
,
thd
->
variables
.
character_set_client
);
}
void
Type_handler_inet6
::
make_sort_key_part
(
uchar
*
to
,
Item
*
item
,
const
SORT_FIELD_ATTR
*
sort_field
,
Sort_param
*
param
)
const
{
DBUG_ASSERT
(
item
->
type_handler
()
==
this
);
NativeBufferInet6
tmp
;
item
->
val_native_result
(
current_thd
,
&
tmp
);
if
(
item
->
maybe_null
())
{
if
(
item
->
null_value
)
{
memset
(
to
,
0
,
Inet6
::
binary_length
()
+
1
);
return
;
}
*
to
++=
1
;
}
DBUG_ASSERT
(
!
item
->
null_value
);
DBUG_ASSERT
(
Inet6
::
binary_length
()
==
tmp
.
length
());
DBUG_ASSERT
(
Inet6
::
binary_length
()
==
sort_field
->
length
);
memcpy
(
to
,
tmp
.
ptr
(),
tmp
.
length
());
}
uint
Type_handler_inet6
::
make_packed_sort_key_part
(
uchar
*
to
,
Item
*
item
,
const
SORT_FIELD_ATTR
*
sort_field
,
Sort_param
*
param
)
const
{
DBUG_ASSERT
(
item
->
type_handler
()
==
this
);
NativeBufferInet6
tmp
;
item
->
val_native_result
(
current_thd
,
&
tmp
);
if
(
item
->
maybe_null
())
{
if
(
item
->
null_value
)
{
*
to
++=
0
;
return
0
;
}
*
to
++=
1
;
}
DBUG_ASSERT
(
!
item
->
null_value
);
DBUG_ASSERT
(
Inet6
::
binary_length
()
==
tmp
.
length
());
DBUG_ASSERT
(
Inet6
::
binary_length
()
==
sort_field
->
length
);
memcpy
(
to
,
tmp
.
ptr
(),
tmp
.
length
());
return
tmp
.
length
();
}
void
Type_handler_inet6
::
sort_length
(
THD
*
thd
,
const
Type_std_attributes
*
item
,
SORT_FIELD_ATTR
*
attr
)
const
{
attr
->
original_length
=
attr
->
length
=
Inet6
::
binary_length
();
attr
->
suffix_length
=
0
;
}
cmp_item
*
Type_handler_inet6
::
make_cmp_item
(
THD
*
thd
,
CHARSET_INFO
*
cs
)
const
{
return
new
(
thd
->
mem_root
)
cmp_item_inet6
;
}
in_vector
*
Type_handler_inet6
::
make_in_vector
(
THD
*
thd
,
const
Item_func_in
*
func
,
uint
nargs
)
const
{
return
new
(
thd
->
mem_root
)
in_inet6
(
thd
,
nargs
);
}
Item
*
Type_handler_inet6
::
create_typecast_item
(
THD
*
thd
,
Item
*
item
,
const
Type_cast_attributes
&
attr
)
const
{
return
new
(
thd
->
mem_root
)
Item_typecast_inet6
(
thd
,
item
);
}
Item_cache
*
Type_handler_inet6
::
Item_get_cache
(
THD
*
thd
,
const
Item
*
item
)
const
{
return
new
(
thd
->
mem_root
)
Item_cache_inet6
(
thd
);
}
Item_copy
*
Type_handler_inet6
::
create_item_copy
(
THD
*
thd
,
Item
*
item
)
const
{
return
new
(
thd
->
mem_root
)
Item_copy_inet6
(
thd
,
item
);
}
Item
*
Type_handler_inet6
::
make_const_item_for_comparison
(
THD
*
thd
,
Item
*
src
,
const
Item
*
cmp
)
const
{
Inet6_null
tmp
(
src
);
if
(
tmp
.
is_null
())
return
new
(
thd
->
mem_root
)
Item_null
(
thd
,
src
->
name
.
str
);
return
new
(
thd
->
mem_root
)
Item_literal_inet6
(
thd
,
tmp
);
}
Item
*
Field_inet6
::
get_equal_const_item
(
THD
*
thd
,
const
Context
&
ctx
,
Item
*
const_item
)
{
Inet6_null
tmp
(
const_item
);
if
(
tmp
.
is_null
())
return
NULL
;
return
new
(
thd
->
mem_root
)
Item_literal_inet6
(
thd
,
tmp
);
}
Field
*
Type_handler_inet6
::
make_table_field_from_def
(
TABLE_SHARE
*
share
,
MEM_ROOT
*
mem_root
,
const
LEX_CSTRING
*
name
,
const
Record_addr
&
addr
,
const
Bit_addr
&
bit
,
const
Column_definition_attributes
*
attr
,
uint32
flags
)
const
{
return
new
(
mem_root
)
Field_inet6
(
name
,
addr
);
}
Field
*
Type_handler_inet6
::
make_table_field
(
MEM_ROOT
*
root
,
const
LEX_CSTRING
*
name
,
const
Record_addr
&
addr
,
const
Type_all_attributes
&
attr
,
TABLE_SHARE
*
share
)
const
{
return
new
(
root
)
Field_inet6
(
name
,
addr
);
}
Field
*
Type_handler_inet6
::
make_conversion_table_field
(
MEM_ROOT
*
root
,
TABLE
*
table
,
uint
metadata
,
const
Field
*
target
)
const
{
const
Record_addr
tmp
(
NULL
,
Bit_addr
(
true
));
return
new
(
table
->
in_use
->
mem_root
)
Field_inet6
(
&
empty_clex_str
,
tmp
);
}
bool
Type_handler_inet6
::
partition_field_check
(
const
LEX_CSTRING
&
field_name
,
Item
*
item_expr
)
const
{
if
(
item_expr
->
cmp_type
()
!=
STRING_RESULT
)
{
my_error
(
ER_WRONG_TYPE_COLUMN_VALUE_ERROR
,
MYF
(
0
));
return
true
;
}
return
false
;
}
bool
Type_handler_inet6
::
partition_field_append_value
(
String
*
to
,
Item
*
item_expr
,
CHARSET_INFO
*
field_cs
,
partition_value_print_mode_t
mode
)
const
{
StringBufferInet6
inet6str
;
Inet6_null
inet6
(
item_expr
);
if
(
inet6
.
is_null
())
{
my_error
(
ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
,
MYF
(
0
));
return
true
;
}
return
inet6
.
to_string
(
&
inet6str
)
||
to
->
append
(
'\''
)
||
to
->
append
(
inet6str
)
||
to
->
append
(
'\''
);
}
/***************************************************************/
class
Type_collection_inet
:
public
Type_collection
{
const
Type_handler
*
aggregate_common
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
{
if
(
a
==
b
)
return
a
;
return
NULL
;
}
const
Type_handler
*
aggregate_if_string
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
{
static
const
Type_aggregator
::
Pair
agg
[]
=
{
{
&
type_handler_inet6
,
&
type_handler_null
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_varchar
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_string
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_tiny_blob
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_blob
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_medium_blob
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_long_blob
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_hex_hybrid
,
&
type_handler_inet6
},
{
NULL
,
NULL
,
NULL
}
};
return
Type_aggregator
::
find_handler_in_array
(
agg
,
a
,
b
,
true
);
}
public:
const
Type_handler
*
aggregate_for_result
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
const
Type_handler
*
h
;
if
((
h
=
aggregate_common
(
a
,
b
))
||
(
h
=
aggregate_if_string
(
a
,
b
)))
return
h
;
return
NULL
;
}
const
Type_handler
*
aggregate_for_min_max
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
return
aggregate_for_result
(
a
,
b
);
}
const
Type_handler
*
aggregate_for_comparison
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
if
(
const
Type_handler
*
h
=
aggregate_common
(
a
,
b
))
return
h
;
static
const
Type_aggregator
::
Pair
agg
[]
=
{
{
&
type_handler_inet6
,
&
type_handler_null
,
&
type_handler_inet6
},
{
&
type_handler_inet6
,
&
type_handler_long_blob
,
&
type_handler_inet6
},
{
NULL
,
NULL
,
NULL
}
};
return
Type_aggregator
::
find_handler_in_array
(
agg
,
a
,
b
,
true
);
}
const
Type_handler
*
aggregate_for_num_op
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
return
NULL
;
}
const
Type_handler
*
handler_by_name
(
const
LEX_CSTRING
&
name
)
const
override
{
if
(
type_handler_inet6
.
name
().
eq
(
name
))
return
&
type_handler_inet6
;
return
NULL
;
}
};
const
Type_collection
*
Type_handler_inet6
::
type_collection
()
const
const
Name
&
Inet6
::
default_value
()
{
static
Type_collection_inet
type_collection_inet
;
return
&
type_collection_inet
;
static
Name
def
(
STRING_WITH_LEN
(
"::"
))
;
return
def
;
}
plugin/type_inet/sql_type_inet.h
View file @
0e8544cd
#ifndef SQL_TYPE_INET_H
#define SQL_TYPE_INET_H
/* Copyright (c) 2011,
2013, Oracle and/or its affiliates. All rights reserved
.
/* Copyright (c) 2011,
2013, Oracle and/or its affiliates
.
Copyright (c) 2014 MariaDB Foundation
Copyright (c) 2019 MariaDB Corporation
Copyright (c) 2019
,2021
MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
...
...
@@ -31,14 +31,20 @@ static const size_t IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2;
*/
static
const
uint
IN6_ADDR_MAX_CHAR_LENGTH
=
8
*
4
+
7
;
#include "sql_type_fixedbin_storage.h"
class
NativeBufferInet6
:
public
NativeBuffer
<
IN6_ADDR_SIZE
+
1
>
class
Inet6
:
public
FixedBinTypeStorage
<
IN6_ADDR_SIZE
,
IN6_ADDR_MAX_CHAR_LENGTH
>
{
public:
using
FixedBinTypeStorage
::
FixedBinTypeStorage
;
bool
ascii_to_fbt
(
const
char
*
str
,
size_t
str_length
);
size_t
to_string
(
char
*
dst
,
size_t
dstsize
)
const
;
static
const
Name
&
default_value
();
};
class
StringBufferInet6
:
public
StringBuffer
<
IN6_ADDR_MAX_CHAR_LENGTH
+
1
>
{
}
;
#include "sql_type_fixedbin.h"
typedef
FixedBinTypeBundle
<
Inet6
>
Inet6Bundle
;
/***********************************************************************/
...
...
@@ -132,898 +138,4 @@ class Inet4_null: public Inet4, public Null_flag
}
};
class
Inet6
{
protected:
char
m_buffer
[
IN6_ADDR_SIZE
];
bool
make_from_item
(
Item
*
item
,
bool
warn
);
bool
ascii_to_ipv6
(
const
char
*
str
,
size_t
str_length
);
bool
character_string_to_ipv6
(
const
char
*
str
,
size_t
str_length
,
CHARSET_INFO
*
cs
)
{
if
(
cs
->
state
&
MY_CS_NONASCII
)
{
char
tmp
[
IN6_ADDR_MAX_CHAR_LENGTH
];
String_copier
copier
;
uint
length
=
copier
.
well_formed_copy
(
&
my_charset_latin1
,
tmp
,
sizeof
(
tmp
),
cs
,
str
,
str_length
);
return
ascii_to_ipv6
(
tmp
,
length
);
}
return
ascii_to_ipv6
(
str
,
str_length
);
}
bool
make_from_character_or_binary_string
(
const
String
*
str
,
bool
warn
);
bool
binary_to_ipv6
(
const
char
*
str
,
size_t
length
)
{
if
(
length
!=
sizeof
(
m_buffer
))
return
true
;
memcpy
(
m_buffer
,
str
,
length
);
return
false
;
}
Inet6
()
{
}
public:
static
uint
binary_length
()
{
return
IN6_ADDR_SIZE
;
}
/**
Non-abbreviated syntax is 8 groups, up to 4 digits each,
plus 7 delimiters between the groups.
Abbreviated syntax is even shorter.
*/
static
uint
max_char_length
()
{
return
IN6_ADDR_MAX_CHAR_LENGTH
;
}
static
bool
only_zero_bytes
(
const
char
*
ptr
,
uint
length
)
{
for
(
uint
i
=
0
;
i
<
length
;
i
++
)
{
if
(
ptr
[
i
]
!=
0
)
return
false
;
}
return
true
;
}
/*
Check at Item's fix_fields() time if "item" can return a nullable value
on conversion to INET6, or conversion produces a NOT NULL INET6 value.
*/
static
bool
fix_fields_maybe_null_on_conversion_to_inet6
(
Item
*
item
);
public:
Inet6
(
Item
*
item
,
bool
*
error
,
bool
warn
=
true
)
{
*
error
=
make_from_item
(
item
,
warn
);
}
void
to_binary
(
char
*
str
,
size_t
str_size
)
const
{
DBUG_ASSERT
(
str_size
>=
sizeof
(
m_buffer
));
memcpy
(
str
,
m_buffer
,
sizeof
(
m_buffer
));
}
bool
to_binary
(
String
*
to
)
const
{
return
to
->
copy
(
m_buffer
,
sizeof
(
m_buffer
),
&
my_charset_bin
);
}
bool
to_native
(
Native
*
to
)
const
{
return
to
->
copy
(
m_buffer
,
sizeof
(
m_buffer
));
}
size_t
to_string
(
char
*
dst
,
size_t
dstsize
)
const
;
bool
to_string
(
String
*
to
)
const
{
to
->
set_charset
(
&
my_charset_latin1
);
if
(
to
->
alloc
(
INET6_ADDRSTRLEN
))
return
true
;
to
->
length
((
uint32
)
to_string
((
char
*
)
to
->
ptr
(),
INET6_ADDRSTRLEN
));
return
false
;
}
bool
is_v4compat
()
const
{
static_assert
(
sizeof
(
in6_addr
)
==
IN6_ADDR_SIZE
,
"unexpected in6_addr size"
);
return
IN6_IS_ADDR_V4COMPAT
((
struct
in6_addr
*
)
m_buffer
);
}
bool
is_v4mapped
()
const
{
static_assert
(
sizeof
(
in6_addr
)
==
IN6_ADDR_SIZE
,
"unexpected in6_addr size"
);
return
IN6_IS_ADDR_V4MAPPED
((
struct
in6_addr
*
)
m_buffer
);
}
int
cmp
(
const
char
*
str
,
size_t
length
)
const
{
DBUG_ASSERT
(
length
==
sizeof
(
m_buffer
));
return
memcmp
(
m_buffer
,
str
,
length
);
}
int
cmp
(
const
Binary_string
&
other
)
const
{
return
cmp
(
other
.
ptr
(),
other
.
length
());
}
int
cmp
(
const
Inet6
&
other
)
const
{
return
memcmp
(
m_buffer
,
other
.
m_buffer
,
sizeof
(
m_buffer
));
}
};
class
Inet6_zero
:
public
Inet6
{
public:
Inet6_zero
()
{
bzero
(
&
m_buffer
,
sizeof
(
m_buffer
));
}
};
class
Inet6_null
:
public
Inet6
,
public
Null_flag
{
public:
// Initialize from a text representation
Inet6_null
(
const
char
*
str
,
size_t
length
,
CHARSET_INFO
*
cs
)
:
Null_flag
(
character_string_to_ipv6
(
str
,
length
,
cs
))
{
}
Inet6_null
(
const
String
&
str
)
:
Inet6_null
(
str
.
ptr
(),
str
.
length
(),
str
.
charset
())
{
}
// Initialize from a binary representation
Inet6_null
(
const
char
*
str
,
size_t
length
)
:
Null_flag
(
binary_to_ipv6
(
str
,
length
))
{
}
Inet6_null
(
const
Binary_string
&
str
)
:
Inet6_null
(
str
.
ptr
(),
str
.
length
())
{
}
// Initialize from an Item
Inet6_null
(
Item
*
item
,
bool
warn
=
true
)
:
Null_flag
(
make_from_item
(
item
,
warn
))
{
}
public:
const
Inet6
&
to_inet6
()
const
{
DBUG_ASSERT
(
!
is_null
());
return
*
this
;
}
void
to_binary
(
char
*
str
,
size_t
str_size
)
const
{
to_inet6
().
to_binary
(
str
,
str_size
);
}
bool
to_binary
(
String
*
to
)
const
{
return
to_inet6
().
to_binary
(
to
);
}
size_t
to_string
(
char
*
dst
,
size_t
dstsize
)
const
{
return
to_inet6
().
to_string
(
dst
,
dstsize
);
}
bool
to_string
(
String
*
to
)
const
{
return
to_inet6
().
to_string
(
to
);
}
bool
is_v4compat
()
const
{
return
to_inet6
().
is_v4compat
();
}
bool
is_v4mapped
()
const
{
return
to_inet6
().
is_v4mapped
();
}
};
class
Type_std_attributes_inet6
:
public
Type_std_attributes
{
public:
Type_std_attributes_inet6
()
:
Type_std_attributes
(
Type_numeric_attributes
(
Inet6
::
max_char_length
(),
0
,
true
),
DTCollation_numeric
())
{
}
};
class
Type_handler_inet6
:
public
Type_handler
{
bool
character_or_binary_string_to_native
(
THD
*
thd
,
const
String
*
str
,
Native
*
to
)
const
;
public:
~
Type_handler_inet6
()
override
{}
const
Type_collection
*
type_collection
()
const
override
;
const
Name
&
default_value
()
const
override
{
static
Name
def
(
STRING_WITH_LEN
(
"::"
));
return
def
;
}
protocol_send_type_t
protocol_send_type
()
const
override
{
return
PROTOCOL_SEND_STRING
;
}
bool
Item_append_extended_type_info
(
Send_field_extended_metadata
*
to
,
const
Item
*
item
)
const
override
{
return
to
->
set_data_type_name
(
name
().
lex_cstring
());
}
enum_field_types
field_type
()
const
override
{
return
MYSQL_TYPE_STRING
;
}
Item_result
result_type
()
const
override
{
return
STRING_RESULT
;
}
Item_result
cmp_type
()
const
override
{
return
STRING_RESULT
;
}
enum_dynamic_column_type
dyncol_type
(
const
Type_all_attributes
*
attr
)
const
override
{
return
DYN_COL_STRING
;
}
uint32
max_display_length_for_field
(
const
Conv_source
&
src
)
const
override
{
return
Inet6
::
max_char_length
();
}
const
Type_handler
*
type_handler_for_comparison
()
const
override
{
return
this
;
}
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
override
{
DBUG_ASSERT
(
field
->
type_handler
()
==
this
);
Inet6_null
ni
(
item
);
// Convert Item to INET6
if
(
ni
.
is_null
())
return
0
;
NativeBufferInet6
tmp
;
if
(
field
->
val_native
(
&
tmp
))
{
DBUG_ASSERT
(
0
);
return
0
;
}
return
-
ni
.
cmp
(
tmp
);
}
CHARSET_INFO
*
charset_for_protocol
(
const
Item
*
item
)
const
override
{
return
item
->
collation
.
collation
;
}
bool
is_scalar_type
()
const
override
{
return
true
;
}
bool
is_val_native_ready
()
const
override
{
return
true
;
}
bool
can_return_int
()
const
override
{
return
false
;
}
bool
can_return_decimal
()
const
override
{
return
false
;
}
bool
can_return_real
()
const
override
{
return
false
;
}
bool
can_return_str
()
const
override
{
return
true
;
}
bool
can_return_text
()
const
override
{
return
true
;
}
bool
can_return_date
()
const
override
{
return
false
;
}
bool
can_return_time
()
const
override
{
return
false
;
}
bool
convert_to_binary_using_val_native
()
const
override
{
return
true
;
}
decimal_digits_t
Item_time_precision
(
THD
*
thd
,
Item
*
item
)
const
override
{
return
0
;
}
decimal_digits_t
Item_datetime_precision
(
THD
*
thd
,
Item
*
item
)
const
override
{
return
0
;
}
decimal_digits_t
Item_decimal_scale
(
const
Item
*
item
)
const
override
{
return
0
;
}
decimal_digits_t
Item_decimal_precision
(
const
Item
*
item
)
const
override
{
/*
This will be needed if we ever allow cast from INET6 to DECIMAL.
Decimal precision of INET6 is 39 digits:
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' =
340282366920938463463374607431768211456 = 39 digits
*/
return
39
;
}
/*
Returns how many digits a divisor adds into a division result.
See Item::divisor_precision_increment() in item.h for more comments.
*/
decimal_digits_t
Item_divisor_precision_increment
(
const
Item
*
)
const
override
{
return
0
;
}
/**
Makes a temporary table Field to handle numeric aggregate functions,
e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc.
*/
Field
*
make_num_distinct_aggregator_field
(
MEM_ROOT
*
,
const
Item
*
)
const
override
{
DBUG_ASSERT
(
0
);
return
0
;
}
Field
*
make_conversion_table_field
(
MEM_ROOT
*
root
,
TABLE
*
TABLE
,
uint
metadata
,
const
Field
*
target
)
const
override
;
// Fix attributes after the parser
bool
Column_definition_fix_attributes
(
Column_definition
*
c
)
const
override
{
c
->
length
=
Inet6
::
max_char_length
();
return
false
;
}
bool
Column_definition_prepare_stage1
(
THD
*
thd
,
MEM_ROOT
*
mem_root
,
Column_definition
*
def
,
handler
*
file
,
ulonglong
table_flags
,
const
Column_derived_attributes
*
derived_attr
)
const
override
{
def
->
prepare_stage1_simple
(
&
my_charset_numeric
);
return
false
;
}
bool
Column_definition_redefine_stage1
(
Column_definition
*
def
,
const
Column_definition
*
dup
,
const
handler
*
file
)
const
override
{
def
->
redefine_stage1_common
(
dup
,
file
);
def
->
set_compression_method
(
dup
->
compression_method
());
def
->
create_length_to_internal_length_string
();
return
false
;
}
bool
Column_definition_prepare_stage2
(
Column_definition
*
def
,
handler
*
file
,
ulonglong
table_flags
)
const
override
{
def
->
pack_flag
=
FIELDFLAG_BINARY
;
return
false
;
}
bool
partition_field_check
(
const
LEX_CSTRING
&
field_name
,
Item
*
item_expr
)
const
override
;
bool
partition_field_append_value
(
String
*
to
,
Item
*
item_expr
,
CHARSET_INFO
*
field_cs
,
partition_value_print_mode_t
mode
)
const
override
;
Field
*
make_table_field
(
MEM_ROOT
*
root
,
const
LEX_CSTRING
*
name
,
const
Record_addr
&
addr
,
const
Type_all_attributes
&
attr
,
TABLE_SHARE
*
table
)
const
override
;
Field
*
make_table_field_from_def
(
TABLE_SHARE
*
share
,
MEM_ROOT
*
mem_root
,
const
LEX_CSTRING
*
name
,
const
Record_addr
&
addr
,
const
Bit_addr
&
bit
,
const
Column_definition_attributes
*
attr
,
uint32
flags
)
const
override
;
void
Column_definition_attributes_frm_pack
(
const
Column_definition_attributes
*
def
,
uchar
*
buff
)
const
override
{
def
->
frm_pack_basic
(
buff
);
def
->
frm_pack_charset
(
buff
);
}
bool
Column_definition_attributes_frm_unpack
(
Column_definition_attributes
*
def
,
TABLE_SHARE
*
share
,
const
uchar
*
buffer
,
LEX_CUSTRING
*
gis_options
)
const
override
{
def
->
frm_unpack_basic
(
buffer
);
return
def
->
frm_unpack_charset
(
share
,
buffer
);
}
void
make_sort_key_part
(
uchar
*
to
,
Item
*
item
,
const
SORT_FIELD_ATTR
*
sort_field
,
Sort_param
*
param
)
const
override
;
uint
make_packed_sort_key_part
(
uchar
*
to
,
Item
*
item
,
const
SORT_FIELD_ATTR
*
sort_field
,
Sort_param
*
param
)
const
override
;
void
sort_length
(
THD
*
thd
,
const
Type_std_attributes
*
item
,
SORT_FIELD_ATTR
*
attr
)
const
override
;
uint32
max_display_length
(
const
Item
*
item
)
const
override
{
return
Inet6
::
max_char_length
();
}
uint32
calc_pack_length
(
uint32
length
)
const
override
{
return
Inet6
::
binary_length
();
}
void
Item_update_null_value
(
Item
*
item
)
const
override
{
NativeBufferInet6
tmp
;
item
->
val_native
(
current_thd
,
&
tmp
);
}
bool
Item_save_in_value
(
THD
*
thd
,
Item
*
item
,
st_value
*
value
)
const
override
;
void
Item_param_setup_conversion
(
THD
*
thd
,
Item_param
*
param
)
const
override
;
void
Item_param_set_param_func
(
Item_param
*
param
,
uchar
**
pos
,
ulong
len
)
const
override
{
param
->
set_param_str
(
pos
,
len
);
}
bool
Item_param_set_from_value
(
THD
*
thd
,
Item_param
*
param
,
const
Type_all_attributes
*
attr
,
const
st_value
*
val
)
const
override
{
param
->
unsigned_flag
=
false
;
//QQ
param
->
setup_conversion_string
(
thd
,
attr
->
collation
.
collation
);
/*
Exact value of max_length is not known unless data is converted to
charset of connection, so we have to set it later.
*/
return
param
->
set_str
(
val
->
m_string
.
ptr
(),
val
->
m_string
.
length
(),
attr
->
collation
.
collation
,
attr
->
collation
.
collation
);
}
bool
Item_param_val_native
(
THD
*
thd
,
Item_param
*
item
,
Native
*
to
)
const
override
{
StringBufferInet6
buffer
;
String
*
str
=
item
->
val_str
(
&
buffer
);
if
(
!
str
)
return
true
;
Inet6_null
tmp
(
*
str
);
return
tmp
.
is_null
()
||
tmp
.
to_native
(
to
);
}
bool
Item_send
(
Item
*
item
,
Protocol
*
p
,
st_value
*
buf
)
const
override
{
return
Item_send_str
(
item
,
p
,
buf
);
}
int
Item_save_in_field
(
Item
*
item
,
Field
*
field
,
bool
no_conversions
)
const
override
{
if
(
field
->
type_handler
()
==
this
)
{
NativeBuffer
<
MAX_FIELD_WIDTH
>
tmp
;
bool
rc
=
item
->
val_native
(
current_thd
,
&
tmp
);
if
(
rc
||
item
->
null_value
)
return
set_field_to_null_with_conversions
(
field
,
no_conversions
);
field
->
set_notnull
();
return
field
->
store_native
(
tmp
);
}
return
item
->
save_str_in_field
(
field
,
no_conversions
);
}
String
*
print_item_value
(
THD
*
thd
,
Item
*
item
,
String
*
str
)
const
override
{
StringBufferInet6
buf
;
String
*
result
=
item
->
val_str
(
&
buf
);
/*
TODO: This should eventually use one of these notations:
1. CAST('::' AS INET6)
Problem: CAST is not supported as a NAME_CONST() argument.
2. INET6'::
Problem: This syntax is not supported by the parser yet.
*/
return
!
result
||
str
->
realloc
(
result
->
length
()
+
2
)
||
str
->
append
(
STRING_WITH_LEN
(
"'"
))
||
str
->
append
(
result
->
ptr
(),
result
->
length
())
||
str
->
append
(
STRING_WITH_LEN
(
"'"
))
?
NULL
:
str
;
}
/**
Check if
WHERE expr=value AND expr=const
can be rewritten as:
WHERE const=value AND expr=const
"this" is the comparison handler that is used by "target".
@param target - the predicate expr=value,
whose "expr" argument will be replaced to "const".
@param target_expr - the target's "expr" which will be replaced to "const".
@param target_value - the target's second argument, it will remain unchanged.
@param source - the equality predicate expr=const (or expr<=>const)
that can be used to rewrite the "target" part
(under certain conditions, see the code).
@param source_expr - the source's "expr". It should be exactly equal to
the target's "expr" to make condition rewrite possible.
@param source_const - the source's "const" argument, it will be inserted
into "target" instead of "expr".
*/
bool
can_change_cond_ref_to_const
(
Item_bool_func2
*
target
,
Item
*
target_expr
,
Item
*
target_value
,
Item_bool_func2
*
source
,
Item
*
source_expr
,
Item
*
source_const
)
const
override
{
/*
WHERE COALESCE(inet6_col)='::1' AND COALESCE(inet6_col)=CONCAT(a); -->
WHERE COALESCE(inet6_col)='::1' AND '::1'=CONCAT(a);
*/
return
target
->
compare_type_handler
()
==
source
->
compare_type_handler
();
}
bool
subquery_type_allows_materialization
(
const
Item
*
inner
,
const
Item
*
outer
,
bool
)
const
override
{
/*
Example:
SELECT * FROM t1 WHERE a IN (SELECT inet6col FROM t1 GROUP BY inet6col);
Allow materialization only if the outer column is also INET6.
This can be changed for more relaxed rules in the future.
*/
DBUG_ASSERT
(
inner
->
type_handler
()
==
this
);
return
outer
->
type_handler
()
==
this
;
}
/**
Make a simple constant replacement item for a constant "src",
so the new item can futher be used for comparison with "cmp", e.g.:
src = cmp -> replacement = cmp
"this" is the type handler that is used to compare "src" and "cmp".
@param thd - current thread, for mem_root
@param src - The item that we want to replace. It's a const item,
but it can be complex enough to calculate on every row.
@param cmp - The src's comparand.
@retval - a pointer to the created replacement Item
@retval - NULL, if could not create a replacement (e.g. on EOM).
NULL is also returned for ROWs, because instead of replacing
a Item_row to a new Item_row, Type_handler_row just replaces
its elements.
*/
Item
*
make_const_item_for_comparison
(
THD
*
thd
,
Item
*
src
,
const
Item
*
cmp
)
const
override
;
Item_cache
*
Item_get_cache
(
THD
*
thd
,
const
Item
*
item
)
const
override
;
Item
*
create_typecast_item
(
THD
*
thd
,
Item
*
item
,
const
Type_cast_attributes
&
attr
)
const
override
;
Item_copy
*
create_item_copy
(
THD
*
thd
,
Item
*
item
)
const
override
;
int
cmp_native
(
const
Native
&
a
,
const
Native
&
b
)
const
override
{
DBUG_ASSERT
(
a
.
length
()
==
Inet6
::
binary_length
());
DBUG_ASSERT
(
b
.
length
()
==
Inet6
::
binary_length
());
return
memcmp
(
a
.
ptr
(),
b
.
ptr
(),
Inet6
::
binary_length
());
}
bool
set_comparator_func
(
THD
*
thd
,
Arg_comparator
*
cmp
)
const
override
{
return
cmp
->
set_cmp_func_native
(
thd
);
}
bool
Item_const_eq
(
const
Item_const
*
a
,
const
Item_const
*
b
,
bool
binary_cmp
)
const
override
{
return
false
;
//QQ
}
bool
Item_eq_value
(
THD
*
thd
,
const
Type_cmp_attributes
*
attr
,
Item
*
a
,
Item
*
b
)
const
override
{
Inet6_null
na
(
a
);
Inet6_null
nb
(
b
);
return
!
na
.
is_null
()
&&
!
nb
.
is_null
()
&&
!
na
.
cmp
(
nb
);
}
bool
Item_hybrid_func_fix_attributes
(
THD
*
thd
,
const
LEX_CSTRING
&
name
,
Type_handler_hybrid_field_type
*
h
,
Type_all_attributes
*
attr
,
Item
**
items
,
uint
nitems
)
const
override
{
attr
->
Type_std_attributes
::
operator
=
(
Type_std_attributes_inet6
());
h
->
set_handler
(
this
);
/*
If some of the arguments cannot be safely converted to "INET6 NOT NULL",
then mark the entire function nullability as NULL-able.
Otherwise, keep the generic nullability calculated by earlier stages:
- either by the most generic way in Item_func::fix_fields()
- or by Item_func_xxx::fix_length_and_dec() before the call of
Item_hybrid_func_fix_attributes()
IFNULL() is special. It does not need to test args[0].
*/
uint
first
=
dynamic_cast
<
Item_func_ifnull
*>
(
attr
)
?
1
:
0
;
for
(
uint
i
=
first
;
i
<
nitems
;
i
++
)
{
if
(
Inet6
::
fix_fields_maybe_null_on_conversion_to_inet6
(
items
[
i
]))
{
attr
->
set_type_maybe_null
(
true
);
break
;
}
}
return
false
;
}
bool
Item_func_min_max_fix_attributes
(
THD
*
thd
,
Item_func_min_max
*
func
,
Item
**
items
,
uint
nitems
)
const
override
{
return
Item_hybrid_func_fix_attributes
(
thd
,
func
->
func_name_cstring
(),
func
,
func
,
items
,
nitems
);
}
bool
Item_sum_hybrid_fix_length_and_dec
(
Item_sum_hybrid
*
func
)
const
override
{
func
->
Type_std_attributes
::
operator
=
(
Type_std_attributes_inet6
());
func
->
set_handler
(
this
);
return
false
;
}
bool
Item_sum_sum_fix_length_and_dec
(
Item_sum_sum
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_sum_avg_fix_length_and_dec
(
Item_sum_avg
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_sum_variance_fix_length_and_dec
(
Item_sum_variance
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_val_native_with_conversion
(
THD
*
thd
,
Item
*
item
,
Native
*
to
)
const
override
{
if
(
item
->
type_handler
()
==
this
)
return
item
->
val_native
(
thd
,
to
);
// No conversion needed
StringBufferInet6
buffer
;
String
*
str
=
item
->
val_str
(
&
buffer
);
return
str
?
character_or_binary_string_to_native
(
thd
,
str
,
to
)
:
true
;
}
bool
Item_val_native_with_conversion_result
(
THD
*
thd
,
Item
*
item
,
Native
*
to
)
const
override
{
if
(
item
->
type_handler
()
==
this
)
return
item
->
val_native_result
(
thd
,
to
);
// No conversion needed
StringBufferInet6
buffer
;
String
*
str
=
item
->
str_result
(
&
buffer
);
return
str
?
character_or_binary_string_to_native
(
thd
,
str
,
to
)
:
true
;
}
bool
Item_val_bool
(
Item
*
item
)
const
override
{
NativeBufferInet6
tmp
;
if
(
item
->
val_native
(
current_thd
,
&
tmp
))
return
false
;
return
!
Inet6
::
only_zero_bytes
(
tmp
.
ptr
(),
tmp
.
length
());
}
void
Item_get_date
(
THD
*
thd
,
Item
*
item
,
Temporal
::
Warn
*
buff
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
const
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
}
longlong
Item_val_int_signed_typecast
(
Item
*
item
)
const
override
{
DBUG_ASSERT
(
0
);
return
0
;
}
longlong
Item_val_int_unsigned_typecast
(
Item
*
item
)
const
override
{
DBUG_ASSERT
(
0
);
return
0
;
}
String
*
Item_func_hex_val_str_ascii
(
Item_func_hex
*
item
,
String
*
str
)
const
override
{
NativeBufferInet6
tmp
;
if
((
item
->
null_value
=
item
->
arguments
()[
0
]
->
val_native
(
current_thd
,
&
tmp
)))
return
NULL
;
DBUG_ASSERT
(
tmp
.
length
()
==
Inet6
::
binary_length
());
if
(
str
->
set_hex
(
tmp
.
ptr
(),
tmp
.
length
()))
{
str
->
length
(
0
);
str
->
set_charset
(
item
->
collation
.
collation
);
}
return
str
;
}
String
*
Item_func_hybrid_field_type_val_str
(
Item_func_hybrid_field_type
*
item
,
String
*
str
)
const
override
{
NativeBufferInet6
native
;
if
(
item
->
val_native
(
current_thd
,
&
native
))
{
DBUG_ASSERT
(
item
->
null_value
);
return
NULL
;
}
DBUG_ASSERT
(
native
.
length
()
==
Inet6
::
binary_length
());
Inet6_null
tmp
(
native
.
ptr
(),
native
.
length
());
return
tmp
.
is_null
()
||
tmp
.
to_string
(
str
)
?
NULL
:
str
;
}
double
Item_func_hybrid_field_type_val_real
(
Item_func_hybrid_field_type
*
)
const
override
{
return
0
;
}
longlong
Item_func_hybrid_field_type_val_int
(
Item_func_hybrid_field_type
*
)
const
override
{
return
0
;
}
my_decimal
*
Item_func_hybrid_field_type_val_decimal
(
Item_func_hybrid_field_type
*
,
my_decimal
*
to
)
const
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
void
Item_func_hybrid_field_type_get_date
(
THD
*
,
Item_func_hybrid_field_type
*
,
Temporal
::
Warn
*
,
MYSQL_TIME
*
to
,
date_mode_t
fuzzydate
)
const
override
{
set_zero_time
(
to
,
MYSQL_TIMESTAMP_TIME
);
}
// WHERE is Item_func_min_max_val_native???
String
*
Item_func_min_max_val_str
(
Item_func_min_max
*
func
,
String
*
str
)
const
override
{
Inet6_null
tmp
(
func
);
return
tmp
.
is_null
()
||
tmp
.
to_string
(
str
)
?
NULL
:
str
;
}
double
Item_func_min_max_val_real
(
Item_func_min_max
*
)
const
override
{
return
0
;
}
longlong
Item_func_min_max_val_int
(
Item_func_min_max
*
)
const
override
{
return
0
;
}
my_decimal
*
Item_func_min_max_val_decimal
(
Item_func_min_max
*
,
my_decimal
*
to
)
const
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
bool
Item_func_min_max_get_date
(
THD
*
thd
,
Item_func_min_max
*
,
MYSQL_TIME
*
to
,
date_mode_t
fuzzydate
)
const
override
{
set_zero_time
(
to
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
Item_func_between_fix_length_and_dec
(
Item_func_between
*
func
)
const
override
{
return
false
;
}
longlong
Item_func_between_val_int
(
Item_func_between
*
func
)
const
override
{
return
func
->
val_int_cmp_native
();
}
cmp_item
*
make_cmp_item
(
THD
*
thd
,
CHARSET_INFO
*
cs
)
const
override
;
in_vector
*
make_in_vector
(
THD
*
thd
,
const
Item_func_in
*
func
,
uint
nargs
)
const
override
;
bool
Item_func_in_fix_comparator_compatible_types
(
THD
*
thd
,
Item_func_in
*
func
)
const
override
{
if
(
func
->
compatible_types_scalar_bisection_possible
())
{
return
func
->
value_list_convert_const_to_int
(
thd
)
||
func
->
fix_for_scalar_comparison_using_bisection
(
thd
);
}
return
func
->
fix_for_scalar_comparison_using_cmp_items
(
thd
,
1U
<<
(
uint
)
STRING_RESULT
);
}
bool
Item_func_round_fix_length_and_dec
(
Item_func_round
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_int_val_fix_length_and_dec
(
Item_func_int_val
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_abs_fix_length_and_dec
(
Item_func_abs
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_neg_fix_length_and_dec
(
Item_func_neg
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_signed_fix_length_and_dec
(
Item_func_signed
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_unsigned_fix_length_and_dec
(
Item_func_unsigned
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_double_typecast_fix_length_and_dec
(
Item_double_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_float_typecast_fix_length_and_dec
(
Item_float_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_decimal_typecast_fix_length_and_dec
(
Item_decimal_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_char_typecast_fix_length_and_dec
(
Item_char_typecast
*
item
)
const
override
;
bool
Item_time_typecast_fix_length_and_dec
(
Item_time_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_date_typecast_fix_length_and_dec
(
Item_date_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_datetime_typecast_fix_length_and_dec
(
Item_datetime_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_plus_fix_length_and_dec
(
Item_func_plus
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_minus_fix_length_and_dec
(
Item_func_minus
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_mul_fix_length_and_dec
(
Item_func_mul
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_div_fix_length_and_dec
(
Item_func_div
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_mod_fix_length_and_dec
(
Item_func_mod
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
};
extern
MYSQL_PLUGIN_IMPORT
Type_handler_inet6
type_handler_inet6
;
#endif
/* SQL_TYPE_INET_H */
sql/sql_string.h
View file @
0e8544cd
...
...
@@ -484,6 +484,11 @@ class Binary_string: public Sql_alloc
if
(
str
.
Alloced_length
)
Alloced_length
=
(
uint32
)
(
str
.
Alloced_length
-
offset
);
}
LEX_CSTRING
to_lex_cstring
()
const
{
LEX_CSTRING
tmp
=
{
Ptr
,
str_length
};
return
tmp
;
}
inline
LEX_CSTRING
*
get_value
(
LEX_CSTRING
*
res
)
{
res
->
str
=
Ptr
;
...
...
sql/sql_type_fixedbin.h
0 → 100644
View file @
0e8544cd
#ifndef SQL_TYPE_FIXEDBIN_H
#define SQL_TYPE_FIXEDBIN_H
/* Copyright (c) 2019,2021 MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/*
This is a common code for plugin (?) types that are generally
handled like strings, but have their own fixed size on-disk binary storage
format and their own (variable size) canonical string representation.
Examples are INET6 and UUID types.
*/
#define MYSQL_SERVER
#include "sql_class.h" // THD, SORT_FIELD_ATTR
#include "opt_range.h" // SEL_ARG, null_element
#include "sql_type_fixedbin_storage.h"
/***********************************************************************/
template
<
class
FbtImpl
>
class
FixedBinTypeBundle
{
public:
class
Fbt
:
public
FbtImpl
{
protected:
using
FbtImpl
::
m_buffer
;
bool
make_from_item
(
Item
*
item
,
bool
warn
)
{
if
(
item
->
type_handler
()
==
type_handler_fbt
())
{
Native
tmp
(
m_buffer
,
sizeof
(
m_buffer
));
bool
rc
=
item
->
val_native
(
current_thd
,
&
tmp
);
if
(
rc
)
return
true
;
DBUG_ASSERT
(
tmp
.
length
()
==
sizeof
(
m_buffer
));
if
(
tmp
.
ptr
()
!=
m_buffer
)
memcpy
(
m_buffer
,
tmp
.
ptr
(),
sizeof
(
m_buffer
));
return
false
;
}
StringBuffer
<
FbtImpl
::
max_char_length
()
+
1
>
tmp
;
String
*
str
=
item
->
val_str
(
&
tmp
);
return
str
?
make_from_character_or_binary_string
(
str
,
warn
)
:
true
;
}
bool
character_string_to_fbt
(
const
char
*
str
,
size_t
str_length
,
CHARSET_INFO
*
cs
)
{
if
(
cs
->
state
&
MY_CS_NONASCII
)
{
char
tmp
[
FbtImpl
::
max_char_length
()
+
1
];
String_copier
copier
;
uint
length
=
copier
.
well_formed_copy
(
&
my_charset_latin1
,
tmp
,
sizeof
(
tmp
),
cs
,
str
,
str_length
);
return
FbtImpl
::
ascii_to_fbt
(
tmp
,
length
);
}
return
FbtImpl
::
ascii_to_fbt
(
str
,
str_length
);
}
bool
make_from_character_or_binary_string
(
const
String
*
str
,
bool
warn
)
{
if
(
str
->
charset
()
!=
&
my_charset_bin
)
{
bool
rc
=
character_string_to_fbt
(
str
->
ptr
(),
str
->
length
(),
str
->
charset
());
if
(
rc
&&
warn
)
current_thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
type_handler_fbt
()
->
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
return
rc
;
}
if
(
str
->
length
()
!=
sizeof
(
m_buffer
))
{
if
(
warn
)
current_thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
type_handler_fbt
()
->
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
return
true
;
}
DBUG_ASSERT
(
str
->
ptr
()
!=
m_buffer
);
memcpy
(
m_buffer
,
str
->
ptr
(),
sizeof
(
m_buffer
));
return
false
;
}
bool
binary_to_fbt
(
const
char
*
str
,
size_t
length
)
{
if
(
length
!=
sizeof
(
m_buffer
))
return
true
;
memcpy
(
m_buffer
,
str
,
length
);
return
false
;
}
Fbt
()
{
}
public:
static
Fbt
zero
()
{
Fbt
fbt
;
fbt
.
set_zero
();
return
fbt
;
}
static
Fbt
record_to_memory
(
const
char
*
ptr
)
{
Fbt
fbt
;
FbtImpl
::
record_to_memory
(
fbt
.
m_buffer
,
ptr
);
return
fbt
;
}
/*
Check at Item's fix_fields() time if "item" can return a nullable value
on conversion to Fbt, or conversion produces a NOT NULL Fbt value.
*/
static
bool
fix_fields_maybe_null_on_conversion_to_fbt
(
Item
*
item
)
{
if
(
item
->
maybe_null
())
return
true
;
if
(
item
->
type_handler
()
==
type_handler_fbt
())
return
false
;
if
(
!
item
->
const_item
()
||
item
->
is_expensive
())
return
true
;
return
Fbt_null
(
item
,
false
).
is_null
();
}
public:
Fbt
(
Item
*
item
,
bool
*
error
,
bool
warn
=
true
)
{
*
error
=
make_from_item
(
item
,
warn
);
}
void
to_record
(
char
*
str
,
size_t
str_size
)
const
{
DBUG_ASSERT
(
str_size
>=
sizeof
(
m_buffer
));
FbtImpl
::
memory_to_record
(
str
,
m_buffer
);
}
bool
to_binary
(
String
*
to
)
const
{
return
to
->
copy
(
m_buffer
,
sizeof
(
m_buffer
),
&
my_charset_bin
);
}
bool
to_native
(
Native
*
to
)
const
{
return
to
->
copy
(
m_buffer
,
sizeof
(
m_buffer
));
}
bool
to_string
(
String
*
to
)
const
{
to
->
set_charset
(
&
my_charset_latin1
);
if
(
to
->
alloc
(
FbtImpl
::
max_char_length
()
+
1
))
return
true
;
to
->
length
((
uint32
)
FbtImpl
::
to_string
(
const_cast
<
char
*>
(
to
->
ptr
()),
FbtImpl
::
max_char_length
()
+
1
));
return
false
;
}
int
cmp
(
const
Binary_string
&
other
)
const
{
return
FbtImpl
::
cmp
(
FbtImpl
::
to_lex_cstring
(),
other
.
to_lex_cstring
());
}
int
cmp
(
const
Fbt
&
other
)
const
{
return
FbtImpl
::
cmp
(
FbtImpl
::
to_lex_cstring
(),
other
.
to_lex_cstring
());
}
};
class
Fbt_null
:
public
Fbt
,
public
Null_flag
{
public:
// Initialize from a text representation
Fbt_null
(
const
char
*
str
,
size_t
length
,
CHARSET_INFO
*
cs
)
:
Null_flag
(
Fbt
::
character_string_to_fbt
(
str
,
length
,
cs
))
{
}
Fbt_null
(
const
String
&
str
)
:
Fbt_null
(
str
.
ptr
(),
str
.
length
(),
str
.
charset
())
{
}
// Initialize from a binary representation
Fbt_null
(
const
char
*
str
,
size_t
length
)
:
Null_flag
(
Fbt
::
binary_to_fbt
(
str
,
length
))
{
}
Fbt_null
(
const
Binary_string
&
str
)
:
Fbt_null
(
str
.
ptr
(),
str
.
length
())
{
}
// Initialize from an Item
Fbt_null
(
Item
*
item
,
bool
warn
=
true
)
:
Null_flag
(
Fbt
::
make_from_item
(
item
,
warn
))
{
}
public:
const
Fbt
&
to_fbt
()
const
{
DBUG_ASSERT
(
!
is_null
());
return
*
this
;
}
void
to_record
(
char
*
str
,
size_t
str_size
)
const
{
to_fbt
().
to_record
(
str
,
str_size
);
}
bool
to_binary
(
String
*
to
)
const
{
return
to_fbt
().
to_binary
(
to
);
}
size_t
to_string
(
char
*
dst
,
size_t
dstsize
)
const
{
return
to_fbt
().
to_string
(
dst
,
dstsize
);
}
bool
to_string
(
String
*
to
)
const
{
return
to_fbt
().
to_string
(
to
);
}
};
class
Type_std_attributes_fbt
:
public
Type_std_attributes
{
public:
Type_std_attributes_fbt
()
:
Type_std_attributes
(
Type_numeric_attributes
(
FbtImpl
::
max_char_length
(),
0
,
true
),
DTCollation_numeric
())
{
}
};
class
Type_handler_fbt
:
public
Type_handler
{
bool
character_or_binary_string_to_native
(
THD
*
thd
,
const
String
*
str
,
Native
*
to
)
const
{
if
(
str
->
charset
()
==
&
my_charset_bin
)
{
// Convert from a binary string
if
(
str
->
length
()
!=
FbtImpl
::
binary_length
()
||
to
->
copy
(
str
->
ptr
(),
str
->
length
()))
{
thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
return
true
;
}
return
false
;
}
// Convert from a character string
Fbt_null
tmp
(
*
str
);
if
(
tmp
.
is_null
())
thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
return
tmp
.
is_null
()
||
tmp
.
to_native
(
to
);
}
public:
~
Type_handler_fbt
()
override
{}
const
Type_collection
*
type_collection
()
const
override
{
static
Type_collection_fbt
type_collection_fbt
;
return
&
type_collection_fbt
;
}
const
Name
&
default_value
()
const
override
{
return
FbtImpl
::
default_value
();
}
ulong
KEY_pack_flags
(
uint
column_nr
)
const
override
{
return
FbtImpl
::
KEY_pack_flags
(
column_nr
);
}
protocol_send_type_t
protocol_send_type
()
const
override
{
return
PROTOCOL_SEND_STRING
;
}
bool
Item_append_extended_type_info
(
Send_field_extended_metadata
*
to
,
const
Item
*
item
)
const
override
{
return
to
->
set_data_type_name
(
name
().
lex_cstring
());
}
enum_field_types
field_type
()
const
override
{
return
MYSQL_TYPE_STRING
;
}
Item_result
result_type
()
const
override
{
return
STRING_RESULT
;
}
Item_result
cmp_type
()
const
override
{
return
STRING_RESULT
;
}
enum_dynamic_column_type
dyncol_type
(
const
Type_all_attributes
*
attr
)
const
override
{
return
DYN_COL_STRING
;
}
uint32
max_display_length_for_field
(
const
Conv_source
&
src
)
const
override
{
return
FbtImpl
::
max_char_length
();
}
const
Type_handler
*
type_handler_for_comparison
()
const
override
{
return
this
;
}
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
override
{
DBUG_ASSERT
(
field
->
type_handler
()
==
this
);
Fbt_null
ni
(
item
);
// Convert Item to Fbt
if
(
ni
.
is_null
())
return
0
;
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
tmp
;
if
(
field
->
val_native
(
&
tmp
))
{
DBUG_ASSERT
(
0
);
return
0
;
}
return
-
ni
.
cmp
(
tmp
);
}
CHARSET_INFO
*
charset_for_protocol
(
const
Item
*
item
)
const
override
{
return
item
->
collation
.
collation
;
}
bool
is_scalar_type
()
const
override
{
return
true
;
}
bool
is_val_native_ready
()
const
override
{
return
true
;
}
bool
can_return_int
()
const
override
{
return
false
;
}
bool
can_return_decimal
()
const
override
{
return
false
;
}
bool
can_return_real
()
const
override
{
return
false
;
}
bool
can_return_str
()
const
override
{
return
true
;
}
bool
can_return_text
()
const
override
{
return
true
;
}
bool
can_return_date
()
const
override
{
return
false
;
}
bool
can_return_time
()
const
override
{
return
false
;
}
bool
convert_to_binary_using_val_native
()
const
override
{
return
true
;
}
decimal_digits_t
Item_time_precision
(
THD
*
thd
,
Item
*
item
)
const
override
{
return
0
;
}
decimal_digits_t
Item_datetime_precision
(
THD
*
thd
,
Item
*
item
)
const
override
{
return
0
;
}
decimal_digits_t
Item_decimal_scale
(
const
Item
*
item
)
const
override
{
return
0
;
}
decimal_digits_t
Item_decimal_precision
(
const
Item
*
item
)
const
override
{
/* This will be needed if we ever allow cast from Fbt to DECIMAL. */
return
(
FbtImpl
::
binary_length
()
*
8
+
7
)
/
10
*
3
;
// = bytes to decimal digits
}
/*
Returns how many digits a divisor adds into a division result.
See Item::divisor_precision_increment() in item.h for more comments.
*/
decimal_digits_t
Item_divisor_precision_increment
(
const
Item
*
)
const
override
{
return
0
;
}
/**
Makes a temporary table Field to handle numeric aggregate functions,
e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc.
*/
Field
*
make_num_distinct_aggregator_field
(
MEM_ROOT
*
,
const
Item
*
)
const
override
{
DBUG_ASSERT
(
0
);
return
0
;
}
Field
*
make_conversion_table_field
(
MEM_ROOT
*
root
,
TABLE
*
table
,
uint
metadata
,
const
Field
*
target
)
const
override
{
const
Record_addr
tmp
(
NULL
,
Bit_addr
(
true
));
return
new
(
table
->
in_use
->
mem_root
)
Field_fbt
(
&
empty_clex_str
,
tmp
);
}
// Fix attributes after the parser
bool
Column_definition_fix_attributes
(
Column_definition
*
c
)
const
override
{
c
->
length
=
FbtImpl
::
max_char_length
();
return
false
;
}
bool
Column_definition_prepare_stage1
(
THD
*
thd
,
MEM_ROOT
*
mem_root
,
Column_definition
*
def
,
handler
*
file
,
ulonglong
table_flags
,
const
Column_derived_attributes
*
derived_attr
)
const
override
{
def
->
prepare_stage1_simple
(
&
my_charset_numeric
);
return
false
;
}
bool
Column_definition_redefine_stage1
(
Column_definition
*
def
,
const
Column_definition
*
dup
,
const
handler
*
file
)
const
override
{
def
->
redefine_stage1_common
(
dup
,
file
);
def
->
set_compression_method
(
dup
->
compression_method
());
def
->
create_length_to_internal_length_string
();
return
false
;
}
bool
Column_definition_prepare_stage2
(
Column_definition
*
def
,
handler
*
file
,
ulonglong
table_flags
)
const
override
{
def
->
pack_flag
=
FIELDFLAG_BINARY
;
return
false
;
}
bool
partition_field_check
(
const
LEX_CSTRING
&
field_name
,
Item
*
item_expr
)
const
override
{
if
(
item_expr
->
cmp_type
()
!=
STRING_RESULT
)
{
my_error
(
ER_WRONG_TYPE_COLUMN_VALUE_ERROR
,
MYF
(
0
));
return
true
;
}
return
false
;
}
bool
partition_field_append_value
(
String
*
to
,
Item
*
item_expr
,
CHARSET_INFO
*
field_cs
,
partition_value_print_mode_t
mode
)
const
override
{
StringBuffer
<
FbtImpl
::
max_char_length
()
+
64
>
fbtstr
;
Fbt_null
fbt
(
item_expr
);
if
(
fbt
.
is_null
())
{
my_error
(
ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
,
MYF
(
0
));
return
true
;
}
return
fbt
.
to_string
(
&
fbtstr
)
||
to
->
append
(
'\''
)
||
to
->
append
(
fbtstr
)
||
to
->
append
(
'\''
);
}
Field
*
make_table_field
(
MEM_ROOT
*
root
,
const
LEX_CSTRING
*
name
,
const
Record_addr
&
addr
,
const
Type_all_attributes
&
attr
,
TABLE_SHARE
*
table
)
const
override
{
return
new
(
root
)
Field_fbt
(
name
,
addr
);
}
Field
*
make_table_field_from_def
(
TABLE_SHARE
*
share
,
MEM_ROOT
*
mem_root
,
const
LEX_CSTRING
*
name
,
const
Record_addr
&
addr
,
const
Bit_addr
&
bit
,
const
Column_definition_attributes
*
attr
,
uint32
flags
)
const
override
{
return
new
(
mem_root
)
Field_fbt
(
name
,
addr
);
}
void
Column_definition_attributes_frm_pack
(
const
Column_definition_attributes
*
def
,
uchar
*
buff
)
const
override
{
def
->
frm_pack_basic
(
buff
);
def
->
frm_pack_charset
(
buff
);
}
bool
Column_definition_attributes_frm_unpack
(
Column_definition_attributes
*
def
,
TABLE_SHARE
*
share
,
const
uchar
*
buffer
,
LEX_CUSTRING
*
gis_options
)
const
override
{
def
->
frm_unpack_basic
(
buffer
);
return
def
->
frm_unpack_charset
(
share
,
buffer
);
}
void
make_sort_key_part
(
uchar
*
to
,
Item
*
item
,
const
SORT_FIELD_ATTR
*
sort_field
,
Sort_param
*
param
)
const
override
{
DBUG_ASSERT
(
item
->
type_handler
()
==
this
);
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
tmp
;
item
->
val_native_result
(
current_thd
,
&
tmp
);
if
(
item
->
maybe_null
())
{
if
(
item
->
null_value
)
{
memset
(
to
,
0
,
FbtImpl
::
binary_length
()
+
1
);
return
;
}
*
to
++=
1
;
}
DBUG_ASSERT
(
!
item
->
null_value
);
DBUG_ASSERT
(
FbtImpl
::
binary_length
()
==
tmp
.
length
());
DBUG_ASSERT
(
FbtImpl
::
binary_length
()
==
sort_field
->
length
);
FbtImpl
::
memory_to_record
((
char
*
)
to
,
tmp
.
ptr
());
}
uint
make_packed_sort_key_part
(
uchar
*
to
,
Item
*
item
,
const
SORT_FIELD_ATTR
*
sort_field
,
Sort_param
*
param
)
const
override
{
DBUG_ASSERT
(
item
->
type_handler
()
==
this
);
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
tmp
;
item
->
val_native_result
(
current_thd
,
&
tmp
);
if
(
item
->
maybe_null
())
{
if
(
item
->
null_value
)
{
*
to
++=
0
;
return
0
;
}
*
to
++=
1
;
}
DBUG_ASSERT
(
!
item
->
null_value
);
DBUG_ASSERT
(
FbtImpl
::
binary_length
()
==
tmp
.
length
());
DBUG_ASSERT
(
FbtImpl
::
binary_length
()
==
sort_field
->
length
);
FbtImpl
::
memory_to_record
((
char
*
)
to
,
tmp
.
ptr
());
return
tmp
.
length
();
}
void
sort_length
(
THD
*
thd
,
const
Type_std_attributes
*
item
,
SORT_FIELD_ATTR
*
attr
)
const
override
{
attr
->
original_length
=
attr
->
length
=
FbtImpl
::
binary_length
();
attr
->
suffix_length
=
0
;
}
uint32
max_display_length
(
const
Item
*
item
)
const
override
{
return
FbtImpl
::
max_char_length
();
}
uint32
calc_pack_length
(
uint32
length
)
const
override
{
return
FbtImpl
::
binary_length
();
}
void
Item_update_null_value
(
Item
*
item
)
const
override
{
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
tmp
;
item
->
val_native
(
current_thd
,
&
tmp
);
}
bool
Item_save_in_value
(
THD
*
thd
,
Item
*
item
,
st_value
*
value
)
const
override
{
value
->
m_type
=
DYN_COL_STRING
;
String
*
str
=
item
->
val_str
(
&
value
->
m_string
);
if
(
str
!=
&
value
->
m_string
&&
!
item
->
null_value
)
{
// "item" returned a non-NULL value
if
(
Fbt_null
(
*
str
).
is_null
())
{
/*
The value was not-null, but conversion to FBT failed:
SELECT a, DECODE_ORACLE(fbtcol, 'garbage', '<NULL>', '::01', '01')
FROM t1;
*/
thd
->
push_warning_wrong_value
(
Sql_condition
::
WARN_LEVEL_WARN
,
name
().
ptr
(),
ErrConvString
(
str
).
ptr
());
value
->
m_type
=
DYN_COL_NULL
;
return
true
;
}
// "item" returned a non-NULL value, and it was a valid FBT
value
->
m_string
.
set
(
str
->
ptr
(),
str
->
length
(),
str
->
charset
());
}
return
check_null
(
item
,
value
);
}
void
Item_param_setup_conversion
(
THD
*
thd
,
Item_param
*
param
)
const
override
{
param
->
setup_conversion_string
(
thd
,
thd
->
variables
.
character_set_client
);
}
void
Item_param_set_param_func
(
Item_param
*
param
,
uchar
**
pos
,
ulong
len
)
const
override
{
param
->
set_param_str
(
pos
,
len
);
}
bool
Item_param_set_from_value
(
THD
*
thd
,
Item_param
*
param
,
const
Type_all_attributes
*
attr
,
const
st_value
*
val
)
const
override
{
param
->
unsigned_flag
=
false
;
param
->
setup_conversion_string
(
thd
,
attr
->
collation
.
collation
);
/*
Exact value of max_length is not known unless fbt is converted to
charset of connection, so we have to set it later.
*/
return
param
->
set_str
(
val
->
m_string
.
ptr
(),
val
->
m_string
.
length
(),
attr
->
collation
.
collation
,
attr
->
collation
.
collation
);
}
bool
Item_param_val_native
(
THD
*
thd
,
Item_param
*
item
,
Native
*
to
)
const
override
{
StringBuffer
<
FbtImpl
::
max_char_length
()
+
1
>
buffer
;
String
*
str
=
item
->
val_str
(
&
buffer
);
if
(
!
str
)
return
true
;
Fbt_null
tmp
(
*
str
);
return
tmp
.
is_null
()
||
tmp
.
to_native
(
to
);
}
bool
Item_send
(
Item
*
item
,
Protocol
*
p
,
st_value
*
buf
)
const
override
{
return
Item_send_str
(
item
,
p
,
buf
);
}
int
Item_save_in_field
(
Item
*
item
,
Field
*
field
,
bool
no_conversions
)
const
override
{
if
(
field
->
type_handler
()
==
this
)
{
NativeBuffer
<
MAX_FIELD_WIDTH
>
tmp
;
bool
rc
=
item
->
val_native
(
current_thd
,
&
tmp
);
if
(
rc
||
item
->
null_value
)
return
set_field_to_null_with_conversions
(
field
,
no_conversions
);
field
->
set_notnull
();
return
field
->
store_native
(
tmp
);
}
return
item
->
save_str_in_field
(
field
,
no_conversions
);
}
String
*
print_item_value
(
THD
*
thd
,
Item
*
item
,
String
*
str
)
const
override
{
StringBuffer
<
FbtImpl
::
max_char_length
()
+
64
>
buf
;
String
*
result
=
item
->
val_str
(
&
buf
);
/*
TODO: This should eventually use one of these notations:
1. CAST('xxx' AS Fbt)
Problem: CAST is not supported as a NAME_CONST() argument.
2. Fbt'xxx'
Problem: This syntax is not supported by the parser yet.
*/
return
!
result
||
str
->
realloc
(
result
->
length
()
+
2
)
||
str
->
append
(
STRING_WITH_LEN
(
"'"
))
||
str
->
append
(
result
->
ptr
(),
result
->
length
())
||
str
->
append
(
STRING_WITH_LEN
(
"'"
))
?
nullptr
:
str
;
}
/**
Check if
WHERE expr=value AND expr=const
can be rewritten as:
WHERE const=value AND expr=const
"this" is the comparison handler that is used by "target".
@param target - the predicate expr=value,
whose "expr" argument will be replaced to "const".
@param target_expr - the target's "expr" which will be replaced to "const".
@param target_value - the target's second argument, it will remain unchanged.
@param source - the equality predicate expr=const (or expr<=>const)
that can be used to rewrite the "target" part
(under certain conditions, see the code).
@param source_expr - the source's "expr". It should be exactly equal to
the target's "expr" to make condition rewrite possible.
@param source_const - the source's "const" argument, it will be inserted
into "target" instead of "expr".
*/
bool
can_change_cond_ref_to_const
(
Item_bool_func2
*
target
,
Item
*
target_expr
,
Item
*
target_value
,
Item_bool_func2
*
source
,
Item
*
source_expr
,
Item
*
source_const
)
const
override
{
/*
WHERE COALESCE(col)='xxx' AND COALESCE(col)=CONCAT(a); -->
WHERE COALESCE(col)='xxx' AND 'xxx'=CONCAT(a);
*/
return
target
->
compare_type_handler
()
==
source
->
compare_type_handler
();
}
bool
subquery_type_allows_materialization
(
const
Item
*
inner
,
const
Item
*
outer
,
bool
)
const
override
{
/*
Example:
SELECT * FROM t1 WHERE a IN (SELECT col FROM t1 GROUP BY col);
Allow materialization only if the outer column is also FBT.
This can be changed for more relaxed rules in the future.
*/
DBUG_ASSERT
(
inner
->
type_handler
()
==
this
);
return
outer
->
type_handler
()
==
this
;
}
/**
Make a simple constant replacement item for a constant "src",
so the new item can futher be used for comparison with "cmp", e.g.:
src = cmp -> replacement = cmp
"this" is the type handler that is used to compare "src" and "cmp".
@param thd - current thread, for mem_root
@param src - The item that we want to replace. It's a const item,
but it can be complex enough to calculate on every row.
@param cmp - The src's comparand.
@retval - a pointer to the created replacement Item
@retval - NULL, if could not create a replacement (e.g. on EOM).
NULL is also returned for ROWs, because instead of replacing
a Item_row to a new Item_row, Type_handler_row just replaces
its elements.
*/
Item
*
make_const_item_for_comparison
(
THD
*
thd
,
Item
*
src
,
const
Item
*
cmp
)
const
override
{
Fbt_null
tmp
(
src
);
if
(
tmp
.
is_null
())
return
new
(
thd
->
mem_root
)
Item_null
(
thd
,
src
->
name
.
str
);
return
new
(
thd
->
mem_root
)
Item_literal_fbt
(
thd
,
tmp
);
}
Item_cache
*
Item_get_cache
(
THD
*
thd
,
const
Item
*
item
)
const
override
{
return
new
(
thd
->
mem_root
)
Item_cache_fbt
(
thd
);
}
Item
*
create_typecast_item
(
THD
*
thd
,
Item
*
item
,
const
Type_cast_attributes
&
attr
)
const
override
{
return
new
(
thd
->
mem_root
)
Item_typecast_fbt
(
thd
,
item
);
}
Item_copy
*
create_item_copy
(
THD
*
thd
,
Item
*
item
)
const
override
{
return
new
(
thd
->
mem_root
)
Item_copy_fbt
(
thd
,
item
);
}
int
cmp_native
(
const
Native
&
a
,
const
Native
&
b
)
const
override
{
return
FbtImpl
::
cmp
(
a
.
to_lex_cstring
(),
b
.
to_lex_cstring
());
}
bool
set_comparator_func
(
THD
*
thd
,
Arg_comparator
*
cmp
)
const
override
{
return
cmp
->
set_cmp_func_native
(
thd
);
}
bool
Item_const_eq
(
const
Item_const
*
a
,
const
Item_const
*
b
,
bool
binary_cmp
)
const
override
{
return
false
;
}
bool
Item_eq_value
(
THD
*
thd
,
const
Type_cmp_attributes
*
attr
,
Item
*
a
,
Item
*
b
)
const
override
{
Fbt_null
na
(
a
),
nb
(
b
);
return
!
na
.
is_null
()
&&
!
nb
.
is_null
()
&&
!
na
.
cmp
(
nb
);
}
bool
Item_hybrid_func_fix_attributes
(
THD
*
thd
,
const
LEX_CSTRING
&
name
,
Type_handler_hybrid_field_type
*
h
,
Type_all_attributes
*
attr
,
Item
**
items
,
uint
nitems
)
const
override
{
attr
->
Type_std_attributes
::
operator
=
(
Type_std_attributes_fbt
());
h
->
set_handler
(
this
);
/*
If some of the arguments cannot be safely converted to "FBT NOT NULL",
then mark the entire function nullability as NULL-able.
Otherwise, keep the generic nullability calculated by earlier stages:
- either by the most generic way in Item_func::fix_fields()
- or by Item_func_xxx::fix_length_and_dec() before the call of
Item_hybrid_func_fix_attributes()
IFNULL() is special. It does not need to test args[0].
*/
uint
first
=
dynamic_cast
<
Item_func_ifnull
*>
(
attr
)
?
1
:
0
;
for
(
uint
i
=
first
;
i
<
nitems
;
i
++
)
{
if
(
Fbt
::
fix_fields_maybe_null_on_conversion_to_fbt
(
items
[
i
]))
{
attr
->
set_type_maybe_null
(
true
);
break
;
}
}
return
false
;
}
bool
Item_func_min_max_fix_attributes
(
THD
*
thd
,
Item_func_min_max
*
func
,
Item
**
items
,
uint
nitems
)
const
override
{
return
Item_hybrid_func_fix_attributes
(
thd
,
func
->
func_name_cstring
(),
func
,
func
,
items
,
nitems
);
}
bool
Item_sum_hybrid_fix_length_and_dec
(
Item_sum_hybrid
*
func
)
const
override
{
func
->
Type_std_attributes
::
operator
=
(
Type_std_attributes_fbt
());
func
->
set_handler
(
this
);
return
false
;
}
bool
Item_sum_sum_fix_length_and_dec
(
Item_sum_sum
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_sum_avg_fix_length_and_dec
(
Item_sum_avg
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_sum_variance_fix_length_and_dec
(
Item_sum_variance
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_val_native_with_conversion
(
THD
*
thd
,
Item
*
item
,
Native
*
to
)
const
override
{
if
(
item
->
type_handler
()
==
this
)
return
item
->
val_native
(
thd
,
to
);
// No conversion needed
StringBuffer
<
FbtImpl
::
max_char_length
()
+
1
>
buffer
;
String
*
str
=
item
->
val_str
(
&
buffer
);
return
str
?
character_or_binary_string_to_native
(
thd
,
str
,
to
)
:
true
;
}
bool
Item_val_native_with_conversion_result
(
THD
*
thd
,
Item
*
item
,
Native
*
to
)
const
override
{
if
(
item
->
type_handler
()
==
this
)
return
item
->
val_native_result
(
thd
,
to
);
// No conversion needed
StringBuffer
<
FbtImpl
::
max_char_length
()
+
1
>
buffer
;
String
*
str
=
item
->
str_result
(
&
buffer
);
return
str
?
character_or_binary_string_to_native
(
thd
,
str
,
to
)
:
true
;
}
bool
Item_val_bool
(
Item
*
item
)
const
override
{
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
tmp
;
if
(
item
->
val_native
(
current_thd
,
&
tmp
))
return
false
;
return
!
Fbt
::
only_zero_bytes
(
tmp
.
ptr
(),
tmp
.
length
());
}
void
Item_get_date
(
THD
*
thd
,
Item
*
item
,
Temporal
::
Warn
*
buff
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
const
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
}
longlong
Item_val_int_signed_typecast
(
Item
*
item
)
const
override
{
DBUG_ASSERT
(
0
);
return
0
;
}
longlong
Item_val_int_unsigned_typecast
(
Item
*
item
)
const
override
{
DBUG_ASSERT
(
0
);
return
0
;
}
String
*
Item_func_hex_val_str_ascii
(
Item_func_hex
*
item
,
String
*
str
)
const
override
{
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
tmp
;
if
((
item
->
null_value
=
item
->
arguments
()[
0
]
->
val_native
(
current_thd
,
&
tmp
)))
return
nullptr
;
DBUG_ASSERT
(
tmp
.
length
()
==
FbtImpl
::
binary_length
());
if
(
str
->
set_hex
(
tmp
.
ptr
(),
tmp
.
length
()))
{
str
->
length
(
0
);
str
->
set_charset
(
item
->
collation
.
collation
);
}
return
str
;
}
String
*
Item_func_hybrid_field_type_val_str
(
Item_func_hybrid_field_type
*
item
,
String
*
str
)
const
override
{
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
native
;
if
(
item
->
val_native
(
current_thd
,
&
native
))
{
DBUG_ASSERT
(
item
->
null_value
);
return
nullptr
;
}
DBUG_ASSERT
(
native
.
length
()
==
FbtImpl
::
binary_length
());
Fbt_null
tmp
(
native
.
ptr
(),
native
.
length
());
return
tmp
.
is_null
()
||
tmp
.
to_string
(
str
)
?
nullptr
:
str
;
}
double
Item_func_hybrid_field_type_val_real
(
Item_func_hybrid_field_type
*
)
const
override
{
return
0
;
}
longlong
Item_func_hybrid_field_type_val_int
(
Item_func_hybrid_field_type
*
)
const
override
{
return
0
;
}
my_decimal
*
Item_func_hybrid_field_type_val_decimal
(
Item_func_hybrid_field_type
*
,
my_decimal
*
to
)
const
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
void
Item_func_hybrid_field_type_get_date
(
THD
*
,
Item_func_hybrid_field_type
*
,
Temporal
::
Warn
*
,
MYSQL_TIME
*
to
,
date_mode_t
fuzzydate
)
const
override
{
set_zero_time
(
to
,
MYSQL_TIMESTAMP_TIME
);
}
// WHERE is Item_func_min_max_val_native???
String
*
Item_func_min_max_val_str
(
Item_func_min_max
*
func
,
String
*
str
)
const
override
{
Fbt_null
tmp
(
func
);
return
tmp
.
is_null
()
||
tmp
.
to_string
(
str
)
?
nullptr
:
str
;
}
double
Item_func_min_max_val_real
(
Item_func_min_max
*
)
const
override
{
return
0
;
}
longlong
Item_func_min_max_val_int
(
Item_func_min_max
*
)
const
override
{
return
0
;
}
my_decimal
*
Item_func_min_max_val_decimal
(
Item_func_min_max
*
,
my_decimal
*
to
)
const
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
bool
Item_func_min_max_get_date
(
THD
*
thd
,
Item_func_min_max
*
,
MYSQL_TIME
*
to
,
date_mode_t
fuzzydate
)
const
override
{
set_zero_time
(
to
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
Item_func_between_fix_length_and_dec
(
Item_func_between
*
func
)
const
override
{
return
false
;
}
longlong
Item_func_between_val_int
(
Item_func_between
*
func
)
const
override
{
return
func
->
val_int_cmp_native
();
}
cmp_item
*
make_cmp_item
(
THD
*
thd
,
CHARSET_INFO
*
cs
)
const
override
{
return
new
(
thd
->
mem_root
)
cmp_item_fbt
;
}
in_vector
*
make_in_vector
(
THD
*
thd
,
const
Item_func_in
*
func
,
uint
nargs
)
const
override
{
return
new
(
thd
->
mem_root
)
in_fbt
(
thd
,
nargs
);
}
bool
Item_func_in_fix_comparator_compatible_types
(
THD
*
thd
,
Item_func_in
*
func
)
const
override
{
if
(
func
->
compatible_types_scalar_bisection_possible
())
{
return
func
->
value_list_convert_const_to_int
(
thd
)
||
func
->
fix_for_scalar_comparison_using_bisection
(
thd
);
}
return
func
->
fix_for_scalar_comparison_using_cmp_items
(
thd
,
1U
<<
(
uint
)
STRING_RESULT
);
}
bool
Item_func_round_fix_length_and_dec
(
Item_func_round
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_int_val_fix_length_and_dec
(
Item_func_int_val
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_abs_fix_length_and_dec
(
Item_func_abs
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_neg_fix_length_and_dec
(
Item_func_neg
*
func
)
const
override
{
return
Item_func_or_sum_illegal_param
(
func
);
}
bool
Item_func_signed_fix_length_and_dec
(
Item_func_signed
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_unsigned_fix_length_and_dec
(
Item_func_unsigned
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_double_typecast_fix_length_and_dec
(
Item_double_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_float_typecast_fix_length_and_dec
(
Item_float_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_decimal_typecast_fix_length_and_dec
(
Item_decimal_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_char_typecast_fix_length_and_dec
(
Item_char_typecast
*
item
)
const
override
{
if
(
item
->
cast_charset
()
==
&
my_charset_bin
)
{
static
Item_char_typecast_func_handler_fbt_to_binary
item_char_typecast_func_handler_fbt_to_binary
;
item
->
fix_length_and_dec_native_to_binary
(
FbtImpl
::
binary_length
());
item
->
set_func_handler
(
&
item_char_typecast_func_handler_fbt_to_binary
);
return
false
;
}
item
->
fix_length_and_dec_str
();
return
false
;
}
bool
Item_time_typecast_fix_length_and_dec
(
Item_time_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_date_typecast_fix_length_and_dec
(
Item_date_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_datetime_typecast_fix_length_and_dec
(
Item_datetime_typecast
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_plus_fix_length_and_dec
(
Item_func_plus
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_minus_fix_length_and_dec
(
Item_func_minus
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_mul_fix_length_and_dec
(
Item_func_mul
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_div_fix_length_and_dec
(
Item_func_div
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
bool
Item_func_mod_fix_length_and_dec
(
Item_func_mod
*
item
)
const
override
{
return
Item_func_or_sum_illegal_param
(
item
);
}
};
class
cmp_item_fbt
:
public
cmp_item_scalar
{
Fbt
m_native
;
public:
cmp_item_fbt
()
:
cmp_item_scalar
(),
m_native
(
Fbt
::
zero
())
{
}
void
store_value
(
Item
*
item
)
override
{
m_native
=
Fbt
(
item
,
&
m_null_value
);
}
int
cmp_not_null
(
const
Value
*
val
)
override
{
DBUG_ASSERT
(
!
val
->
is_null
());
DBUG_ASSERT
(
val
->
is_string
());
Fbt_null
tmp
(
val
->
m_string
);
DBUG_ASSERT
(
!
tmp
.
is_null
());
return
m_native
.
cmp
(
tmp
);
}
int
cmp
(
Item
*
arg
)
override
{
Fbt_null
tmp
(
arg
);
return
m_null_value
||
tmp
.
is_null
()
?
UNKNOWN
:
m_native
.
cmp
(
tmp
)
!=
0
;
}
int
compare
(
cmp_item
*
ci
)
override
{
cmp_item_fbt
*
tmp
=
static_cast
<
cmp_item_fbt
*>
(
ci
);
DBUG_ASSERT
(
!
m_null_value
);
DBUG_ASSERT
(
!
tmp
->
m_null_value
);
return
m_native
.
cmp
(
tmp
->
m_native
);
}
cmp_item
*
make_same
(
THD
*
thd
)
override
{
return
new
(
thd
->
mem_root
)
cmp_item_fbt
();
}
};
class
Field_fbt
:
public
Field
{
static
void
set_min_value
(
char
*
ptr
)
{
memset
(
ptr
,
0
,
FbtImpl
::
binary_length
());
}
static
void
set_max_value
(
char
*
ptr
)
{
memset
(
ptr
,
0xFF
,
FbtImpl
::
binary_length
());
}
void
store_warning
(
const
ErrConv
&
str
,
Sql_condition
::
enum_warning_level
level
)
{
if
(
get_thd
()
->
count_cuted_fields
<=
CHECK_FIELD_EXPRESSION
)
return
;
const
TABLE_SHARE
*
s
=
table
->
s
;
static
const
Name
type_name
=
type_handler_fbt
()
->
name
();
get_thd
()
->
push_warning_truncated_value_for_field
(
level
,
type_name
.
ptr
(),
str
.
ptr
(),
s
?
s
->
db
.
str
:
nullptr
,
s
?
s
->
table_name
.
str
:
nullptr
,
field_name
.
str
);
}
int
set_null_with_warn
(
const
ErrConv
&
str
)
{
store_warning
(
str
,
Sql_condition
::
WARN_LEVEL_WARN
);
set_null
();
return
1
;
}
int
set_min_value_with_warn
(
const
ErrConv
&
str
)
{
store_warning
(
str
,
Sql_condition
::
WARN_LEVEL_WARN
);
set_min_value
((
char
*
)
ptr
);
return
1
;
}
int
set_max_value_with_warn
(
const
ErrConv
&
str
)
{
store_warning
(
str
,
Sql_condition
::
WARN_LEVEL_WARN
);
set_max_value
((
char
*
)
ptr
);
return
1
;
}
int
store_fbt_null_with_warn
(
const
Fbt_null
&
fbt
,
const
ErrConvString
&
err
)
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
if
(
fbt
.
is_null
())
return
maybe_null
()
?
set_null_with_warn
(
err
)
:
set_min_value_with_warn
(
err
);
fbt
.
to_record
((
char
*
)
ptr
,
FbtImpl
::
binary_length
());
return
0
;
}
public:
Field_fbt
(
const
LEX_CSTRING
*
field_name_arg
,
const
Record_addr
&
rec
)
:
Field
(
rec
.
ptr
(),
FbtImpl
::
max_char_length
(),
rec
.
null_ptr
(),
rec
.
null_bit
(),
Field
::
NONE
,
field_name_arg
)
{
flags
|=
BINARY_FLAG
|
UNSIGNED_FLAG
;
}
const
Type_handler
*
type_handler
()
const
override
{
return
type_handler_fbt
();
}
uint32
max_display_length
()
const
override
{
return
field_length
;
}
bool
str_needs_quotes
()
const
override
{
return
true
;
}
const
DTCollation
&
dtcollation
()
const
override
{
static
DTCollation_numeric
c
;
return
c
;
}
CHARSET_INFO
*
charset
(
void
)
const
override
{
return
&
my_charset_numeric
;
}
const
CHARSET_INFO
*
sort_charset
(
void
)
const
override
{
return
&
my_charset_bin
;
}
/**
This makes client-server protocol convert the value according
to @@character_set_client.
*/
bool
binary
()
const
override
{
return
false
;
}
enum
ha_base_keytype
key_type
()
const
override
{
return
HA_KEYTYPE_BINARY
;
}
bool
is_equal
(
const
Column_definition
&
new_field
)
const
override
{
return
new_field
.
type_handler
()
==
type_handler
();
}
bool
eq_def
(
const
Field
*
field
)
const
override
{
return
Field
::
eq_def
(
field
);
}
double
pos_in_interval
(
Field
*
min
,
Field
*
max
)
override
{
return
pos_in_interval_val_str
(
min
,
max
,
0
);
}
int
cmp
(
const
uchar
*
a
,
const
uchar
*
b
)
const
override
{
return
memcmp
(
a
,
b
,
pack_length
());
}
void
sort_string
(
uchar
*
to
,
uint
length
)
override
{
DBUG_ASSERT
(
length
==
pack_length
());
memcpy
(
to
,
ptr
,
length
);
}
uint32
pack_length
()
const
override
{
return
FbtImpl
::
binary_length
();
}
uint
pack_length_from_metadata
(
uint
field_metadata
)
const
override
{
return
FbtImpl
::
binary_length
();
}
void
sql_type
(
String
&
str
)
const
override
{
static
Name
name
=
type_handler_fbt
()
->
name
();
str
.
set_ascii
(
name
.
ptr
(),
name
.
length
());
}
void
make_send_field
(
Send_field
*
to
)
override
{
Field
::
make_send_field
(
to
);
to
->
set_data_type_name
(
type_handler_fbt
()
->
name
().
lex_cstring
());
}
bool
validate_value_in_record
(
THD
*
thd
,
const
uchar
*
record
)
const
override
{
return
false
;
}
bool
val_native
(
Native
*
to
)
override
{
DBUG_ASSERT
(
marked_for_read
());
if
(
to
->
alloc
(
FbtImpl
::
binary_length
()))
return
true
;
to
->
length
(
FbtImpl
::
binary_length
());
FbtImpl
::
record_to_memory
((
char
*
)
to
->
ptr
(),
(
const
char
*
)
ptr
);
return
false
;
}
Fbt
to_fbt
()
const
{
DBUG_ASSERT
(
marked_for_read
());
return
Fbt
::
record_to_memory
((
const
char
*
)
ptr
);
}
String
*
val_str
(
String
*
val_buffer
,
String
*
)
override
{
return
to_fbt
().
to_string
(
val_buffer
)
?
NULL
:
val_buffer
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
DBUG_ASSERT
(
marked_for_read
());
my_decimal_set_zero
(
to
);
return
to
;
}
longlong
val_int
()
override
{
DBUG_ASSERT
(
marked_for_read
());
return
0
;
}
double
val_real
()
override
{
DBUG_ASSERT
(
marked_for_read
());
return
0
;
}
bool
get_date
(
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
DBUG_ASSERT
(
marked_for_read
());
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_bool
(
void
)
override
{
DBUG_ASSERT
(
marked_for_read
());
return
!
Fbt
::
only_zero_bytes
((
const
char
*
)
ptr
,
FbtImpl
::
binary_length
());
}
int
store_native
(
const
Native
&
value
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
DBUG_ASSERT
(
value
.
length
()
==
FbtImpl
::
binary_length
());
FbtImpl
::
memory_to_record
((
char
*
)
ptr
,
value
.
ptr
());
return
0
;
}
int
store
(
const
char
*
str
,
size_t
length
,
CHARSET_INFO
*
cs
)
override
{
return
cs
==
&
my_charset_bin
?
store_binary
(
str
,
length
)
:
store_text
(
str
,
length
,
cs
);
}
int
store_text
(
const
char
*
str
,
size_t
length
,
CHARSET_INFO
*
cs
)
override
{
return
store_fbt_null_with_warn
(
Fbt_null
(
str
,
length
,
cs
),
ErrConvString
(
str
,
length
,
cs
));
}
int
store_binary
(
const
char
*
str
,
size_t
length
)
override
{
return
store_fbt_null_with_warn
(
Fbt_null
(
str
,
length
),
ErrConvString
(
str
,
length
,
&
my_charset_bin
));
}
int
store_hex_hybrid
(
const
char
*
str
,
size_t
length
)
override
{
return
Field_fbt
::
store_binary
(
str
,
length
);
}
int
store_decimal
(
const
my_decimal
*
num
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvDecimal
(
num
));
}
int
store
(
longlong
nr
,
bool
unsigned_flag
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvInteger
(
Longlong_hybrid
(
nr
,
unsigned_flag
)));
}
int
store
(
double
nr
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvDouble
(
nr
));
}
int
store_time_dec
(
const
MYSQL_TIME
*
ltime
,
uint
dec
)
override
{
DBUG_ASSERT
(
marked_for_write_or_computed
());
return
set_min_value_with_warn
(
ErrConvTime
(
ltime
));
}
/*** Field conversion routines ***/
int
store_field
(
Field
*
from
)
override
{
// INSERT INTO t1 (fbt_field) SELECT different_field_type FROM t2;
return
from
->
save_in_field
(
this
);
}
int
save_in_field
(
Field
*
to
)
override
{
// INSERT INTO t2 (different_field_type) SELECT fbt_field FROM t1;
if
(
to
->
charset
()
==
&
my_charset_bin
&&
dynamic_cast
<
const
Type_handler_general_purpose_string
*>
(
to
->
type_handler
()))
{
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
res
;
val_native
(
&
res
);
return
to
->
store
(
res
.
ptr
(),
res
.
length
(),
&
my_charset_bin
);
}
return
save_in_field_str
(
to
);
}
Copy_func
*
get_copy_func
(
const
Field
*
from
)
const
override
{
// ALTER to FBT from another field
return
do_field_string
;
}
Copy_func
*
get_copy_func_to
(
const
Field
*
to
)
const
override
{
if
(
type_handler
()
==
to
->
type_handler
())
{
// ALTER from FBT to FBT
DBUG_ASSERT
(
pack_length
()
==
to
->
pack_length
());
DBUG_ASSERT
(
charset
()
==
to
->
charset
());
DBUG_ASSERT
(
sort_charset
()
==
to
->
sort_charset
());
return
Field
::
do_field_eq
;
}
// ALTER from FBT to another fbt type
if
(
to
->
charset
()
==
&
my_charset_bin
&&
dynamic_cast
<
const
Type_handler_general_purpose_string
*>
(
to
->
type_handler
()))
{
/*
ALTER from FBT to a binary string type, e.g.:
BINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
*/
return
do_field_fbt_native_to_binary
;
}
return
do_field_string
;
}
static
void
do_field_fbt_native_to_binary
(
Copy_field
*
copy
)
{
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
res
;
copy
->
from_field
->
val_native
(
&
res
);
copy
->
to_field
->
store
(
res
.
ptr
(),
res
.
length
(),
&
my_charset_bin
);
}
bool
memcpy_field_possible
(
const
Field
*
from
)
const
override
{
// INSERT INTO t1 (fbt_field) SELECT field2 FROM t2;
return
type_handler
()
==
from
->
type_handler
();
}
enum_conv_type
rpl_conv_type_from
(
const
Conv_source
&
source
,
const
Relay_log_info
*
rli
,
const
Conv_param
&
param
)
const
override
{
if
(
type_handler
()
==
source
.
type_handler
()
||
(
source
.
type_handler
()
==
&
type_handler_string
&&
source
.
type_handler
()
->
max_display_length_for_field
(
source
)
==
FbtImpl
::
binary_length
()))
return
rpl_conv_type_from_same_data_type
(
source
.
metadata
(),
rli
,
param
);
return
CONV_TYPE_IMPOSSIBLE
;
}
/*** Optimizer routines ***/
bool
test_if_equality_guarantees_uniqueness
(
const
Item
*
const_item
)
const
override
{
/*
This condition:
WHERE fbt_field=const
should return a single distinct value only,
as comparison is done according to FBT.
*/
return
true
;
}
bool
can_be_substituted_to_equal_item
(
const
Context
&
ctx
,
const
Item_equal
*
item_equal
)
override
{
switch
(
ctx
.
subst_constraint
())
{
case
ANY_SUBST
:
return
ctx
.
compare_type_handler
()
==
item_equal
->
compare_type_handler
();
case
IDENTITY_SUBST
:
return
true
;
}
return
false
;
}
Item
*
get_equal_const_item
(
THD
*
thd
,
const
Context
&
ctx
,
Item
*
const_item
)
override
{
Fbt_null
tmp
(
const_item
);
if
(
tmp
.
is_null
())
return
NULL
;
return
new
(
thd
->
mem_root
)
Item_literal_fbt
(
thd
,
tmp
);
}
bool
can_optimize_keypart_ref
(
const
Item_bool_func
*
cond
,
const
Item
*
item
)
const
override
{
/*
Mixing of two different non-traditional types is currently prevented.
This may change in the future.
*/
DBUG_ASSERT
(
item
->
type_handler
()
->
type_handler_base_or_self
()
->
is_traditional_scalar_type
()
||
item
->
type_handler
()
==
type_handler
());
return
true
;
}
/**
Test if Field can use range optimizer for a standard comparison operation:
<=, <, =, <=>, >, >=
Note, this method does not cover spatial operations.
*/
bool
can_optimize_range
(
const
Item_bool_func
*
cond
,
const
Item
*
item
,
bool
is_eq_func
)
const
override
{
// See the DBUG_ASSERT comment in can_optimize_keypart_ref()
DBUG_ASSERT
(
item
->
type_handler
()
->
type_handler_base_or_self
()
->
is_traditional_scalar_type
()
||
item
->
type_handler
()
==
type_handler
());
return
true
;
}
void
hash
(
ulong
*
nr
,
ulong
*
nr2
)
override
{
if
(
is_null
())
*
nr
^=
(
*
nr
<<
1
)
|
1
;
else
FbtImpl
::
hash_record
(
ptr
,
nr
,
nr2
);
}
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
prm
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
override
{
DBUG_ENTER
(
"Field_fbt::get_mm_leaf"
);
if
(
!
can_optimize_scalar_range
(
prm
,
key_part
,
cond
,
op
,
value
))
DBUG_RETURN
(
0
);
int
err
=
value
->
save_in_field_no_warnings
(
this
,
1
);
if
((
op
!=
SCALAR_CMP_EQUAL
&&
is_real_null
())
||
err
<
0
)
DBUG_RETURN
(
&
null_element
);
if
(
err
>
0
)
{
if
(
op
==
SCALAR_CMP_EQ
||
op
==
SCALAR_CMP_EQUAL
)
DBUG_RETURN
(
new
(
prm
->
mem_root
)
SEL_ARG_IMPOSSIBLE
(
this
));
DBUG_RETURN
(
NULL
);
/* Cannot infer anything */
}
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
}
bool
can_optimize_hash_join
(
const
Item_bool_func
*
cond
,
const
Item
*
item
)
const
override
{
return
can_optimize_keypart_ref
(
cond
,
item
);
}
bool
can_optimize_group_min_max
(
const
Item_bool_func
*
cond
,
const
Item
*
const_item
)
const
override
{
return
true
;
}
uint
row_pack_length
()
const
override
{
return
pack_length
();
}
Binlog_type_info
binlog_type_info
()
const
override
{
DBUG_ASSERT
(
type
()
==
binlog_type
());
return
Binlog_type_info_fixed_string
(
Field_fbt
::
binlog_type
(),
FbtImpl
::
binary_length
(),
&
my_charset_bin
);
}
uchar
*
pack
(
uchar
*
to
,
const
uchar
*
from
,
uint
max_length
)
override
{
DBUG_PRINT
(
"debug"
,
(
"Packing field '%s'"
,
field_name
.
str
));
return
FbtImpl
::
pack
(
to
,
from
,
max_length
);
}
const
uchar
*
unpack
(
uchar
*
to
,
const
uchar
*
from
,
const
uchar
*
from_end
,
uint
param_data
)
override
{
return
FbtImpl
::
unpack
(
to
,
from
,
from_end
,
param_data
);
}
uint
max_packed_col_length
(
uint
max_length
)
override
{
return
StringPack
::
max_packed_col_length
(
max_length
);
}
uint
packed_col_length
(
const
uchar
*
fbt_ptr
,
uint
length
)
override
{
return
StringPack
::
packed_col_length
(
fbt_ptr
,
length
);
}
uint
size_of
()
const
override
{
return
sizeof
(
*
this
);
}
};
class
Item_typecast_fbt
:
public
Item_func
{
public:
Item_typecast_fbt
(
THD
*
thd
,
Item
*
a
)
:
Item_func
(
thd
,
a
)
{}
const
Type_handler
*
type_handler
()
const
override
{
return
type_handler_fbt
();
}
enum
Functype
functype
()
const
override
{
return
CHAR_TYPECAST_FUNC
;
}
bool
eq
(
const
Item
*
item
,
bool
binary_cmp
)
const
override
{
if
(
this
==
item
)
return
true
;
if
(
item
->
type
()
!=
FUNC_ITEM
||
functype
()
!=
((
Item_func
*
)
item
)
->
functype
())
return
false
;
if
(
type_handler
()
!=
item
->
type_handler
())
return
false
;
Item_typecast_fbt
*
cast
=
(
Item_typecast_fbt
*
)
item
;
return
args
[
0
]
->
eq
(
cast
->
args
[
0
],
binary_cmp
);
}
LEX_CSTRING
func_name_cstring
()
const
override
{
static
Name
name
=
type_handler_fbt
()
->
name
();
size_t
len
=
9
+
name
.
length
()
+
1
;
char
*
buf
=
(
char
*
)
current_thd
->
alloc
(
len
);
strmov
(
strmov
(
buf
,
"cast_as_"
),
name
.
ptr
());
return
{
buf
,
len
};
}
void
print
(
String
*
str
,
enum_query_type
query_type
)
override
{
str
->
append
(
STRING_WITH_LEN
(
"cast("
));
args
[
0
]
->
print
(
str
,
query_type
);
str
->
append
(
STRING_WITH_LEN
(
" as "
));
str
->
append
(
type_handler_fbt
()
->
name
().
lex_cstring
());
str
->
append
(
')'
);
}
bool
fix_length_and_dec
()
override
{
Type_std_attributes
::
operator
=
(
Type_std_attributes_fbt
());
if
(
Fbt
::
fix_fields_maybe_null_on_conversion_to_fbt
(
args
[
0
]))
set_maybe_null
();
return
false
;
}
String
*
val_str
(
String
*
to
)
override
{
Fbt_null
tmp
(
args
[
0
]);
return
(
null_value
=
tmp
.
is_null
()
||
tmp
.
to_string
(
to
))
?
NULL
:
to
;
}
longlong
val_int
()
override
{
return
0
;
}
double
val_real
()
override
{
return
0
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
override
{
Fbt_null
tmp
(
args
[
0
]);
return
null_value
=
tmp
.
is_null
()
||
tmp
.
to_native
(
to
);
}
Item
*
get_copy
(
THD
*
thd
)
override
{
return
get_item_copy
<
Item_typecast_fbt
>
(
thd
,
this
);
}
};
class
Item_cache_fbt
:
public
Item_cache
{
NativeBuffer
<
FbtImpl
::
binary_length
()
+
1
>
m_value
;
public:
Item_cache_fbt
(
THD
*
thd
)
:
Item_cache
(
thd
,
type_handler_fbt
())
{
}
Item
*
get_copy
(
THD
*
thd
)
{
return
get_item_copy
<
Item_cache_fbt
>
(
thd
,
this
);
}
bool
cache_value
()
{
if
(
!
example
)
return
false
;
value_cached
=
true
;
null_value_inside
=
null_value
=
example
->
val_native_with_conversion_result
(
current_thd
,
&
m_value
,
type_handler
());
return
true
;
}
String
*
val_str
(
String
*
to
)
{
if
(
!
has_value
())
return
NULL
;
Fbt_null
tmp
(
m_value
.
ptr
(),
m_value
.
length
());
return
tmp
.
is_null
()
||
tmp
.
to_string
(
to
)
?
NULL
:
to
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
{
if
(
!
has_value
())
return
NULL
;
my_decimal_set_zero
(
to
);
return
to
;
}
longlong
val_int
()
{
if
(
!
has_value
())
return
0
;
return
0
;
}
double
val_real
()
{
if
(
!
has_value
())
return
0
;
return
0
;
}
longlong
val_datetime_packed
(
THD
*
thd
)
{
DBUG_ASSERT
(
0
);
if
(
!
has_value
())
return
0
;
return
0
;
}
longlong
val_time_packed
(
THD
*
thd
)
{
DBUG_ASSERT
(
0
);
if
(
!
has_value
())
return
0
;
return
0
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
{
if
(
!
has_value
())
return
true
;
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
{
if
(
!
has_value
())
return
true
;
return
to
->
copy
(
m_value
.
ptr
(),
m_value
.
length
());
}
};
class
Item_literal_fbt
:
public
Item_literal
{
Fbt
m_value
;
public:
Item_literal_fbt
(
THD
*
thd
)
:
Item_literal
(
thd
),
m_value
(
Fbt
::
zero
())
{
}
Item_literal_fbt
(
THD
*
thd
,
const
Fbt
&
value
)
:
Item_literal
(
thd
),
m_value
(
value
)
{
}
const
Type_handler
*
type_handler
()
const
override
{
return
type_handler_fbt
();
}
longlong
val_int
()
override
{
return
0
;
}
double
val_real
()
override
{
return
0
;
}
String
*
val_str
(
String
*
to
)
override
{
return
m_value
.
to_string
(
to
)
?
NULL
:
to
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
false
;
}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
override
{
return
m_value
.
to_native
(
to
);
}
void
print
(
String
*
str
,
enum_query_type
query_type
)
override
{
StringBuffer
<
FbtImpl
::
max_char_length
()
+
64
>
tmp
;
tmp
.
append
(
type_handler_fbt
()
->
name
().
lex_cstring
());
my_caseup_str
(
&
my_charset_latin1
,
tmp
.
c_ptr
());
str
->
append
(
tmp
);
str
->
append
(
'\''
);
m_value
.
to_string
(
&
tmp
);
str
->
append
(
tmp
);
str
->
append
(
'\''
);
}
Item
*
get_copy
(
THD
*
thd
)
override
{
return
get_item_copy
<
Item_literal_fbt
>
(
thd
,
this
);
}
// Non-overriding methods
void
set_value
(
const
Fbt
&
value
)
{
m_value
=
value
;
}
};
class
Item_copy_fbt
:
public
Item_copy
{
NativeBuffer
<
Fbt
::
binary_length
()
+
1
>
m_value
;
public:
Item_copy_fbt
(
THD
*
thd
,
Item
*
item_arg
)
:
Item_copy
(
thd
,
item_arg
)
{}
bool
val_native
(
THD
*
thd
,
Native
*
to
)
override
{
if
(
null_value
)
return
true
;
return
to
->
copy
(
m_value
.
ptr
(),
m_value
.
length
());
}
String
*
val_str
(
String
*
to
)
override
{
if
(
null_value
)
return
NULL
;
Fbt_null
tmp
(
m_value
.
ptr
(),
m_value
.
length
());
return
tmp
.
is_null
()
||
tmp
.
to_string
(
to
)
?
NULL
:
to
;
}
my_decimal
*
val_decimal
(
my_decimal
*
to
)
override
{
my_decimal_set_zero
(
to
);
return
to
;
}
double
val_real
()
override
{
return
0
;
}
longlong
val_int
()
override
{
return
0
;
}
bool
get_date
(
THD
*
thd
,
MYSQL_TIME
*
ltime
,
date_mode_t
fuzzydate
)
override
{
set_zero_time
(
ltime
,
MYSQL_TIMESTAMP_TIME
);
return
null_value
;
}
void
copy
()
override
{
null_value
=
item
->
val_native
(
current_thd
,
&
m_value
);
DBUG_ASSERT
(
null_value
==
item
->
null_value
);
}
int
save_in_field
(
Field
*
field
,
bool
no_conversions
)
override
{
return
Item
::
save_in_field
(
field
,
no_conversions
);
}
Item
*
get_copy
(
THD
*
thd
)
override
{
return
get_item_copy
<
Item_copy_fbt
>
(
thd
,
this
);
}
};
class
in_fbt
:
public
in_vector
{
Fbt
m_value
;
static
int
cmp_fbt
(
void
*
cmp_arg
,
Fbt
*
a
,
Fbt
*
b
)
{
return
a
->
cmp
(
*
b
);
}
public:
in_fbt
(
THD
*
thd
,
uint
elements
)
:
in_vector
(
thd
,
elements
,
sizeof
(
Fbt
),
(
qsort2_cmp
)
cmp_fbt
,
0
),
m_value
(
Fbt
::
zero
())
{
}
const
Type_handler
*
type_handler
()
const
override
{
return
type_handler_fbt
();
}
void
set
(
uint
pos
,
Item
*
item
)
override
{
Fbt
*
buff
=
&
((
Fbt
*
)
base
)[
pos
];
Fbt_null
value
(
item
);
if
(
value
.
is_null
())
*
buff
=
Fbt
::
zero
();
else
*
buff
=
value
;
}
uchar
*
get_value
(
Item
*
item
)
override
{
Fbt_null
value
(
item
);
if
(
value
.
is_null
())
return
0
;
m_value
=
value
;
return
(
uchar
*
)
&
m_value
;
}
Item
*
create_item
(
THD
*
thd
)
override
{
return
new
(
thd
->
mem_root
)
Item_literal_fbt
(
thd
);
}
void
value_to_item
(
uint
pos
,
Item
*
item
)
override
{
const
Fbt
&
buff
=
(((
Fbt
*
)
base
)[
pos
]);
static_cast
<
Item_literal_fbt
*>
(
item
)
->
set_value
(
buff
);
}
};
class
Item_char_typecast_func_handler_fbt_to_binary
:
public
Item_handled_func
::
Handler_str
{
public:
const
Type_handler
*
return_type_handler
(
const
Item_handled_func
*
item
)
const
override
{
if
(
item
->
max_length
>
MAX_FIELD_VARCHARLENGTH
)
return
Type_handler
::
blob_type_handler
(
item
->
max_length
);
if
(
item
->
max_length
>
255
)
return
&
type_handler_varchar
;
return
&
type_handler_string
;
}
bool
fix_length_and_dec
(
Item_handled_func
*
xitem
)
const
override
{
return
false
;
}
String
*
val_str
(
Item_handled_func
*
item
,
String
*
to
)
const
override
{
DBUG_ASSERT
(
dynamic_cast
<
const
Item_char_typecast
*>
(
item
));
return
static_cast
<
Item_char_typecast
*>
(
item
)
->
val_str_binary_from_native
(
to
);
}
};
class
Type_collection_fbt
:
public
Type_collection
{
const
Type_handler
*
aggregate_common
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
{
if
(
a
==
b
)
return
a
;
return
NULL
;
}
const
Type_handler
*
aggregate_if_string
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
{
static
const
Type_aggregator
::
Pair
agg
[]
=
{
{
type_handler_fbt
(),
&
type_handler_null
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_varchar
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_string
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_tiny_blob
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_blob
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_medium_blob
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_long_blob
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_hex_hybrid
,
type_handler_fbt
()},
{
NULL
,
NULL
,
NULL
}
};
return
Type_aggregator
::
find_handler_in_array
(
agg
,
a
,
b
,
true
);
}
public:
const
Type_handler
*
aggregate_for_result
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
const
Type_handler
*
h
;
if
((
h
=
aggregate_common
(
a
,
b
))
||
(
h
=
aggregate_if_string
(
a
,
b
)))
return
h
;
return
NULL
;
}
const
Type_handler
*
aggregate_for_min_max
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
return
aggregate_for_result
(
a
,
b
);
}
const
Type_handler
*
aggregate_for_comparison
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
if
(
const
Type_handler
*
h
=
aggregate_common
(
a
,
b
))
return
h
;
static
const
Type_aggregator
::
Pair
agg
[]
=
{
{
type_handler_fbt
(),
&
type_handler_null
,
type_handler_fbt
()},
{
type_handler_fbt
(),
&
type_handler_long_blob
,
type_handler_fbt
()},
{
NULL
,
NULL
,
NULL
}
};
return
Type_aggregator
::
find_handler_in_array
(
agg
,
a
,
b
,
true
);
}
const
Type_handler
*
aggregate_for_num_op
(
const
Type_handler
*
a
,
const
Type_handler
*
b
)
const
override
{
return
NULL
;
}
const
Type_handler
*
handler_by_name
(
const
LEX_CSTRING
&
name
)
const
override
{
if
(
type_handler_fbt
()
->
name
().
eq
(
name
))
return
type_handler_fbt
();
return
NULL
;
}
};
static
Type_handler_fbt
*
type_handler_fbt
()
{
static
Type_handler_fbt
th
;
return
&
th
;
}
};
#endif
/* SQL_TYPE_FIXEDBIN_H */
sql/sql_type_fixedbin_storage.h
0 → 100644
View file @
0e8544cd
#ifndef SQL_TYPE_FIXEDBIN_STORAGE
#define SQL_TYPE_FIXEDBIN_STORAGE
/* Copyright (c) 2019,2021 MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/*
This is a common code for plugin (?) types that are generally
handled like strings, but have their own fixed size on-disk binary storage
format and their own (variable size) canonical string representation.
Examples are INET6 and UUID types.
The MariaDB server uses three binary representations of a data type:
1. In-memory binary representation (user visible)
This representation:
- can be used in INSERT..VALUES (X'AABBCC')
- can be used in WHERE conditions: WHERE c1=X'AABBCC'
- is returned by CAST(x AS BINARY(N))
- is returned by Field::val_native() and Item::val_native()
2. In-record binary representation (user invisible)
This representation:
- is used in records (is pointed by Field::ptr)
- must be comparable by memcmp()
3. Binlog binary (row) representation
Usually, for string data types the binlog representation
is based on the in-record representation with trailing byte compression:
- trailing space compression for text string data types
- trailing zero compression for binary string data types
We have to have separate in-memory and in-record representations
because we use HA_KEYTYPE_BINARY for indexing. The engine API
does not have a way to pass a comparison function as a parameter.
The default implementation below assumes that:
- the in-memory and in-record representations are equal
- the binlog representation is compatible with BINARY(N)
This is OK for simple data types, like INET6.
Data type implementations that need different representations
can override the default implementation (like e.g. UUID does).
*/
/***********************************************************************/
template
<
size_t
NATIVE_LEN
,
size_t
MAX_CHAR_LEN
>
class
FixedBinTypeStorage
{
protected:
// The buffer that stores the in-memory binary representation
char
m_buffer
[
NATIVE_LEN
];
// Non-initializing constructor
FixedBinTypeStorage
()
{
}
FixedBinTypeStorage
&
set_zero
()
{
bzero
(
&
m_buffer
,
sizeof
(
m_buffer
));
return
*
this
;
}
public:
// Initialize from the in-memory binary representation
FixedBinTypeStorage
(
const
char
*
str
,
size_t
length
)
{
if
(
length
!=
binary_length
())
set_zero
();
else
memcpy
(
&
m_buffer
,
str
,
sizeof
(
m_buffer
));
}
// Return the buffer with the in-memory representation
Lex_cstring
to_lex_cstring
()
const
{
return
Lex_cstring
(
m_buffer
,
sizeof
(
m_buffer
));
}
static
constexpr
uint
binary_length
()
{
return
NATIVE_LEN
;
}
static
constexpr
uint
max_char_length
()
{
return
MAX_CHAR_LEN
;
}
// Compare the in-memory binary representations of two values
static
int
cmp
(
const
LEX_CSTRING
&
a
,
const
LEX_CSTRING
&
b
)
{
DBUG_ASSERT
(
a
.
length
==
binary_length
());
DBUG_ASSERT
(
b
.
length
==
binary_length
());
return
memcmp
(
a
.
str
,
b
.
str
,
b
.
length
);
}
/*
Convert from the in-memory to the in-record representation.
Used in Field::store_native().
*/
static
void
memory_to_record
(
char
*
to
,
const
char
*
from
)
{
memcpy
(
to
,
from
,
NATIVE_LEN
);
}
/*
Convert from the in-record to the in-memory representation
Used in Field::val_native().
*/
static
void
record_to_memory
(
char
*
to
,
const
char
*
from
)
{
memcpy
(
to
,
from
,
NATIVE_LEN
);
}
/*
Hash the in-record representation
Used in Field::hash().
*/
static
void
hash_record
(
const
uchar
*
ptr
,
ulong
*
nr
,
ulong
*
nr2
)
{
my_charset_bin
.
hash_sort
(
ptr
,
binary_length
(),
nr
,
nr2
);
}
static
bool
only_zero_bytes
(
const
char
*
ptr
,
size_t
length
)
{
for
(
uint
i
=
0
;
i
<
length
;
i
++
)
{
if
(
ptr
[
i
]
!=
0
)
return
false
;
}
return
true
;
}
static
ulong
KEY_pack_flags
(
uint
column_nr
)
{
/*
Return zero by default. A particular data type can override
this method return some flags, e.g. HA_PACK_KEY to enable
key prefix compression.
*/
return
0
;
}
/*
Convert from the in-record to the binlog representation.
Used in Field::pack(), and in filesort to store the addon fields.
By default, do what BINARY(N) does.
*/
static
uchar
*
pack
(
uchar
*
to
,
const
uchar
*
from
,
uint
max_length
)
{
return
StringPack
(
&
my_charset_bin
,
binary_length
()).
pack
(
to
,
from
,
max_length
);
}
/*
Convert from the in-binary-log to the in-record representation.
Used in Field::unpack().
By default, do what BINARY(N) does.
*/
static
const
uchar
*
unpack
(
uchar
*
to
,
const
uchar
*
from
,
const
uchar
*
from_end
,
uint
param_data
)
{
return
StringPack
(
&
my_charset_bin
,
binary_length
()).
unpack
(
to
,
from
,
from_end
,
param_data
);
}
};
#endif
/* SQL_TYPE_FIXEDBIN_STORAGE */
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