1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00
Files
mariadb/sql/item_strfunc.h
Alexander Barkov 8c4943d208 MDEV-41246 "Illegal mix of collations" on the mysql.user view
This SQL script failed:

SET NAMES latin1 COLLATE latin1_swedish_ci;
CREATE OR REPLACE VIEW v1 AS SELECT 'Y' AS c1;
SET NAMES big5 COLLATE big5_chinese_ci;
SELECT * FROM v1 WHERE c1='y';

with the following error:

ERROR 1267 (HY000): Illegal mix of collations
(latin1_swedish_ci,COERCIBLE) and (big5_chinese_ci,COERCIBLE)
for operation '='

Note, latin1_swedish_ci and big5_chinese_ci are used here as examples.
The error also happened with different collation combinations.

Fix main idea:

If two collations have equal comparison rules (known as "tailoring")
on a given character repertoire,
like latin1_swedish_ci and big5_chinese_ci on ASCII letters,
then the "Illegal mix of collations" error can be avoided in
a comparison operator. We can choose any of the sides as the operation
effective collation - the result will be equal.

This optimization is not applied when at least one side has an explicit
COLLATE clause. Two explicit COLLATE clauses in one comparison are
already illegal when the character sets are the same, so for
consistency this stays illegal when the character sets differ too.

Most important details:

- Splitting enum_repertoire_t into smaller subsets,
  for better repertoire granularity.
  A variable holding a repertoire value can now have multiple
  MY_REPERTOIRE_XXX flags set.

  This patch implements detecting tailoring equality
  on these repertoires:
  * MY_REPERTOIRE_ASCII_DIGITS - [0..9]
  * MY_REPERTOIRE_ASCII_MINUS_DOT_DIGITS - [-.0..9], e.g. '-10.5'.
    It consists of the new bits MY_REPERTOIRE_ASCII_MINUS and
    MY_REPERTOIRE_ASCII_DOT. They were a part of
    MY_REPERTOIRE_ASCII_NOT_IDENT before. As a result, the numeric values
    of MY_REPERTOIRE_ASCII and MY_REPERTOIRE_UNICODE30 changed
    (223 and 255).
  * MY_REPERTOIRE_ASCII_ALNUM - [A..Z,a..z,0..9].
  * MY_REPERTOIRE_ASCII_IDENT - ALNUM + underscore
  * MY_REPERTOIRE_ASCII       - the entire range U+0000..U+007F

- Adding a new virtual function "tailoring" in my_collation_handler_st.

  It returns the tailoring on the given repertoire for the given
  collation.

  If cs1->coll->tailoring(cs1, some_repertoire) returns {0,0},
  it means the illegal mix optimization cannot be used
  for this collation on the given repertoire.

  If these calls:
     tr1= cs1->coll->tailoring(cs1, some_repertoire);
     tr2= cs2->coll->tailoring(cs2, some_repertoire);
  return both non-NULL results and tr1.str==tr2.str,
  then these collations are equal on the given repertoire
  and are mutually replaceable for a comparison operator,
  so "Illegal mix of collations" can be avoided.

- Tailoring strings are shared constants my_tailoring_str_*
  (strings/strings_def.h). Tailorings are compared by the string
  pointer, so tailoring() implementations return strings only from
  these constants. The strings do not depend on PAD/NOPAD.

- my_string_repertoire() for ucs2, utf16, utf32 and NONASCII 8bit
  character sets no longer stops at the first bad byte sequence with
  the repertoire found so far, which could be MY_REPERTOIRE_NONE
  (compatible with everything). It returns MY_REPERTOIRE_EXTENDED
  for such strings. A unit test was added into unittest/strings.

- Adding CHARSET_INFO::is_ascii_superset(). It tells if a character set
  can store all ASCII characters (it is false for swe7).
  It is used in Item_func_conv_charset to calculate "safe", and in
  left_is_algorithmically_simpler() to prefer other character sets
  to those where ASCII strings cannot be converted safely.

- DBUG_ASSERTs were added into mysys/charset.c, to check that
  the "tailoring" method is set in collation handlers when a collation
  is added: compiled-in, from ctype-extra.c, or loaded from Index.xml.

- Adding a new function my_collations_equal_on_repertoire(cs1, cs2,
  repertoire) in strings/. It tells if two collations are equal on
  the repertoire, taking tailoring() results and PAD/NOPAD and the UCA
  version into account. Callers do not compare tailoring() results
  directly, so the way tailorings are compared (currently by the pointer
  to the shared constant string) is private to strings/ and can be
  extended later, e.g. for UCA collations on MY_REPERTOIRE_UNICODE30.

- Adding a new method DTCollation::aggregate_by_tailoring().
  Collations with different MY_CS_NOPAD are never compatible.
  UCA collations of different versions are not compatible on
  the repertoire with ASCII punctuation, as the UCA version
  affects its order (e.g. UCA-6.2.0 moved GRAVE ACCENT
  and CIRCUMFLEX ACCENT after PERCENT SIGN).

- DTCollation::aggregate() now makes the repertoire of the result cover
  the repertoires of both sides in all successful branches.
  Before, set(dt) replaced the repertoire with the repertoire of the
  winner side only, so the result could have a too narrow repertoire,
  e.g. IF(1, 1.5, HEX(255)) had MY_REPERTOIRE_ASCII_ALNUM although the
  value '1.5' has a punctuation character. With the more granular
  repertoires this could wrongly allow mixing collations which are
  equal on ALNUM but different on punctuation.

- Adding a new flag MY_COLL_ALLOW_BY_TAILORING.
  It indicates to DTCollation::aggregate() that the illegal
  mix optimization by repertoire can be used in the given context.

  MY_COLL_CMP_CONV now includes MY_COLL_ALLOW_BY_TAILORING.
  Note, only comparison operators pass this flag.
  Functions returning a string result do not pass this flag,
  because in operations like CONCAT(a,b) we still need to evaluate
  precisely the collation of the result - we cannot just choose
  a collation of one of the sides (even if they are compatible
  on the given repertoire). This also applies to ExtractValue()
  and UpdateXML(), which now aggregate their arguments without
  this flag.

- As in my_repertoire_t the value MY_REPERTOIRE_ASCII is now a set of
  bits rather than a single bit, the way to detect "is only ASCII"
  repertoires has changed in the code.

  For example:
    // repertoire *IS* ascii
    if (repertoire == MY_REPERTOIRE_ASCII)

  has changed in multiple places in the code to

    // repertoire *HAS* only ascii characters
    if (my_repertoire_is_subset_of(repertoire, MY_REPERTOIRE_ASCII))

  The new function my_repertoire_is_subset_of() in m_ctype.h
  is used for this purpose in C code. In C++ code
  DTCollation::repertoire_is_subset_of() is used, e.g.:

    if (collation.repertoire_is_subset_of(MY_REPERTOIRE_ASCII))

- Repertoire of some expressions was adjusted to the new meaning:
  * Item_null now has MY_REPERTOIRE_NONE (was ASCII).
  * MY_LOCALE::repertoire() now returns MY_REPERTOIRE_UNICODE30
    (was EXTENDED).
  * Lex_string_with_metadata_st::repertoire(cs) now scans the string
    contents to detect the actual repertoire.
  * HEX() now has MY_REPERTOIRE_ASCII_ALNUM.
  * DATE_FORMAT() decides on MY_REPERTOIRE_EXTENDED using the locale
    which is actually used: the explicit third argument, or
    @@lc_time_names. It was always @@lc_time_names before.
    A non-constant locale argument is assumed to be non-ASCII.
  * QUOTE, MAKE_SET, EXPORT_SET, LPAD, RPAD, GROUP_CONCAT, JSON_ARRAY,
    JSON_OBJECT and JSON_OBJECTAGG add the repertoire of the extra
    characters they put into the result (quotes, separators, padding,
    brackets).
  * LOWER() and UPPER() add the letters of both cases to the repertoire,
    because the result can contain letters of the opposite case.
    In Turkish collations they also add MY_REPERTOIRE_EXTENDED, as an
    ASCII letter can be converted to a non-ASCII one (I -> dotless i).
    Unicode collations are detected by the new member
    casefold_info_st::can_convert_to_non_ascii_on_casefolding,
    simple 8bit collations by to_lower['I'] and to_upper['i'].

- Lex_string_with_metadata_st::repertoire(cs) now scans a string literal
  for any byte oriented character set (mbminlen==1), not only for
  ASCII based ones. It was assumed to have the full repertoire for swe7,
  which is not ASCII based. The scan is done by Unicode code points, so
  swe7 strings with digits and letters get a narrow repertoire, while
  e.g. 0x5B (LATIN CAPITAL LETTER A WITH DIAERESIS in swe7) is non-ASCII.
  Therefore swe7_swedish_ci can be mixed with other collations now,
  in the same way as other collations with MY_CS_IDENT_CASEUP_CI.
  The test func_time was adjusted: a swe7 literal ' ull' with ASCII
  characters is now safe to convert, the error is still tested for '[ull'.

- cp1250_czech_cs sorts -, . and 0..9 in the code point order, so it gets
  the MINUS_DOT_DIGITS tailoring. latin2_czech_cs gets only DIGITS,
  as it sorts the minus and the dot differently. Both were verified
  with ctype_digits_verify.

- The tis620 collations now set CHARSET_INFO::tab_to_uni (was NULL),
  so my_charset_is_ascii_based() is true for tis620.
  It was false for tis620, although tis620 is ASCII compatible.
  Therefore tis620 string literals were always considered to have
  a non-ASCII repertoire, and the repertoire optimizations did not work
  for them. Now ASCII-only tis620 literals are detected as ASCII.
  This changes the result of subselect_extra_no_semijoin
  from an error to success.

- tis620_thai_ci and tis620_thai_nopad_ci fold letters to lower case
  and then compare by the code point on the entire ASCII range
  (the Thai specific rules affect only non-ASCII characters).
  A new function my_tailoring_ascii_casedn_ci() returns tailorings
  for such collations on ALNUM, IDENT and ASCII. For example, the
  underscore sorts before the letters, unlike in the caseup tailorings.

- New flags were added for CHARSET_INFO::state
  * MY_CS_ASCII_CASEUP_CI - for simple 8bit case insensitive collations.
    It means that this collation has no irregularities on the ASCII
    repertoire, and converts lower case letters to upper case ones,
    so the underscore sorts after the letters (with an upper to lower
    case conversion it would sort before the letters).

  * MY_CS_IDENT_CASEUP_CI - for simple 8bit case insensitive collations.
    It means that this collation has no irregularities on the IDENT
    repertoire (but can have irregularities say on punctuation).

  * MY_CS_ASCII_STD_UCA - for UCA collations.
    It means that a UCA collation does not reorder ASCII characters.

  * MY_CS_DIGITS_STD - for any collation. It means that the ASCII digits
    0..9 are sorted in the code point order and are not tailored, and,
    for PAD collations, the space sorts before the digits. Strings of
    digits are compared in the same way in all such collations, even if
    they have irregularities on letters (latin7, cp866, czech, danish,
    turkish UCA, etc.), or differ by case sensitivity. It is detected
    from sort_order for 8bit collations, and from the tailoring rules
    for UCA collations. Collations with MY_CS_DIGITS_STD still must have
    the same PAD/NOPAD attribute.

  * MY_CS_ASCII_MINUS_DOT_DIGITS - for any collation. Means
    MY_CS_DIGITS_STD, and additionally the minus sorts before the dot,
    which sorts before the digits (and the space sorts before the minus
    in PAD collations). Strings like '-10.5' are compared in the same
    way in all such collations. It is detected from sort_order for simple
    8bit collations (my_coll_init_simple()), and from the tailoring rules
    for UCA collations. For the multi-byte collations big5_chinese_ci,
    gbk_chinese_ci, gb2312_chinese_ci and sjis_japanese_ci it is declared
    by my_tailoring_ident_caseup_ci_generic(). The flags MY_CS_DIGITS_STD
    and MY_CS_ASCII_MINUS_DOT_DIGITS are stored in ctype-extra.c for
    compiled collations (conf_to_src.c prints them), and the detection is
    skipped for a collation which already has any of the repertoire flags
    (MY_CS_REPERTOIRE_FLAGS).

- strings/conf_to_src.c was modified to detect and print
  MY_CS_ASCII_CASEUP_CI and MY_CS_IDENT_CASEUP_CI flags.

- strings/ctype-extra.c was regenerated with new flags.

- 8bit collations are not given MY_CS_ASCII_CASEUP_CI and
  MY_CS_IDENT_CASEUP_CI if they are PAD and the space does not sort
  before the digits. A shorter string is padded with spaces for
  comparison, so the position of the space matters even for strings
  without spaces ("ab" is compared to "abc" as "ab " to "abc").
  A test collation latin1_space_after_letters_ci was added to
  mysql-test/std_data/ldml/ for this. ctype-extra.c does not change.

- The initializer of my_collation_cs_handler in ctype-utf8.c
  (utf8mb3_general_cs, under HAVE_UTF8_GENERAL_CS) was fixed to match
  my_collation_handler_st: the missing get_id and get_collation_name
  members were added, so that eq_collation was not initialized in their
  place, and the new member "tailoring" is now set to my_tailoring_none.

- Results of the existing tests func_str, func_test, ps, view
  and subselect_sj changed from "Illegal mix of collations" to success.
  In these tests ASCII-only strings were compared using collations
  with equal tailoring on ASCII, e.g. latin1_swedish_ci with
  latin2_general_ci (func_str, ps), koi8r_general_ci with
  latin1_swedish_ci (func_test), latin1_general_ci with
  latin1_swedish_ci on letters and digits (view), cp932_japanese_ci
  with latin1_swedish_ci (subselect_sj).
  Such comparisons are now allowed.
  Cases with collations that are still incompatible on ASCII,
  e.g. latin7_general_ci, were added to the tests and still fail.

- Adding a number of MTR tests in
  plugin/func_test/mysql-test/func_test/.
  They display a tailoring by collation name and repertoire as
  returned by:
    cs->coll->tailoring(cs, some_repertoire)
  A dynamically linked plugin function collation_tailoring() was added
  for the purpose of these tests. Tailorings do not depend on PAD/NOPAD
  and on the UCA version, so the function shows "[nopad]" for NOPAD
  collations, and "[version X.Y.Z]" for UCA collations on the ASCII
  repertoire. The version is formatted by a new class UCAVersion,
  which uses a new method CharBuffer::append_uint8().

- Adding the test plugin/func_test/mysql-test/func_test/
  ctype_caseup_ci_verify.test. It checks the order of ASCII characters
  for all collations declared "caseup CI" on the ASCII or IDENT range.

- Adding the test plugin/func_test/mysql-test/func_test/
  collation_tailoring_args.test. It checks the arguments of the plugin
  function collation_tailoring(): the repertoire passed by name or by
  number, and the NULL results for unknown names.

- Adding the test plugin/func_test/mysql-test/func_test/ctype_ldml.test.
  It displays the tailorings of collations loaded at runtime from
  Index.xml: simple 8bit collations (flags detected from the weights)
  and Unicode collations (LDML rules which do or do not reorder ASCII).

- Adding a number of MTR tests mysql-test/main/ctype_xxx_tailoring.test
  They display two-dimensional charts showing which collations
  are compatible on which repertoires.
  Tests for DATE_FORMAT() with an explicit locale were added to
  ctype_big5_tailoring.test, ctype_cp932_tailoring.test and
  ctype_latin5_tailoring.test, which also has the chart for latin5.

- Adding a number of MTR tests in the form of the originally
  reported script for various collations:

    SELECT Insert_priv FROM mysql.user WHERE Insert_priv='...';

  The repeated blocks of queries are shared through
  mysql-test/include/
  ctype_tailoring_0{1,2,3}_mysql_user_Insert_priv*.inc.

- Adding tests to ctype_cp932.test checking that ExtractValue() and
  UpdateXML() still raise "Illegal mix of collations".
2026-10-15 15:39:04 +04:00

2711 lines
78 KiB
C++

#ifndef ITEM_STRFUNC_INCLUDED
#define ITEM_STRFUNC_INCLUDED
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2009, 2022, MariaDB
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 Street, Fifth Floor, Boston, MA 02110-1335 USA */
/* This file defines all string functions */
extern size_t username_char_length;
class Item_str_func :public Item_func
{
protected:
/**
Sets the result value of the function an empty string, using the current
character set. No memory is allocated.
@retval A pointer to the str_value member.
*/
virtual String *make_empty_result(String *str)
{
/*
Reset string length to an empty string. We don't use str_value.set() as
we don't want to free and potentially have to reallocate the buffer
for each call.
*/
if (!str->is_alloced())
str->set("", 0, collation.collation); /* Avoid null ptrs */
else
{
str->length(0); /* Reuse allocated area */
str->set_charset(collation.collation);
}
return str;
}
public:
Item_str_func(THD *thd): Item_func(thd) { decimals=NOT_FIXED_DEC; }
Item_str_func(THD *thd, Item *a): Item_func(thd, a) {decimals=NOT_FIXED_DEC; }
Item_str_func(THD *thd, Item *a, Item *b):
Item_func(thd, a, b) { decimals=NOT_FIXED_DEC; }
Item_str_func(THD *thd, Item *a, Item *b, Item *c):
Item_func(thd, a, b, c) { decimals=NOT_FIXED_DEC; }
Item_str_func(THD *thd, Item *a, Item *b, Item *c, Item *d):
Item_func(thd, a, b, c, d) { decimals=NOT_FIXED_DEC; }
Item_str_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e):
Item_func(thd, a, b, c, d, e) { decimals=NOT_FIXED_DEC; }
Item_str_func(THD *thd, List<Item> &list):
Item_func(thd, list) { decimals=NOT_FIXED_DEC; }
longlong val_int() override;
double val_real() override;
my_decimal *val_decimal(my_decimal *) override;
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{ return get_date_from_string(thd, ltime, fuzzydate); }
const Type_handler *type_handler() const override
{ return string_type_handler(); }
void left_right_max_length();
bool fix_fields(THD *thd, Item **ref) override;
};
/*
Functions that return values with ASCII repertoire
*/
class Item_str_ascii_func :public Item_str_func
{
String ascii_buf;
public:
Item_str_ascii_func(THD *thd): Item_str_func(thd) {}
Item_str_ascii_func(THD *thd, Item *a): Item_str_func(thd, a) {}
Item_str_ascii_func(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
Item_str_ascii_func(THD *thd, Item *a, Item *b, Item *c):
Item_str_func(thd, a, b, c) {}
String *val_str(String *str) override
{
return val_str_from_val_str_ascii(str, &ascii_buf);
}
String *val_str_ascii(String *) override= 0;
};
/**
Functions that return a checksum or a hash of the argument,
or somehow else encode or decode the argument,
returning an ASCII-repertoire string.
*/
class Item_str_ascii_checksum_func: public Item_str_ascii_func
{
public:
Item_str_ascii_checksum_func(THD *thd, Item *a)
:Item_str_ascii_func(thd, a) { }
Item_str_ascii_checksum_func(THD *thd, Item *a, Item *b)
:Item_str_ascii_func(thd, a, b) { }
bool eq(const Item *item, const Eq_config &config) const override
{
// Always use binary argument comparison: MD5('x') != MD5('X')
Eq_config new_config= config;
new_config.binary_cmp= true;
return Item_func::eq(item, new_config);
}
};
/**
Functions that return a checksum or a hash of the argument,
or somehow else encode or decode the argument,
returning a binary string.
*/
class Item_str_binary_checksum_func: public Item_str_func
{
public:
Item_str_binary_checksum_func(THD *thd, Item *a)
:Item_str_func(thd, a) { }
Item_str_binary_checksum_func(THD *thd, Item *a, Item *b)
:Item_str_func(thd, a, b) { }
Item_str_binary_checksum_func(THD *thd, Item *a, Item *b, Item *c)
:Item_str_func(thd, a, b, c) { }
Item_str_binary_checksum_func(THD *thd, Item *a, Item *b, Item *c, Item *d)
:Item_str_func(thd, a, b, c, d) { }
Item_str_binary_checksum_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item *e)
:Item_str_func(thd, a, b, c, d, e) { }
bool eq(const Item *item, const Eq_config &config) const override
{
/*
Always use binary argument comparison:
FROM_BASE64('test') != FROM_BASE64('TEST')
*/
Eq_config new_config= config;
new_config.binary_cmp= true;
return Item_func::eq(item, new_config);
}
};
class Item_func_md5 :public Item_str_ascii_checksum_func
{
public:
Item_func_md5(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {}
String *val_str_ascii(String *) override;
bool fix_length_and_dec(THD *thd) override
{
fix_length_and_charset(32, default_charset());
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("md5") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_md5>(thd, this); }
};
class Item_func_sha :public Item_str_ascii_checksum_func
{
public:
Item_func_sha(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {}
String *val_str_ascii(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("sha") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_sha>(thd, this); }
};
class Item_func_sha2 :public Item_str_ascii_checksum_func
{
public:
Item_func_sha2(THD *thd, Item *a, Item *b)
:Item_str_ascii_checksum_func(thd, a, b) {}
String *val_str_ascii(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("sha2") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_sha2>(thd, this); }
};
class Item_func_to_base64 :public Item_str_ascii_checksum_func
{
String tmp_value;
public:
Item_func_to_base64(THD *thd, Item *a)
:Item_str_ascii_checksum_func(thd, a) {}
String *val_str_ascii(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("to_base64") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_to_base64>(thd, this); }
};
class Item_func_from_base64 :public Item_str_binary_checksum_func
{
String tmp_value;
public:
Item_func_from_base64(THD *thd, Item *a)
:Item_str_binary_checksum_func(thd, a) { }
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("from_base64") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_from_base64>(thd, this); }
};
#include <my_crypt.h>
class Item_aes_crypt :public Item_str_binary_checksum_func
{
void create_key(String *user_key, uchar* key);
int parse_mode();
String tmp_value;
const int what;
uint aes_key_length;
enum my_aes_mode aes_mode;
public:
Item_aes_crypt(THD *thd, int what, Item *a, Item *b)
: Item_str_binary_checksum_func(thd, a, b), what(what) {}
Item_aes_crypt(THD *thd, int what, Item *a, Item *b, Item *c)
: Item_str_binary_checksum_func(thd, a, b, c), what(what) {}
Item_aes_crypt(THD *thd, int what, Item *a, Item *b, Item *c, Item *d)
: Item_str_binary_checksum_func(thd, a, b, c, d), what(what) {}
bool fix_fields(THD *thd, Item **ref) override;
String *val_str(String *) override;
bool check_vcol_func_processor(void *arg) override
{
if (arg_count > 3)
return FALSE;
return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC);
}
};
class Item_func_aes_encrypt :public Item_aes_crypt
{
public:
Item_func_aes_encrypt(THD *thd, Item *a, Item *b)
:Item_aes_crypt(thd, ENCRYPTION_FLAG_ENCRYPT, a, b) {}
Item_func_aes_encrypt(THD *thd, Item *a, Item *b, Item *c)
:Item_aes_crypt(thd, ENCRYPTION_FLAG_ENCRYPT, a, b, c) {}
Item_func_aes_encrypt(THD *thd, Item *a, Item *b, Item *c, Item *d)
:Item_aes_crypt(thd, ENCRYPTION_FLAG_ENCRYPT, a, b, c, d) {}
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("aes_encrypt") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_aes_encrypt>(thd, this); }
};
class Item_func_aes_decrypt :public Item_aes_crypt
{
public:
Item_func_aes_decrypt(THD *thd, Item *a, Item *b):
Item_aes_crypt(thd, ENCRYPTION_FLAG_DECRYPT, a, b) {}
Item_func_aes_decrypt(THD *thd, Item *a, Item *b, Item *c):
Item_aes_crypt(thd, ENCRYPTION_FLAG_DECRYPT, a, b, c) {}
Item_func_aes_decrypt(THD *thd, Item *a, Item *b, Item *c, Item *d):
Item_aes_crypt(thd, ENCRYPTION_FLAG_DECRYPT, a, b, c, d) {}
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("aes_decrypt") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_aes_decrypt>(thd, this); }
};
class Item_func_kdf :public Item_str_binary_checksum_func
{
uint key_length;
public:
Item_func_kdf(THD *thd, Item *a, Item *b)
: Item_str_binary_checksum_func(thd, a, b) {}
Item_func_kdf(THD *thd, Item *a, Item *b, Item *c)
: Item_str_binary_checksum_func(thd, a, b, c) {}
Item_func_kdf(THD *thd, Item *a, Item *b, Item *c, Item *d)
: Item_str_binary_checksum_func(thd, a, b, c, d) {}
Item_func_kdf(THD *thd, Item *a, Item *b, Item *c, Item *d, Item *e)
: Item_str_binary_checksum_func(thd, a, b, c, d, e) {}
bool fix_length_and_dec(THD *thd) override;
String *val_str(String *) override;
bool check_vcol_func_processor(void *arg) override
{
if (arg_count > 4)
return FALSE;
return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC);
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("kdf") };
return name;
}
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_kdf>(thd, this); }
};
class Item_func_natural_sort_key : public Item_str_func
{
public:
Item_func_natural_sort_key(THD *thd, Item *a)
: Item_str_func(thd, a){};
String *val_str(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("natural_sort_key")};
return name;
}
bool fix_length_and_dec(THD *thd) override;
Item *shallow_copy(THD *thd) const override
{
return get_item_copy<Item_func_natural_sort_key>(thd, this);
}
bool check_vcol_func_processor(void *arg) override;
};
class Item_func_concat :public Item_str_func
{
protected:
String tmp_value;
/*
Append a non-NULL value to the result.
@param [IN] thd - The current thread.
@param [IN/OUT] res - The current val_str() return value.
@param [IN] app - The value to be appended.
@retval - false on success, true on error
*/
bool append_value(THD *thd, String *res, const String *app);
bool realloc_result(String *str, uint length) const;
public:
Item_func_concat(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
Item_func_concat(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
const Schema *schema() const override { return &mariadb_schema; }
void print(String *str, enum_query_type query_type) override
{
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("concat") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_concat>(thd, this); }
};
/*
This class handles the || operator in sql_mode=ORACLE.
Unlike the traditional MariaDB concat(), it treats NULL arguments as ''.
*/
class Item_func_concat_operator_oracle :public Item_func_concat
{
public:
Item_func_concat_operator_oracle(THD *thd, List<Item> &list)
:Item_func_concat(thd, list)
{ }
Item_func_concat_operator_oracle(THD *thd, Item *a, Item *b)
:Item_func_concat(thd, a, b)
{ }
String *val_str(String *) override;
const Schema *schema() const override { return &oracle_schema_ref; }
void print(String *str, enum_query_type query_type) override
{
if (query_type & QT_FOR_FRM)
{
// 10.3 downgrade compatibility for FRM
str->append(STRING_WITH_LEN("concat_operator_oracle"));
}
else
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_concat_operator_oracle>(thd, this); }
};
class Item_func_decode_histogram :public Item_str_func
{
public:
Item_func_decode_histogram(THD *thd, Item *a, Item *b):
Item_str_func(thd, a, b) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
collation.set(system_charset_info_for_i_s);
max_length= MAX_BLOB_WIDTH;
set_maybe_null();
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("decode_histogram") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_decode_histogram>(thd, this); }
};
class Item_func_concat_ws :public Item_str_func
{
String tmp_value;
public:
Item_func_concat_ws(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("concat_ws") };
return name;
}
table_map not_null_tables() const override { return 0; }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_concat_ws>(thd, this); }
};
class Item_func_random_bytes : public Item_str_func
{
public:
Item_func_random_bytes(THD *thd, Item *arg1) : Item_str_func(thd, arg1) {}
bool fix_length_and_dec(THD *thd) override;
void update_used_tables() override;
String *val_str(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("random_bytes")};
return name;
}
bool check_vcol_func_processor(void *arg) override
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC);
}
Item *shallow_copy(THD *thd) const override
{
return get_item_copy<Item_func_random_bytes>(thd, this);
}
static const int MAX_RANDOM_BYTES= 1024;
};
class Item_func_reverse :public Item_str_func
{
String tmp_value;
public:
Item_func_reverse(THD *thd, Item *a): Item_str_func(thd, a) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("reverse") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_reverse>(thd, this); }
};
class Item_func_replace :public Item_str_func
{
String tmp_value,tmp_value2;
protected:
String *val_str_internal(String *str, bool null_to_empty);
public:
Item_func_replace(THD *thd, Item *org, Item *find, Item *replace):
Item_str_func(thd, org, find, replace) {}
String *val_str(String *to) override { return val_str_internal(to, false); };
bool fix_length_and_dec(THD *thd) override;
const Schema *schema() const override { return &mariadb_schema; }
void print(String *str, enum_query_type query_type) override
{
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("replace") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_replace>(thd, this); }
};
class Item_func_replace_oracle :public Item_func_replace
{
String tmp_emtpystr;
public:
Item_func_replace_oracle(THD *thd, Item *org, Item *find, Item *replace):
Item_func_replace(thd, org, find, replace) {}
String *val_str(String *to) override
{ return val_str_internal(to, true); };
const Schema *schema() const override { return &oracle_schema_ref; }
void print(String *str, enum_query_type query_type) override
{
if (query_type & QT_FOR_FRM)
{
// 10.3 downgrade compatibility for FRM
str->append(STRING_WITH_LEN("replace_oracle"));
}
else
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_replace_oracle>(thd, this); }
};
class Item_func_regexp_replace :public Item_str_func
{
Regexp_processor_pcre re;
bool append_replacement(String *str,
const LEX_CSTRING *source,
const LEX_CSTRING *replace);
protected:
String *val_str_internal(String *str, bool null_to_empty);
public:
Item_func_regexp_replace(THD *thd, Item *a, Item *b, Item *c):
Item_str_func(thd, a, b, c)
{}
const Schema *schema() const override { return &mariadb_schema; }
void print(String *str, enum_query_type query_type) override
{
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
void cleanup() override
{
DBUG_ENTER("Item_func_regexp_replace::cleanup");
Item_str_func::cleanup();
re.cleanup();
DBUG_VOID_RETURN;
}
String *val_str(String *str) override
{
return val_str_internal(str, false);
}
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("regexp_replace") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override { return nullptr; }
};
class Item_func_regexp_replace_oracle: public Item_func_regexp_replace
{
public:
Item_func_regexp_replace_oracle(THD *thd, Item *a, Item *b, Item *c)
:Item_func_regexp_replace(thd, a, b, c)
{}
const Schema *schema() const override { return &oracle_schema_ref; }
bool fix_length_and_dec(THD *thd) override
{
bool rc= Item_func_regexp_replace::fix_length_and_dec(thd);
set_maybe_null(); // Empty result is converted to NULL
return rc;
}
String *val_str(String *str) override
{
return val_str_internal(str, true);
}
protected:
Item *shallow_copy(THD *thd) const override { return nullptr; }
};
class Item_func_regexp_substr :public Item_str_func
{
Regexp_processor_pcre re;
public:
Item_func_regexp_substr(THD *thd, Item *a, Item *b):
Item_str_func(thd, a, b)
{}
void cleanup() override
{
DBUG_ENTER("Item_func_regexp_substr::cleanup");
Item_str_func::cleanup();
re.cleanup();
DBUG_VOID_RETURN;
}
String *val_str(String *str) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("regexp_substr") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override { return nullptr; }
};
class Item_func_insert :public Item_str_func
{
String tmp_value;
public:
Item_func_insert(THD *thd, Item *org, Item *start, Item *length,
Item *new_str):
Item_str_func(thd, org, start, length, new_str) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("insert") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_insert>(thd, this); }
};
class Item_str_conv :public Item_str_func
{
protected:
uint multiply;
my_charset_conv_case converter;
String tmp_value;
public:
Item_str_conv(THD *thd, Item *item): Item_str_func(thd, item) {}
String *val_str(String *) override;
};
class Item_func_lcase :public Item_str_conv
{
public:
Item_func_lcase(THD *thd, Item *item): Item_str_conv(thd, item) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("lcase") };
return name;
}
bool fix_length_and_dec(THD *thd) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_lcase>(thd, this); }
};
class Item_func_ucase :public Item_str_conv
{
public:
Item_func_ucase(THD *thd, Item *item): Item_str_conv(thd, item) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("ucase") };
return name;
}
bool fix_length_and_dec(THD *thd) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_ucase>(thd, this); }
};
class Item_func_left :public Item_str_func
{
String tmp_value;
public:
Item_func_left(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
bool hash_not_null(Hasher *hasher) override;
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
enum Functype functype() const override { return LEFT_FUNC; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("left") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_left>(thd, this); }
};
class Item_func_right :public Item_str_func
{
String tmp_value;
public:
Item_func_right(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("right") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_right>(thd, this); }
};
class Item_func_substr :public Item_str_func
{
String tmp_value;
protected:
virtual longlong get_position() { return args[1]->val_int(); }
public:
Item_func_substr(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
Item_func_substr(THD *thd, Item *a, Item *b, Item *c):
Item_str_func(thd, a, b, c) {}
Item_func_substr(THD *thd, List<Item> &list)
:Item_str_func(thd, list) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
const Schema *schema() const override { return &mariadb_schema; }
void print(String *str, enum_query_type query_type) override
{
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
enum Functype functype() const override { return SUBSTR_FUNC; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("substr") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_substr>(thd, this); }
};
class Item_func_sformat :public Item_str_func
{
String *val_arg;
void alloc(THD *thd);
public:
Item_func_sformat(THD *thd, List<Item> &list) : Item_str_func(thd, list)
{ alloc(thd); }
~Item_func_sformat() { delete [] val_arg; }
String *val_str(String*) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("sformat") };
return name;
}
Item *shallow_copy(THD *thd) const override
{
auto *sf= get_item_copy<Item_func_sformat>(thd, this);
sf->alloc(thd);
return sf;
}
};
class Item_func_substr_oracle :public Item_func_substr
{
protected:
longlong get_position() override
{ longlong pos= args[1]->val_int(); return pos == 0 ? 1 : pos; }
String *make_empty_result(String *str) override
{ null_value= 1; return NULL; }
public:
Item_func_substr_oracle(THD *thd, Item *a, Item *b):
Item_func_substr(thd, a, b) {}
Item_func_substr_oracle(THD *thd, Item *a, Item *b, Item *c):
Item_func_substr(thd, a, b, c) {}
Item_func_substr_oracle(THD *thd, List<Item> &list)
:Item_func_substr(thd, list) {}
bool fix_length_and_dec(THD *thd) override
{
bool res= Item_func_substr::fix_length_and_dec(thd);
set_maybe_null();
return res;
}
const Schema *schema() const override { return &oracle_schema_ref; }
void print(String *str, enum_query_type query_type) override
{
if (query_type & QT_FOR_FRM)
{
// 10.3 downgrade compatibility for FRM
str->append(STRING_WITH_LEN("substr_oracle"));
}
else
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_substr_oracle>(thd, this); }
};
class Item_func_substr_index :public Item_str_func
{
String tmp_value;
public:
Item_func_substr_index(THD *thd, Item *a,Item *b,Item *c):
Item_str_func(thd, a, b, c) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("substring_index") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_substr_index>(thd, this); }
};
class Item_func_trim :public Item_str_func
{
protected:
String tmp_value;
String remove;
String *trimmed_value(String *res, uint32 offset, uint32 length)
{
if (length == 0)
return make_empty_result(&tmp_value);
if (tmp_value.copy(res->ptr() + offset, length, res->charset()))
{
my_error(ER_OUTOFMEMORY, length);
return NULL;
}
/*
Make sure to return correct charset and collation:
TRIM(0x000000 FROM _ucs2 0x0061)
should set charset to "binary" rather than to "ucs2".
*/
tmp_value.set_charset(collation.collation);
return &tmp_value;
}
String *non_trimmed_value(String *res)
{
return trimmed_value(res, 0, res->length());
}
public:
Item_func_trim(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
Item_func_trim(THD *thd, Item *a): Item_str_func(thd, a) {}
Sql_mode_dependency value_depends_on_sql_mode() const override;
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
const Schema *schema() const override { return &mariadb_schema; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("trim") };
return name;
}
void print(String *str, enum_query_type query_type) override;
virtual LEX_CSTRING mode_name() const { return { "both", 4}; }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_trim>(thd, this); }
};
class Item_func_trim_oracle :public Item_func_trim
{
protected:
String *make_empty_result(String *str) override
{ null_value= 1; return NULL; }
public:
Item_func_trim_oracle(THD *thd, Item *a, Item *b):
Item_func_trim(thd, a, b) {}
Item_func_trim_oracle(THD *thd, Item *a): Item_func_trim(thd, a) {}
const Schema *schema() const override { return &oracle_schema_ref; }
bool fix_length_and_dec(THD *thd) override
{
bool res= Item_func_trim::fix_length_and_dec(thd);
set_maybe_null();
return res;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_trim_oracle>(thd, this); }
};
class Item_func_ltrim :public Item_func_trim
{
public:
Item_func_ltrim(THD *thd, Item *a, Item *b): Item_func_trim(thd, a, b) {}
Item_func_ltrim(THD *thd, Item *a): Item_func_trim(thd, a) {}
Sql_mode_dependency value_depends_on_sql_mode() const override
{
return Item_func::value_depends_on_sql_mode();
}
String *val_str(String *) override;
const Schema *schema() const override { return &mariadb_schema; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("ltrim") };
return name;
}
LEX_CSTRING mode_name() const override
{ return { STRING_WITH_LEN("leading") }; }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_ltrim>(thd, this); }
};
class Item_func_ltrim_oracle :public Item_func_ltrim
{
protected:
String *make_empty_result(String *str) override
{ null_value= 1; return NULL; }
public:
Item_func_ltrim_oracle(THD *thd, Item *a, Item *b):
Item_func_ltrim(thd, a, b) {}
Item_func_ltrim_oracle(THD *thd, Item *a): Item_func_ltrim(thd, a) {}
const Schema *schema() const override { return &oracle_schema_ref; }
bool fix_length_and_dec(THD *thd) override
{
bool res= Item_func_ltrim::fix_length_and_dec(thd);
set_maybe_null();
return res;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_ltrim_oracle>(thd, this); }
};
class Item_func_rtrim :public Item_func_trim
{
public:
Item_func_rtrim(THD *thd, Item *a, Item *b): Item_func_trim(thd, a, b) {}
Item_func_rtrim(THD *thd, Item *a): Item_func_trim(thd, a) {}
String *val_str(String *) override;
const Schema *schema() const override { return &mariadb_schema; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("rtrim") };
return name;
}
LEX_CSTRING mode_name() const override
{ return { STRING_WITH_LEN("trailing") }; }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_rtrim>(thd, this); }
};
class Item_func_rtrim_oracle :public Item_func_rtrim
{
protected:
String *make_empty_result(String *str) override
{ null_value= 1; return NULL; }
public:
Item_func_rtrim_oracle(THD *thd, Item *a, Item *b):
Item_func_rtrim(thd, a, b) {}
Item_func_rtrim_oracle(THD *thd, Item *a): Item_func_rtrim(thd, a) {}
const Schema *schema() const override { return &oracle_schema_ref; }
bool fix_length_and_dec(THD *thd) override
{
bool res= Item_func_rtrim::fix_length_and_dec(thd);
set_maybe_null();
return res;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_rtrim_oracle>(thd, this); }
};
/*
Item_func_password -- new (4.1.1) PASSWORD() function implementation.
Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new
password format, sha1(sha1(password) is so-called hash_stage2 value.
Length of returned string is always 41 byte. To find out how entire
authentication procedure works, see comments in password.c.
*/
class Item_func_password :public Item_str_ascii_checksum_func
{
public:
enum PW_Alg {OLD, NEW};
private:
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
enum PW_Alg alg;
bool deflt;
public:
Item_func_password(THD *thd, Item *a):
Item_str_ascii_checksum_func(thd, a), alg(NEW), deflt(1) {}
Item_func_password(THD *thd, Item *a, PW_Alg al):
Item_str_ascii_checksum_func(thd, a), alg(al), deflt(0) {}
String *val_str_ascii(String *str) override;
bool fix_fields(THD *thd, Item **ref) override;
bool fix_length_and_dec(THD *thd) override
{
fix_length_and_charset((alg == 1 ?
SCRAMBLED_PASSWORD_CHAR_LENGTH :
SCRAMBLED_PASSWORD_CHAR_LENGTH_323),
default_charset());
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING password_normal= {STRING_WITH_LEN("password") };
static LEX_CSTRING password_old= {STRING_WITH_LEN("old_password") };
return (deflt || alg == 1) ? password_normal : password_old;
}
static char *alloc(THD *thd, const char *password, size_t pass_len,
enum PW_Alg al);
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_password>(thd, this); }
};
class Item_func_des_encrypt :public Item_str_binary_checksum_func
{
String tmp_value,tmp_arg;
public:
Item_func_des_encrypt(THD *thd, Item *a)
:Item_str_binary_checksum_func(thd, a) {}
Item_func_des_encrypt(THD *thd, Item *a, Item *b)
:Item_str_binary_checksum_func(thd, a, b) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("des_encrypt") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_des_encrypt>(thd, this); }
};
class Item_func_des_decrypt :public Item_str_binary_checksum_func
{
String tmp_value;
public:
Item_func_des_decrypt(THD *thd, Item *a)
:Item_str_binary_checksum_func(thd, a) {}
Item_func_des_decrypt(THD *thd, Item *a, Item *b)
:Item_str_binary_checksum_func(thd, a, b) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("des_decrypt") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_des_decrypt>(thd, this); }
};
/**
QQ: Item_func_encrypt should derive from Item_str_ascii_checksum_func.
However, it should be fixed to handle UCS2, UTF16, UTF32 properly first,
as the underlying crypt() call expects a null-terminated input string.
*/
class Item_func_encrypt :public Item_str_binary_checksum_func
{
String tmp_value;
/* Encapsulate common constructor actions */
void constructor_helper()
{
collation.set(&my_charset_bin);
}
public:
Item_func_encrypt(THD *thd, Item *a): Item_str_binary_checksum_func(thd, a)
{
constructor_helper();
}
Item_func_encrypt(THD *thd, Item *a, Item *b)
:Item_str_binary_checksum_func(thd, a, b)
{
constructor_helper();
}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
set_maybe_null();
max_length = 13;
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("encrypt") };
return name;
}
bool check_vcol_func_processor(void *arg) override
{
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_encrypt>(thd, this); }
};
#include "sql_crypt.h"
class Item_func_encode :public Item_str_binary_checksum_func
{
private:
/** Whether the PRNG has already been seeded. */
bool seeded;
protected:
SQL_CRYPT sql_crypt;
public:
Item_func_encode(THD *thd, Item *a, Item *seed_arg):
Item_str_binary_checksum_func(thd, a, seed_arg) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("encode") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_encode>(thd, this); }
virtual void crypto_transform(String *);
private:
/** Provide a seed for the PRNG sequence. */
bool seed();
};
class Item_func_decode :public Item_func_encode
{
public:
Item_func_decode(THD *thd, Item *a, Item *seed_arg): Item_func_encode(thd, a, seed_arg) {}
const Schema *schema() const override { return &mariadb_schema; }
void print(String *str, enum_query_type query_type) override
{
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("decode") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_decode>(thd, this); }
void crypto_transform(String *) override;
};
class Item_func_sysconst :public Item_str_func
{
public:
Item_func_sysconst(THD *thd): Item_str_func(thd)
{ collation.set(system_charset_info_for_i_s, DERIVATION_SYSCONST); }
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override;
/*
Used to create correct Item name in new converted item in
safe_charset_converter, return string representation of this function
call
*/
virtual const Lex_ident_routine fully_qualified_func_name() const = 0;
bool check_vcol_func_processor(void *arg) override
{
return mark_unsupported_function(fully_qualified_func_name().str, arg,
VCOL_SESSION_FUNC);
}
bool const_item() const override;
};
class Item_func_database :public Item_func_sysconst
{
public:
Item_func_database(THD *thd): Item_func_sysconst(thd) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
fix_char_length(NAME_CHAR_LEN);
set_maybe_null();
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("database") };
return name;
}
const Lex_ident_routine fully_qualified_func_name() const override
{ return Lex_ident_routine("database()"_LEX_CSTRING); }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_database>(thd, this); }
};
class Item_func_sqlerrm :public Item_func_sysconst
{
public:
Item_func_sqlerrm(THD *thd): Item_func_sysconst(thd) {}
String *val_str(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("SQLERRM") };
return name;
}
const Lex_ident_routine fully_qualified_func_name() const override
{ return Lex_ident_routine("SQLERRM"_LEX_CSTRING); }
void print(String *str, enum_query_type query_type) override
{
str->append(func_name_cstring());
}
bool fix_length_and_dec(THD *thd) override
{
fix_char_length(512);
null_value= false;
base_flags&= ~item_base_t::MAYBE_NULL;
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_sqlerrm>(thd, this); }
};
class Item_func_user :public Item_func_sysconst
{
protected:
bool init (const char *user, const char *host);
public:
Item_func_user(THD *thd): Item_func_sysconst(thd)
{
str_value.set("", 0, collation.collation);
}
String *val_str(String *) override
{
DBUG_ASSERT(fixed());
return (null_value ? 0 : &str_value);
}
bool fix_fields(THD *thd, Item **ref) override;
bool fix_length_and_dec(THD *thd) override
{
max_length= (uint32) (username_char_length +
HOSTNAME_LENGTH + 1) * SYSTEM_CHARSET_MBMAXLEN;
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("user") };
return name;
}
const Lex_ident_routine fully_qualified_func_name() const override
{ return Lex_ident_routine("user()"_LEX_CSTRING); }
int save_in_field(Field *field, bool no_conversions) override
{
return save_str_value_in_field(field, &str_value);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_user>(thd, this); }
};
class Item_func_current_user :public Item_func_user
{
Name_resolution_context *context;
public:
Item_func_current_user(THD *thd, Name_resolution_context *context_arg):
Item_func_user(thd), context(context_arg) {}
bool fix_fields(THD *thd, Item **ref) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("current_user") };
return name;
}
const Lex_ident_routine fully_qualified_func_name() const override
{ return Lex_ident_routine("current_user()"_LEX_CSTRING); }
bool check_vcol_func_processor(void *arg) override
{
context= 0;
return mark_unsupported_function(fully_qualified_func_name().str, arg,
VCOL_SESSION_FUNC);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_current_user>(thd, this); }
};
class Item_func_session_user :public Item_func_user
{
public:
Item_func_session_user(THD *thd):
Item_func_user(thd) {}
bool fix_fields(THD *thd, Item **ref) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("session_user") };
return name;
}
const Lex_ident_routine fully_qualified_func_name() const override
{ return Lex_ident_routine("session_user()"_LEX_CSTRING); }
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_session_user>(thd, this); }
};
class Item_func_current_role :public Item_func_sysconst
{
Name_resolution_context *context;
public:
Item_func_current_role(THD *thd, Name_resolution_context *context_arg):
Item_func_sysconst(thd), context(context_arg) {}
bool fix_fields(THD *thd, Item **ref) override;
bool fix_length_and_dec(THD *thd) override
{
max_length= (uint32) username_char_length * SYSTEM_CHARSET_MBMAXLEN;
return FALSE;
}
int save_in_field(Field *field, bool no_conversions) override
{ return save_str_value_in_field(field, &str_value); }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("current_role") };
return name;
}
const Lex_ident_routine fully_qualified_func_name() const override
{ return Lex_ident_routine("current_role()"_LEX_CSTRING); }
String *val_str(String *) override
{
DBUG_ASSERT(fixed());
return null_value ? NULL : &str_value;
}
bool check_vcol_func_processor(void *arg) override
{
context= 0;
return mark_unsupported_function(fully_qualified_func_name().str, arg,
VCOL_SESSION_FUNC);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_current_role>(thd, this); }
};
class Item_func_soundex :public Item_str_func
{
String tmp_value;
public:
Item_func_soundex(THD *thd, Item *a): Item_str_func(thd, a) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("soundex") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_soundex>(thd, this); }
};
class Item_func_elt :public Item_str_func
{
public:
Item_func_elt(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
double val_real() override;
longlong val_int() override;
String *val_str(String *str) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("elt") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_elt>(thd, this); }
};
class Item_func_make_set :public Item_str_func
{
String tmp_str;
public:
Item_func_make_set(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
String *val_str(String *str) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("make_set") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_make_set>(thd, this); }
};
class Item_func_format :public Item_str_ascii_func
{
const MY_LOCALE *locale;
public:
Item_func_format(THD *thd, Item *org, Item *dec):
Item_str_ascii_func(thd, org, dec) {}
Item_func_format(THD *thd, Item *org, Item *dec, Item *lang):
Item_str_ascii_func(thd, org, dec, lang) {}
String *val_str_ascii(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("format") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_format>(thd, this); }
};
class Item_func_char :public Item_str_func
{
public:
Item_func_char(THD *thd, List<Item> &list): Item_str_func(thd, list)
{ collation.set(&my_charset_bin); }
Item_func_char(THD *thd, List<Item> &list, CHARSET_INFO *cs):
Item_str_func(thd, list)
{ collation.set(cs); }
Item_func_char(THD *thd, Item *arg1, CHARSET_INFO *cs):
Item_str_func(thd, arg1)
{ collation.set(cs); }
String *val_str(String *) override;
void append_char(String * str, int32 num);
bool fix_length_and_dec(THD *thd) override
{
max_length= arg_count * 4;
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("char") };
return name;
}
void print(String *str, enum_query_type query_type) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_char>(thd, this); }
} ;
class Item_func_chr :public Item_func_char
{
public:
Item_func_chr(THD *thd, Item *arg1, CHARSET_INFO *cs):
Item_func_char(thd, arg1, cs) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
max_length= 4;
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("chr") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_chr>(thd, this); }
};
class Item_func_repeat :public Item_str_func
{
String tmp_value;
public:
Item_func_repeat(THD *thd, Item *arg1, Item *arg2):
Item_str_func(thd, arg1, arg2) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("repeat") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_repeat>(thd, this); }
};
class Item_func_space :public Item_str_func
{
public:
Item_func_space(THD *thd, Item *arg1): Item_str_func(thd, arg1) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("space") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_space>(thd, this); }
};
class Item_func_binlog_gtid_pos :public Item_str_func
{
public:
Item_func_binlog_gtid_pos(THD *thd, Item *arg1, Item *arg2):
Item_str_func(thd, arg1, arg2) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("binlog_gtid_pos") };
return name;
}
bool check_vcol_func_processor(void *arg) override
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_binlog_gtid_pos>(thd, this); }
};
class Item_func_pad: public Item_str_func
{
protected:
String tmp_value, pad_str;
public:
Item_func_pad(THD *thd, Item *arg1, Item *arg2, Item *arg3):
Item_str_func(thd, arg1, arg2, arg3) {}
Item_func_pad(THD *thd, Item *arg1, Item *arg2):
Item_str_func(thd, arg1, arg2) {}
Item_func_pad(THD *thd, List<Item> &list):
Item_str_func(thd,list) {}
bool fix_length_and_dec(THD *thd) override;
};
class Item_func_rpad :public Item_func_pad
{
public:
Item_func_rpad(THD *thd, Item *arg1, Item *arg2, Item *arg3):
Item_func_pad(thd, arg1, arg2, arg3) {}
Item_func_rpad(THD *thd, Item *arg1, Item *arg2):
Item_func_pad(thd, arg1, arg2) {}
Item_func_rpad(THD *thd, List<Item> &list):
Item_func_pad(thd,list) {}
String *val_str(String *) override;
const Schema *schema() const override { return &mariadb_schema; }
void print(String *str, enum_query_type query_type) override
{
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("rpad") };
return name;
}
Sql_mode_dependency value_depends_on_sql_mode() const override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_rpad>(thd, this); }
};
class Item_func_rpad_oracle :public Item_func_rpad
{
String *make_empty_result(String *str) override
{ null_value= 1; return NULL; }
public:
Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3):
Item_func_rpad(thd, arg1, arg2, arg3) {}
Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2):
Item_func_rpad(thd, arg1, arg2) {}
Item_func_rpad_oracle(THD *thd, List<Item> &list):
Item_func_rpad(thd,list) {}
bool fix_length_and_dec(THD *thd) override
{
bool res= Item_func_rpad::fix_length_and_dec(thd);
set_maybe_null();
return res;
}
const Schema *schema() const override { return &oracle_schema_ref; }
void print(String *str, enum_query_type query_type) override
{
if (query_type & QT_FOR_FRM)
{
// 10.3 downgrade compatibility for FRM
str->append(STRING_WITH_LEN("rpad_oracle"));
}
else
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_rpad_oracle>(thd, this); }
};
class Item_func_lpad :public Item_func_pad
{
public:
Item_func_lpad(THD *thd, Item *arg1, Item *arg2, Item *arg3):
Item_func_pad(thd, arg1, arg2, arg3) {}
Item_func_lpad(THD *thd, Item *arg1, Item *arg2):
Item_func_pad(thd, arg1, arg2) {}
Item_func_lpad(THD *thd, List<Item> &list):
Item_func_pad(thd,list) {}
String *val_str(String *) override;
const Schema *schema() const override { return &mariadb_schema; }
void print(String *str, enum_query_type query_type) override
{
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("lpad") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_lpad>(thd, this); }
};
class Item_func_lpad_oracle :public Item_func_lpad
{
String *make_empty_result(String *str) override
{ null_value= 1; return NULL; }
public:
Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3):
Item_func_lpad(thd, arg1, arg2, arg3) {}
Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2):
Item_func_lpad(thd, arg1, arg2) {}
Item_func_lpad_oracle(THD *thd, List<Item> &list):
Item_func_lpad(thd,list) {}
bool fix_length_and_dec(THD *thd) override
{
bool res= Item_func_lpad::fix_length_and_dec(thd);
set_maybe_null();
return res;
}
const Schema *schema() const override { return &oracle_schema_ref; }
void print(String *str, enum_query_type query_type) override
{
if (query_type & QT_FOR_FRM)
{
// 10.3 downgrade compatibility for FRM
str->append(STRING_WITH_LEN("lpad_oracle"));
}
else
print_sql_mode_qualified_name(str, query_type);
print_args_parenthesized(str, query_type);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_lpad_oracle>(thd, this); }
};
class Item_func_conv :public Item_str_func
{
public:
Item_func_conv(THD *thd, Item *a, Item *b, Item *c):
Item_str_func(thd, a, b, c) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("conv") };
return name;
}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
collation.set(default_charset());
fix_char_length(65);
set_maybe_null();
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_conv>(thd, this); }
};
class Item_func_hex :public Item_str_ascii_checksum_func
{
protected:
String tmp_value;
/*
Calling arg[0]->type_handler() can be expensive on every row.
It's a virtual method, and in case if args[0] is a complex Item,
its type_handler() can call more virtual methods.
So let's cache it during fix_length_and_dec().
*/
const Type_handler *m_arg0_type_handler;
public:
Item_func_hex(THD *thd, Item *a):
Item_str_ascii_checksum_func(thd, a), m_arg0_type_handler(NULL) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("hex") };
return name;
}
String *val_str_ascii_from_val_int(String *str);
String *val_str_ascii_from_val_real(String *str);
String *val_str_ascii_from_val_str(String *str);
String *val_str_ascii(String *str) override
{
DBUG_ASSERT(fixed());
return m_arg0_type_handler->Item_func_hex_val_str_ascii(this, str);
}
bool fix_length_and_dec(THD *thd) override
{
m_arg0_type_handler= args[0]->type_handler();
collation.set(default_charset(), DERIVATION_COERCIBLE,
MY_REPERTOIRE_ASCII_ALNUM);
decimals=0;
/*
Reserve space for 16 characters for signed numeric data types:
hex(-1) -> 'FFFFFFFFFFFFFFFF'.
For unsigned numeric types, HEX() can create too large columns.
This should be eventually fixed to create minimum possible columns.
*/
const Type_handler_numeric *tn=
dynamic_cast<const Type_handler_numeric*>(m_arg0_type_handler);
size_t char_length= (tn && !(tn->flags() & UNSIGNED_FLAG)) ?
(size_t) 16 : (size_t) args[0]->max_length * 2;
fix_char_length(char_length);
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_hex>(thd, this); }
};
class Item_func_unhex :public Item_str_func
{
String tmp_value;
public:
Item_func_unhex(THD *thd, Item *a): Item_str_func(thd, a)
{
/* there can be bad hex strings */
set_maybe_null();
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("unhex") };
return name;
}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
collation.set(&my_charset_bin);
decimals=0;
max_length=(1+args[0]->max_length)/2;
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_unhex>(thd, this); }
};
#ifndef DBUG_OFF
class Item_func_like_range :public Item_str_func
{
protected:
String min_str;
String max_str;
const bool is_min;
public:
Item_func_like_range(THD *thd, Item *a, Item *b, bool is_min_arg):
Item_str_func(thd, a, b), is_min(is_min_arg)
{
set_maybe_null();
}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
collation.set(args[0]->collation);
decimals=0;
max_length= MAX_BLOB_WIDTH;
return FALSE;
}
};
class Item_func_like_range_min :public Item_func_like_range
{
public:
Item_func_like_range_min(THD *thd, Item *a, Item *b):
Item_func_like_range(thd, a, b, true) { }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("like_range_min") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_like_range_min>(thd, this); }
};
class Item_func_like_range_max :public Item_func_like_range
{
public:
Item_func_like_range_max(THD *thd, Item *a, Item *b):
Item_func_like_range(thd, a, b, false) { }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("like_range_max") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_like_range_max>(thd, this); }
};
#endif
class Item_func_binary :public Item_str_func
{
public:
Item_func_binary(THD *thd, Item *a): Item_str_func(thd, a) {}
String *val_str(String *a) override
{
DBUG_ASSERT(fixed());
String *tmp=args[0]->val_str(a);
null_value=args[0]->null_value;
if (tmp)
tmp->set_charset(&my_charset_bin);
return tmp;
}
bool fix_length_and_dec(THD *thd) override
{
collation.set(&my_charset_bin);
max_length=args[0]->max_length;
return FALSE;
}
void print(String *str, enum_query_type query_type) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_binary") };
return name;
}
bool need_parentheses_in_default() override { return true; }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_binary>(thd, this); }
};
class Item_load_file :public Item_str_func
{
String tmp_value;
public:
Item_load_file(THD *thd, Item *a): Item_str_func(thd, a) {}
String *val_str(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("load_file") };
return name;
}
bool fix_length_and_dec(THD *thd) override
{
collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
set_maybe_null();
max_length=MAX_BLOB_WIDTH;
return FALSE;
}
bool check_vcol_func_processor(void *arg) override
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_load_file>(thd, this); }
};
class Item_func_export_set: public Item_str_func
{
public:
Item_func_export_set(THD *thd, Item *a, Item *b, Item* c):
Item_str_func(thd, a, b, c) {}
Item_func_export_set(THD *thd, Item *a, Item *b, Item* c, Item* d):
Item_str_func(thd, a, b, c, d) {}
Item_func_export_set(THD *thd, Item *a, Item *b, Item* c, Item* d, Item* e):
Item_str_func(thd, a, b, c, d, e) {}
String *val_str(String *str) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("export_set") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_export_set>(thd, this); }
};
class Item_func_quote :public Item_str_func
{
String tmp_value;
public:
Item_func_quote(THD *thd, Item *a): Item_str_func(thd, a) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("quote") };
return name;
}
String *val_str(String *) override;
table_map not_null_tables() const override { return 0; }
bool fix_length_and_dec(THD *thd) override
{
collation.set(args[0]->collation);
/*
The result also contains the quote characters and the backslash
escapes that QUOTE() adds around and inside the argument.
*/
collation.repertoire|= MY_REPERTOIRE_ASCII_NOT_IDENT;
ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 +
2 * collation.collation->mbmaxlen;
// NULL argument is returned as a string "NULL" without quotes
if (args[0]->maybe_null())
set_if_bigger(max_result_length, 4 * collation.collation->mbmaxlen);
max_length= (uint32) MY_MIN(max_result_length, MAX_BLOB_WIDTH);
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_quote>(thd, this); }
};
class Item_func_conv_charset :public Item_str_func
{
bool use_cached_value;
String tmp_value;
public:
bool safe;
Item_func_conv_charset(THD *thd, Item *a, CHARSET_INFO *cs):
Item_str_func(thd, a)
{
collation= DTCollation::string_typecast(cs);
use_cached_value= 0; safe= 0;
}
Item_func_conv_charset(THD *thd, Item *a, CHARSET_INFO *cs, bool cache_if_const):
Item_str_func(thd, a)
{
collation= DTCollation::string_typecast(cs);
if (cache_if_const && args[0]->can_eval_in_optimize())
{
uint errors= 0;
String tmp, *str= args[0]->val_str(&tmp);
if (!str || str_value.copy(str->ptr(), str->length(),
str->charset(), cs, &errors))
null_value= 1;
use_cached_value= 1;
str_value.mark_as_const();
safe= (errors == 0);
}
else
{
use_cached_value= 0;
/*
Conversion from and to "binary" is safe.
Conversion to Unicode is safe.
Conversion from an expression with the ASCII repertoire
to any character set that can store characters U+0000..U+007F
(see CHARSET_INFO::is_ascii_superset()) is safe.
Other kind of conversions are potentially lossy.
*/
safe= (args[0]->collation.collation == &my_charset_bin ||
cs == &my_charset_bin ||
(cs->state & MY_CS_UNICODE) ||
(args[0]->collation.
repertoire_is_subset_of(MY_REPERTOIRE_ASCII) &&
cs->is_ascii_superset()));
}
}
String *val_str(String *) override;
longlong val_int() override
{
if (args[0]->result_type() == STRING_RESULT)
return Item_str_func::val_int();
longlong res= args[0]->val_int();
if ((null_value= args[0]->null_value))
return 0;
return res;
}
double val_real() override
{
if (args[0]->result_type() == STRING_RESULT)
return Item_str_func::val_real();
double res= args[0]->val_real();
if ((null_value= args[0]->null_value))
return 0;
return res;
}
my_decimal *val_decimal(my_decimal *d) override
{
if (args[0]->result_type() == STRING_RESULT)
return Item_str_func::val_decimal(d);
my_decimal *res= args[0]->val_decimal(d);
if ((null_value= args[0]->null_value))
return NULL;
return res;
}
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{
if (args[0]->result_type() == STRING_RESULT)
return Item_str_func::get_date(thd, ltime, fuzzydate);
bool res= args[0]->get_date(thd, ltime, fuzzydate);
if ((null_value= args[0]->null_value))
return 1;
return res;
}
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("convert") };
return name;
}
void print(String *str, enum_query_type query_type) override;
int save_in_field(Field*, bool) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_conv_charset>(thd, this); }
};
class Item_func_set_collation :public Item_str_func
{
Lex_extended_collation_st m_set_collation;
public:
Item_func_set_collation(THD *thd, Item *a,
const Lex_extended_collation_st &set_collation):
Item_str_func(thd, a), m_set_collation(set_collation) {}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
bool eq(const Item *item, const Eq_config &config) const override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("collate") };
return name;
}
enum precedence precedence() const override { return COLLATE_PRECEDENCE; }
enum Functype functype() const override { return COLLATE_FUNC; }
void print(String *str, enum_query_type query_type) override;
Item_field *field_for_view_update() override
{
/* this function is transparent for view updating */
return args[0]->field_for_view_update();
}
bool need_parentheses_in_default() override { return true; }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_set_collation>(thd, this); }
};
class Item_func_expr_str_metadata :public Item_str_func
{
public:
Item_func_expr_str_metadata(THD *thd, Item *a): Item_str_func(thd, a) { }
bool fix_length_and_dec(THD *thd) override
{
collation.set(system_charset_info_for_i_s, DERIVATION_SYSCONST);
max_length= 64 * collation.collation->mbmaxlen; // should be enough
base_flags&= ~item_base_t::MAYBE_NULL;
return FALSE;
};
table_map not_null_tables() const override { return 0; }
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
override
{ return this; }
bool const_item() const override { return true; }
};
class Item_func_charset :public Item_func_expr_str_metadata
{
LEX_CSTRING m_cached_charset_info;
public:
Item_func_charset(THD *thd, Item *a)
:Item_func_expr_str_metadata(thd, a) { }
String *val_str(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("charset") };
return name;
}
table_map used_tables() const override { return 0; }
bool fix_length_and_dec(THD* thd) override
{
if (Item_func_expr_str_metadata::fix_length_and_dec(thd))
return true;
/*
Since this is a const item which doesn't use tables (see used_tables()),
we don't want to access the function arguments during execution.
That's why we store the charset here during the preparation phase
and only return it later at the execution phase
*/
DBUG_ASSERT(args[0]->fixed());
m_cached_charset_info.str= args[0]->charset_for_protocol()->cs_name.str;
m_cached_charset_info.length=
args[0]->charset_for_protocol()->cs_name.length;
return false;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_charset>(thd, this); }
};
class Item_func_collation :public Item_func_expr_str_metadata
{
public:
Item_func_collation(THD *thd, Item *a)
:Item_func_expr_str_metadata(thd, a) {}
String *val_str(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("collation") };
return name;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_collation>(thd, this); }
};
class Item_func_weight_string :public Item_str_func
{
String tmp_value;
uint weigth_flags;
uint nweights;
uint result_length;
public:
Item_func_weight_string(THD *thd, Item *a, uint result_length_arg,
uint nweights_arg, uint flags_arg):
Item_str_func(thd, a)
{
nweights= nweights_arg;
weigth_flags= flags_arg;
result_length= result_length_arg;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("weight_string") };
return name;
}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override;
bool eq(const Item *item, const Eq_config &config) const override
{
if (!Item_str_func::eq(item, config))
return false;
Item_func_weight_string *that= (Item_func_weight_string *)item;
return this->weigth_flags == that->weigth_flags &&
this->nweights == that->nweights &&
this->result_length == that->result_length;
}
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
override
{ return this; }
void print(String *str, enum_query_type query_type) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_weight_string>(thd, this); }
};
class Item_func_crc32 :public Item_long_func
{
bool check_arguments() const override
{
return args[0]->check_type_can_return_str(func_name_cstring()) &&
(arg_count == 1 ||
args[1]->check_type_can_return_int(func_name_cstring()));
}
String value;
uint32 (*const crc_func)(uint32, const void*, size_t);
public:
Item_func_crc32(THD *thd, bool Castagnoli, Item *a) :
Item_long_func(thd, a),
crc_func(Castagnoli ? my_crc32c : my_checksum)
{ unsigned_flag= 1; }
Item_func_crc32(THD *thd, bool Castagnoli, Item *a, Item *b) :
Item_long_func(thd, a, b),
crc_func(Castagnoli ? my_crc32c : my_checksum)
{ unsigned_flag= 1; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING crc32_name= {STRING_WITH_LEN("crc32") };
static LEX_CSTRING crc32c_name= {STRING_WITH_LEN("crc32c") };
return crc_func == my_crc32c ? crc32c_name : crc32_name;
}
bool fix_length_and_dec(THD *thd) override { max_length=10; return FALSE; }
longlong val_int() override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_crc32>(thd, this); }
};
class Item_func_uncompressed_length : public Item_long_func_length
{
String value;
public:
Item_func_uncompressed_length(THD *thd, Item *a)
:Item_long_func_length(thd, a) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("uncompressed_length") };
return name;
}
bool fix_length_and_dec(THD *thd) override
{
max_length=10;
set_maybe_null();
return FALSE; }
longlong val_int() override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_uncompressed_length>(thd, this); }
};
#ifdef HAVE_COMPRESS
#define ZLIB_DEPENDED_FUNCTION ;
#else
#define ZLIB_DEPENDED_FUNCTION { null_value=1; return 0; }
#endif
class Item_func_compress: public Item_str_binary_checksum_func
{
String tmp_value;
public:
Item_func_compress(THD *thd, Item *a)
:Item_str_binary_checksum_func(thd, a) {}
bool fix_length_and_dec(THD *thd) override
{
max_length= (args[0]->max_length * 120) / 100 + 12;
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("compress") };
return name;
}
String *val_str(String *) override ZLIB_DEPENDED_FUNCTION
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_compress>(thd, this); }
};
class Item_func_uncompress: public Item_str_binary_checksum_func
{
String tmp_value;
public:
Item_func_uncompress(THD *thd, Item *a)
:Item_str_binary_checksum_func(thd, a) {}
bool fix_length_and_dec(THD *thd) override
{
set_maybe_null();
max_length= MAX_BLOB_WIDTH;
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("uncompress") };
return name;
}
String *val_str(String *) override ZLIB_DEPENDED_FUNCTION
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_uncompress>(thd, this); }
};
class Item_func_dyncol_create: public Item_str_func
{
protected:
DYNCALL_CREATE_DEF *defs;
DYNAMIC_COLUMN_VALUE *vals;
uint *keys_num;
LEX_STRING *keys_str;
bool names, force_names;
bool prepare_arguments(THD *thd, bool force_names);
void print_arguments(String *str, enum_query_type query_type);
public:
Item_func_dyncol_create(THD *thd, List<Item> &args, DYNCALL_CREATE_DEF *dfs);
bool fix_fields(THD *thd, Item **ref) override;
bool fix_length_and_dec(THD *thd) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("column_create") };
return name;
}
String *val_str(String *) override;
void print(String *str, enum_query_type query_type) override;
enum Functype functype() const override { return DYNCOL_FUNC; }
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_dyncol_create>(thd, this); }
};
class Item_func_dyncol_add: public Item_func_dyncol_create
{
public:
Item_func_dyncol_add(THD *thd, List<Item> &args_arg, DYNCALL_CREATE_DEF *dfs):
Item_func_dyncol_create(thd, args_arg, dfs)
{}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("column_add") };
return name;
}
String *val_str(String *) override;
void print(String *str, enum_query_type query_type) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_dyncol_add>(thd, this); }
};
class Item_func_dyncol_json: public Item_str_func
{
public:
Item_func_dyncol_json(THD *thd, Item *str): Item_str_func(thd, str)
{collation.set(DYNCOL_UTF);}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("column_json") };
return name;
}
String *val_str(String *) override;
bool fix_length_and_dec(THD *thd) override
{
max_length= MAX_BLOB_WIDTH;
set_maybe_null();
decimals= 0;
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_dyncol_json>(thd, this); }
};
/*
The following functions is always called from an Item_cast function
*/
class Item_dyncol_get: public Item_str_func
{
public:
Item_dyncol_get(THD *thd, Item *str, Item *num): Item_str_func(thd, str, num)
{}
bool fix_length_and_dec(THD *thd) override
{
set_maybe_null();
max_length= MAX_BLOB_WIDTH;
return FALSE;
}
/* Mark that collation can change between calls */
bool dynamic_result() override { return 1; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("column_get") };
return name;
}
String *val_str(String *) override;
longlong val_int() override;
longlong val_int_signed_typecast() override
{
unsigned_flag= false; // Mark that we want to have a signed value
longlong value= val_int(); // val_int() can change unsigned_flag
if (!null_value && unsigned_flag && value < 0)
push_note_converted_to_negative_complement(current_thd);
return value;
}
longlong val_int_unsigned_typecast() override
{
unsigned_flag= true; // Mark that we want to have an unsigned value
longlong value= val_int(); // val_int() can change unsigned_flag
if (!null_value && unsigned_flag == 0 && value < 0)
push_note_converted_to_positive_complement(current_thd);
return value;
}
double val_real() override;
my_decimal *val_decimal(my_decimal *) override;
bool get_dyn_value(THD *thd, DYNAMIC_COLUMN_VALUE *val, String *tmp);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
void print(String *str, enum_query_type query_type) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_dyncol_get>(thd, this); }
};
class Item_func_dyncol_list: public Item_str_func
{
public:
Item_func_dyncol_list(THD *thd, Item *str): Item_str_func(thd, str)
{collation.set(DYNCOL_UTF);}
bool fix_length_and_dec(THD *thd) override
{
set_maybe_null();
max_length= MAX_BLOB_WIDTH;
return FALSE;
}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("column_list") };
return name;
}
String *val_str(String *) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_dyncol_list>(thd, this); }
};
/*
this is used by JOIN_TAB::keep_current_rowid
and stores handler::position().
It has nothing to do with _rowid pseudo-column, that the parser supports.
*/
class Item_temptable_rowid :public Item_str_func
{
public:
TABLE *table;
Item_temptable_rowid(TABLE *table_arg);
const Type_handler *type_handler() const override
{ return &type_handler_string; }
Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table)
{ return create_table_field_from_handler(root, table); }
String *val_str(String *str) override;
enum Functype functype() const override { return TEMPTABLE_ROWID; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("<rowid>") };
return name;
}
bool fix_length_and_dec(THD *thd) override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_temptable_rowid>(thd, this); }
};
class Item_func_format_pico_time : public Item_str_ascii_func
{
/* Format is 'AAAA.BB UUU' = 11 characters or 'AAA ps' = 6 characters. */
char m_value_buffer[12];
String m_value;
public:
Item_func_format_pico_time(THD *thd, Item *a): Item_str_ascii_func(thd, a) {}
String *val_str_ascii(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("format_pico_time")};
return name;
}
bool fix_length_and_dec(THD *thd) override
{
m_value.set(m_value_buffer, sizeof(m_value_buffer), default_charset());
fix_length_and_charset(sizeof(m_value_buffer), default_charset());
return false;
}
Item *shallow_copy(THD *thd) const override
{
return get_item_copy<Item_func_format_pico_time>(thd, this);
}
};
class Item_func_format_bytes : public Item_str_ascii_func
{
/* Format is '-A.AAe+BB UUU' = 13 or 'AAAA.BB UUU' = 11 characters or 'AAAA bytes' = 10 characters. */
char m_value_buffer[14];
String m_value;
public:
Item_func_format_bytes(THD *thd, Item *a): Item_str_ascii_func(thd, a) {}
String *val_str_ascii(String *) override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("format_bytes")};
return name;
}
bool fix_length_and_dec(THD *thd) override
{
m_value.set(m_value_buffer, sizeof(m_value_buffer), default_charset());
fix_length_and_charset(sizeof(m_value_buffer), default_charset());
return false;
}
Item *shallow_copy(THD *thd) const override
{
return get_item_copy<Item_func_format_bytes>(thd, this);
}
};
#ifdef WITH_WSREP
#include "wsrep_api.h"
class Item_func_wsrep_last_written_gtid: public Item_str_ascii_func
{
String gtid_str;
public:
Item_func_wsrep_last_written_gtid(THD *thd): Item_str_ascii_func(thd) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("wsrep_last_written_gtid") };
return name;
}
String *val_str_ascii(String *) override;
bool fix_length_and_dec(THD *thd) override
{
max_length= WSREP_GTID_STR_LEN;
set_maybe_null();
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_wsrep_last_written_gtid>(thd, this); }
};
class Item_func_wsrep_last_seen_gtid: public Item_str_ascii_func
{
String gtid_str;
public:
Item_func_wsrep_last_seen_gtid(THD *thd): Item_str_ascii_func(thd) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("wsrep_last_seen_gtid") };
return name;
}
String *val_str_ascii(String *) override;
bool fix_length_and_dec(THD *thd) override
{
max_length= WSREP_GTID_STR_LEN;
set_maybe_null();
return FALSE;
}
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_wsrep_last_seen_gtid>(thd, this); }
};
class Item_func_wsrep_sync_wait_upto: public Item_int_func
{
String value;
public:
Item_func_wsrep_sync_wait_upto(THD *thd, Item *a): Item_int_func(thd, a) {}
Item_func_wsrep_sync_wait_upto(THD *thd, Item *a, Item* b): Item_int_func(thd, a, b) {}
const Type_handler *type_handler() const override
{ return &type_handler_string; }
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("wsrep_sync_wait_upto_gtid") };
return name;
}
longlong val_int() override;
protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_wsrep_sync_wait_upto>(thd, this); }
};
#endif /* WITH_WSREP */
#endif /* ITEM_STRFUNC_INCLUDED */