mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
Remove the HA_NO_BLOBS restriction from the HEAP engine, allowing the optimizer to keep temporary tables with BLOB/TEXT columns in memory when they fit within max_heap_table_size / tmp_memory_table_size limits. Additionally, advertise HA_CAN_GEOMETRY so explicit CREATE TABLE ... ENGINE=MEMORY with GEOMETRY columns works. Unlike other HEAP blob implementations (e.g. Percona), this patch provides full HASH index support on blob columns, enabling efficient lookups, GROUP BY, and DISTINCT operations directly in HEAP without falling back to disk. Architecture ------------ BLOB data is stored using continuation records -- additional fixed-size records allocated from the same HP_BLOCK that holds regular rows. This reuses existing allocation, free list, and size accounting with minimal structural change, and avoids per-blob my_malloc() calls. The existing single-byte visibility flag is extended into a flags byte with bits for HP_ROW_HAS_CONT, HP_ROW_IS_CONT, HP_ROW_CONT_ZEROCOPY, HP_ROW_SINGLE_REC, and HP_ROW_MULTIPLE_REC. Continuation records are grouped into variable-length runs -- contiguous sequences within a leaf block. Only the first record of each run carries a 10-byte header (next_cont pointer + run_rec_count); inner records are pure payload. Three storage formats, detected by flag bits via inline predicates: Case A (HP_ROW_SINGLE_REC): single record, no header, data at offset 0. Zero-copy read. Case B (HP_ROW_CONT_ZEROCOPY): single run, multiple records. Header in rec 0, data contiguous in rec 1..N-1. Zero-copy read via chain + recbuffer. Case C (HP_ROW_MULTIPLE_REC): one or more runs linked via next_cont. Reassembly into blob_buff required. Run allocation uses a two-phase strategy: (1) peek-then-unlink walk of the free list detecting contiguous groups, (2) tail allocation from HP_BLOCK for remaining data. A Step 3 scavenge fallback walks the entire free list when tail allocation fails. HP_SHARE::total_records tracks all physical records (primary + continuation), while HP_SHARE::records remains the logical count used by hash bucket mapping. Reassembly buffer (HP_INFO::blob_buff) follows the same pattern as InnoDB's blob_heap -- allocated once, grown via my_realloc, freed on heap_reset()/close. Zero-copy cases (A/B) return pointers directly into HP_BLOCK with no copy. Full HASH index key handling for BLOB columns: hp_rec_hashnr(), hp_rec_key_cmp(), hp_key_cmp(), hp_make_key(), hp_hashnr() are extended for HA_BLOB_PART segments. Hash pre-check optimization skips expensive blob materialization when hashes differ. PAD SPACE collation semantics are preserved for blob key comparisons. Field_blob_key (Monty) produces HEAP-native key format (4-byte length + 8-byte data pointer) directly, eliminating key buffer translation between the SQL layer and HEAP engine. SQL layer changes ----------------- pick_engine() (new, extracted from choose_engine()): replaced the blob_fields check with a reclength > HA_MAX_REC_LENGTH guard. choose_engine() calls pick_engine() with the real reclength. pick_engine() is also called early in finalize() with reclength=0 to predict whether the engine will be HEAP, enabling blob-aware GROUP BY key setup that avoids unnecessary m_using_unique_constraint. finalize(): HEAP+blob uses fixed-width rows; GROUP BY key setup sets key_part_flag from field, uses item max_length for blob key sizing. store_length initialized for all GROUP BY key parts. key_type uses field->binary() to determine FIELDFLAG_BINARY vs text collation. DISTINCT key setup skips null-bits helper for HEAP. remove_duplicates(): blob check moved before HEAP check to fall through to remove_dup_with_compare(). Aggregator_distinct::add(): overflow-to-disk conversion via create_internal_tmp_table_from_heap() for non-dup write errors. Expression cache disabled for HEAP+blob (key format incompatibility). FULLTEXT early detection in mysql_derived_prepare(): forces disk engine via TMP_TABLE_FORCE_MYISAM when outer query uses MATCH. Deferred blob chain free (MDEV-39732): heap_delete() saves chain pointers to pending_blob_chains, flushed on next mutation or heap_reset()/close. Prevents dangling zero-copy pointers during binlog_log_row(). REPLACE safety (MDEV-39825): HP_SHARE::write_can_replace flag forces copy mode in hp_read_blobs(), preventing blob data corruption from freed-then-reused continuation records during REPLACE. Geometry GROUP_CONCAT fix (MDEV-39761): downgrade Field_geom to Field_blob for GROUP_CONCAT temp tables in both expression creation paths. Type_handler_geometry::type_handler_for_tmp_table() added. Geometry GROUP BY key fix (MDEV-39871): detect when new_key_field() produced non-blob Field_varstring for a blob column, replace with Field_blob_key. Performance ----------- Non-blob tables: zero regression. Every blob-specific code path is guarded by if (share->blob_count). No new allocations, no format changes, no hash function changes for non-blob keys. Blob tables: eliminates file creation/deletion overhead and page cache management. For single-run blobs (common case), the read path is entirely zero-copy. Limitations ----------- 1. No BTREE indexes on blob columns (HASH only) 2. No partial-key prefix indexing for blobs 3. 2x memory for Case C reads only (A/B are 1x) 4. No blob compression 5. 65,535 records per run (uint16 cap, auto-split) 6. max_heap_table_size applies to continuation records 7. Expression cache disabled for HEAP+blob 8. FULLTEXT forces disk engine Linked bugs fixed: - MDEV-39703: mroonga fulltext test ordering - MDEV-39723: ER_DUP_ENTRY on GROUP BY with blob column - MDEV-39724: crash in hp_is_single_rec with GROUP BY - MDEV-39732: slave crash in hp_free_run_chain on blob replication - MDEV-39761: Field_geom::store() assertion in GROUP_CONCAT - MDEV-39782: RBR ER_KEY_NOT_FOUND on HEAP blob UPDATE - MDEV-39825: blob data corruption on REPLACE into HEAP table - MDEV-39871: crash in my_hash_sort_bin on GROUP BY with geometry Reviewed by: Michael Widenius <monty@mariadb.org> Monty reviewed the entire patch. Areas where he suggested changes or contributed code: - Field_blob_key class (HEAP-native blob key format, 4-byte length + data pointer) - Duplicate key fix on HEAP-to-Aria conversion - hp_blob_key_length() uint32 fix - hp_rec_hashnr_stored removal - type_handler_for_tmp_table() param cleanup - Type_handler_geometry::type_handler_for_tmp_table() virtual - blob pointer bzero() - find_unique_row() double-materialization fix - Tail reclaim review - Batch tail allocation review - hp_update.c cleanup - Field_blob_compressed temp table fix - row_pack_length() dedup - pack_length_no_ptr() removal - Race condition fix in HEAP - MDEV-39703 mroonga test fix - MDEV-39825 write_can_replace optimization - is_text_key_segment removal (field->binary() simplification) - Documentation (Docs/internal-temporary-tables.txt) Contribution by: Alexander Barkov <bar@mariadb.com> Type_handler::make_and_init_table_field_ex() -- refactored temp table field creation from inline code in sql_select.cc into type handler virtual methods (sql_type.cc, sql_type_geom.cc), enabling clean per-type-handler field creation for HEAP blob promotion.
2773 lines
80 KiB
C++
2773 lines
80 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) { }
|
|
Item_str_ascii_checksum_func(THD *thd, Item *a, Item *b, Item *c)
|
|
:Item_str_ascii_func(thd, a, b, c) { }
|
|
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
|
|
{
|
|
bool check_arguments() const override
|
|
{ return check_argument_types_can_return_str(0, arg_count); }
|
|
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
|
|
{
|
|
bool check_arguments() const override
|
|
{ return check_argument_types_can_return_str(0, arg_count); }
|
|
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
|
|
{
|
|
bool check_arguments() const override
|
|
{ return check_argument_types_can_return_str(0, arg_count); }
|
|
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); }
|
|
};
|
|
|
|
|
|
/**
|
|
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;
|
|
}
|
|
// block standard processor for never null
|
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
|
{ return 0; }
|
|
|
|
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_current_path :public Item_func_sysconst
|
|
{
|
|
public:
|
|
Item_func_current_path(THD *thd): Item_func_sysconst(thd) {}
|
|
String *val_str(String *) override;
|
|
bool fix_length_and_dec(THD *thd) override
|
|
{
|
|
max_length=32767;
|
|
return FALSE;
|
|
}
|
|
LEX_CSTRING func_name_cstring() const override
|
|
{
|
|
static LEX_CSTRING name= {STRING_WITH_LEN("current_path") };
|
|
return name;
|
|
}
|
|
const Lex_ident_routine fully_qualified_func_name() const override
|
|
{ return Lex_ident_routine("current_path()"_LEX_CSTRING); }
|
|
bool check_vcol_func_processor(void *arg) override
|
|
{
|
|
return mark_unsupported_function(fully_qualified_func_name().str, arg,
|
|
VCOL_SESSION_FUNC);
|
|
}
|
|
Item *shallow_copy(THD *thd) const override
|
|
{ return get_item_copy<Item_func_current_path>(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); }
|
|
// null do not depend on nullability of the argument
|
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
|
{ return 0; }
|
|
};
|
|
|
|
|
|
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);
|
|
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);
|
|
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
|
|
is safe:
|
|
- All supported multibyte character sets can store U+0000..U+007F
|
|
- All supported 7bit character sets can store U+0000..U+007F
|
|
except those marked with MY_CS_NONASCII (e.g. swe7).
|
|
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 == MY_REPERTOIRE_ASCII &&
|
|
(cs->mbmaxlen > 1 || !(cs->state & MY_CS_NONASCII))));
|
|
}
|
|
}
|
|
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;
|
|
bool check_arguments() const override
|
|
{ return check_argument_types_can_return_str(0, 1); }
|
|
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;
|
|
};
|
|
// block standard processor for never null
|
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
|
{ return 0; }
|
|
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_xxh32 : public Item_long_func
|
|
{
|
|
String buffer;
|
|
public:
|
|
Item_func_xxh32(THD *thd, Item *arg) : Item_long_func(thd, arg)
|
|
{
|
|
unsigned_flag= true;
|
|
}
|
|
|
|
longlong val_int() override;
|
|
bool check_arguments() const override;
|
|
|
|
bool fix_length_and_dec(THD *) override
|
|
{
|
|
max_length= 10;
|
|
set_maybe_null();
|
|
return false;
|
|
}
|
|
|
|
LEX_CSTRING func_name_cstring() const override
|
|
{
|
|
static LEX_CSTRING name= {STRING_WITH_LEN("XXH32")};
|
|
return name;
|
|
}
|
|
|
|
Item *shallow_copy(THD *thd) const override
|
|
{
|
|
return get_item_copy<Item_func_xxh32>(thd, this);
|
|
}
|
|
};
|
|
|
|
class Item_func_xxh3 : public Item_longlong_func
|
|
{
|
|
String buffer;
|
|
public:
|
|
Item_func_xxh3(THD *thd, Item *arg) : Item_longlong_func(thd, arg)
|
|
{
|
|
unsigned_flag= true;
|
|
}
|
|
|
|
longlong val_int() override;
|
|
bool check_arguments() const override;
|
|
|
|
bool fix_length_and_dec(THD *) override
|
|
{
|
|
max_length= 20;
|
|
set_maybe_null();
|
|
return false;
|
|
}
|
|
|
|
LEX_CSTRING func_name_cstring() const override
|
|
{
|
|
static LEX_CSTRING name= {STRING_WITH_LEN("XXH3")};
|
|
return name;
|
|
}
|
|
|
|
Item *shallow_copy(THD *thd) const override
|
|
{
|
|
return get_item_copy<Item_func_xxh3>(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,
|
|
Tmp_field_param *param)
|
|
{ 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 */
|