/* Copyright (c) 2019, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #define MYSQL_SERVER #include #include #include class Item_func_sysconst_test :public Item_func_sysconst { public: Item_func_sysconst_test(THD *thd): Item_func_sysconst(thd) {} String *val_str(String *str) override { null_value= str->copy(STRING_WITH_LEN("sysconst_test"), system_charset_info); return null_value ? NULL : str; } bool fix_length_and_dec(THD *thd) override { max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen; set_maybe_null(); return false; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sysconst_test") }; return name; } const Lex_ident_routine fully_qualified_func_name() const override { return Lex_ident_routine("sysconst_test()"_LEX_CSTRING); } Item *shallow_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Create_func_sysconst_test : public Create_func_arg0 { public: Item *create_builder(THD *thd) override; static Create_func_sysconst_test s_singleton; protected: Create_func_sysconst_test() {} }; Create_func_sysconst_test Create_func_sysconst_test::s_singleton; Item* Create_func_sysconst_test::create_builder(THD *thd) { return new (thd->mem_root) Item_func_sysconst_test(thd); } #define BUILDER(F) & F::s_singleton static Plugin_function plugin_descriptor_function_sysconst_test(BUILDER(Create_func_sysconst_test)); class Strnxfrm_args: public Null_flag { StringBuffer<128> m_srcbuf; public: String *m_src; longlong m_dstlen; longlong m_nweights; longlong m_flags; Strnxfrm_args(Item **args) :Null_flag(true) { if (!(m_src= args[0]->val_str(&m_srcbuf))) return; m_dstlen= args[1]->val_int(); if (args[1]->null_value || m_dstlen < 0) return; m_nweights= args[2]->val_int(); if (args[2]->null_value || m_nweights < 0) return; m_flags= args[3]->val_int(); if (args[3]->null_value || m_flags < 0) return; m_is_null= false; } my_strnxfrm_ret_t exec(CHARSET_INFO *cs, String *to) { DBUG_ASSERT(!is_null()); if ((m_is_null= to->alloc(m_dstlen))) return {0,0,0}; my_strnxfrm_ret_t rc= cs->strnxfrm((char*) to->ptr(), (size_t)m_dstlen, (uint) m_nweights, m_src->ptr(), m_src->length(), (uint) m_flags); to->length((uint32) rc.m_result_length); return rc; } }; class Item_func_strnxfrm_source_length_used: public Item_longlong_func { using Self = Item_func_strnxfrm_source_length_used; public: using Item_longlong_func::Item_longlong_func; longlong val_int() override { Strnxfrm_args param(args); if ((null_value= param.is_null())) return 0; StringBuffer<128> dstbuf; my_strnxfrm_ret_t rc= param.exec(args[0]->collation.collation, &dstbuf); if ((null_value= param.is_null())) return 0; return (longlong) rc.m_source_length_used; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= "strnxfrm_source_length_used"_LEX_CSTRING; return name; } Item *shallow_copy(THD *thd) const override { return get_item_copy(thd, this); } class Create_func : public Create_native_func { public: using Create_native_func::Create_native_func; Item *create_native(THD *thd, const LEX_CSTRING *name, List *item_list) override { uint arg_count= item_list ? item_list->elements : 0; if (arg_count != 4) { my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str); return nullptr; } return new (thd->mem_root) Self(thd, *item_list); } }; static Plugin_function *plugin_descriptor() { static Create_func creator; static Plugin_function descriptor(&creator); return &descriptor; } }; class Item_func_strnxfrm_warnings: public Item_long_func { using Self = Item_func_strnxfrm_warnings; public: using Item_long_func::Item_long_func; longlong val_int() override { Strnxfrm_args param(args); if ((null_value= param.is_null())) return 0; StringBuffer<128> dstbuf; my_strnxfrm_ret_t rc= param.exec(args[0]->collation.collation, &dstbuf); if ((null_value= param.is_null())) return 0; return (longlong) rc.m_warnings; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= "strnxfrm_warnings"_LEX_CSTRING; return name; } Item *shallow_copy(THD *thd) const override { return get_item_copy(thd, this); } class Create_func : public Create_native_func { public: using Create_native_func::Create_native_func; Item *create_native(THD *thd, const LEX_CSTRING *name, List *item_list) override { uint arg_count= item_list ? item_list->elements : 0; if (arg_count != 4) { my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str); return nullptr; } return new (thd->mem_root) Self(thd, *item_list); } }; static Plugin_function *plugin_descriptor() { static Create_func creator; static Plugin_function descriptor(&creator); return &descriptor; } }; class Item_func_strnxfrm: public Item_str_func { using Self = Item_func_strnxfrm; public: using Item_str_func::Item_str_func; bool fix_length_and_dec(THD *thd) override { max_length= MAX_BLOB_WIDTH; return false; } String *val_str(String *to) override { Strnxfrm_args param(args); if ((null_value= param.is_null())) return nullptr; param.exec(args[0]->collation.collation, to); if ((null_value= param.is_null())) return nullptr; return to; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= "strnxfrm"_LEX_CSTRING; return name; } Item *shallow_copy(THD *thd) const override { return get_item_copy(thd, this); } class Create_func : public Create_native_func { public: using Create_native_func::Create_native_func; Item *create_native(THD *thd, const LEX_CSTRING *name, List *item_list) override { uint arg_count= item_list ? item_list->elements : 0; if (arg_count != 4) { my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str); return nullptr; } return new (thd->mem_root) Self(thd, *item_list); } }; static Plugin_function *plugin_descriptor() { static Create_func creator; static Plugin_function descriptor(&creator); return &descriptor; } }; /* The UCA version formatted as "[version X.Y.Z]". The version is stored in CHARSET_INFO::uca->version as a number, e.g. 400 for 4.0.0, 520 for 5.2.0, 1400 for 14.0.0. The major version is at most 255, the minor and patch versions are one digit. Every number is appended with CharBuffer::append_uint8(), which needs 3 free bytes, hence the buffer size. */ class UCAVersion: public CharBuffer<24> { public: UCAVersion(uint version) { append("[version "_LEX_CSTRING); append_uint8((uint8) (version / 100)); append_char('.'); append_uint8((uint8) ((version / 10) % 10)); append_char('.'); append_uint8((uint8) (version % 10)); append_char(']'); } }; class Item_func_collation_tailoring: public Item_str_func { using Self= Item_func_collation_tailoring; public: /* A helper subclass to get my_repertoire_t from an Item either in numeric or in string (named) format. */ class Repertoire: public Longlong_null { // Returns NULL if the name is unknown static Longlong_null repertoire_by_name(const LEX_CSTRING &name) { static const struct { Lex_ident_charset name; my_repertoire_t value; } names[]= { {"NONE"_Lex_ident_charset, MY_REPERTOIRE_NONE}, {"ASCII_DIGITS"_Lex_ident_charset, MY_REPERTOIRE_ASCII_DIGITS}, {"ASCII_MINUS_DOT_DIGITS"_Lex_ident_charset, MY_REPERTOIRE_ASCII_MINUS_DOT_DIGITS}, {"ASCII_ALNUM"_Lex_ident_charset, MY_REPERTOIRE_ASCII_ALNUM}, {"ASCII_IDENT"_Lex_ident_charset, MY_REPERTOIRE_ASCII_IDENT}, {"ASCII"_Lex_ident_charset, MY_REPERTOIRE_ASCII} }; for (const auto &n : names) { if (n.name.streq(name)) return Longlong_null(n.value); } return Longlong_null(); } public: Repertoire(const Longlong_null &rhs) :Longlong_null(rhs) { } Repertoire(Item *item) :Longlong_null() { if (item->cmp_type() != STRING_RESULT) { *this= item->to_longlong_null(); return; } String tmp; String *repertoire= item->val_str_ascii(&tmp); if (!repertoire) return; *this= repertoire_by_name(repertoire->to_lex_cstring()); } }; using Item_str_func::Item_str_func; bool fix_length_and_dec(THD *thd) override { collation.set(&my_charset_utf8mb4_bin); max_length= MAX_BLOB_WIDTH; return false; } String *val_str(String *to) override { String *clname= args[0]->val_str_ascii(to); Repertoire repertoire(args[1]); if ((null_value= (!clname || args[1]->null_value))) return nullptr; /* An unknown repertoire name or a number with bits outside of the known repertoires is a mistake in a test. Return NULL with a warning, so it is not mixed up with "no tailoring". */ if (repertoire.is_null() || ((ulonglong) repertoire.value() & ~(ulonglong) MY_REPERTOIRE_UNICODE30)) { my_error(ER_WRONG_ARGUMENTS, MYF(ME_WARNING), func_name_cstring().str); null_value= true; return nullptr; } CHARSET_INFO *cl= Charset_loader_mysys(). get_exact_collation(ErrConvString(clname).ptr(), MYF(0)); if (!cl) { my_error(ER_UNKNOWN_COLLATION, MYF(ME_WARNING), ErrConvString(clname).ptr()); null_value= true; return nullptr; } const my_repertoire_t rep= static_cast(repertoire.value()); LEX_CSTRING tr; if ((null_value= !((tr= (cl->coll->tailoring)(cl, rep)).str))) return nullptr; /* Tailorings do not depend on PAD/NOPAD, and on the UCA version. The caller (DTCollation::aggregate_by_tailoring()) checks them separately. Here they are shown only to display the whole picture, the same way as they are checked there: [nopad] for NOPAD collations, and [version X.Y.Z] for UCA collations on a repertoire with punctuation. */ const bool show_uca_version= cl->uca && !my_repertoire_is_subset_of(rep, MY_REPERTOIRE_ASCII_IDENT); if ((cl->state & MY_CS_NOPAD) || show_uca_version) { to->length(0); to->set_charset(collation.collation); if ((cl->state & MY_CS_NOPAD) && to->append(STRING_WITH_LEN("[nopad]"))) return nullptr; if (show_uca_version && to->append(UCAVersion(cl->uca->version).to_lex_cstring())) return nullptr; if (to->append(tr.str, tr.length)) return nullptr; return to; } to->set(tr.str, tr.length, collation.collation); return to; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= "collation_tailoring"_LEX_CSTRING; return name; } Item *shallow_copy(THD *thd) const override { return get_item_copy(thd, this); } class Create_func : public Create_native_func { public: using Create_native_func::Create_native_func; Item *create_native(THD *thd, const LEX_CSTRING *name, List *item_list) override { uint arg_count= item_list ? item_list->elements : 0; if (arg_count != 2) { my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str); return nullptr; } return new (thd->mem_root) Self(thd, *item_list); } }; static Plugin_function *plugin_descriptor() { static Create_func creator; static Plugin_function descriptor(&creator); return &descriptor; } }; /*************************************************************************/ maria_declare_plugin(type_test) { MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h) &plugin_descriptor_function_sysconst_test, // pointer to type-specific plugin descriptor "sysconst_test", // plugin name "MariaDB Corporation", // plugin author "Function SYSCONST_TEST()", // the plugin description PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h) 0, // Pointer to plugin initialization function 0, // Pointer to plugin deinitialization function 0x0100, // Numeric version 0xAABB means AA.BB version NULL, // Status variables NULL, // System variables "1.0", // String version representation MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity(see include/mysql/plugin.h)*/ }, { MariaDB_FUNCTION_PLUGIN, // the plugin type Item_func_strnxfrm::plugin_descriptor(), "strnxfrm", // plugin name "MariaDB Corporation", // plugin author "Function STRNXFRM()", // the plugin description PLUGIN_LICENSE_GPL, // the plugin license 0, // Pointer to plugin initialization function 0, // Pointer to plugin deinitialization function 0x0100, // Numeric version 0xAABB means AA.BB version NULL, // Status variables NULL, // System variables "1.0", // String version representation MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity }, { MariaDB_FUNCTION_PLUGIN, // the plugin type Item_func_strnxfrm_source_length_used::plugin_descriptor(), "strnxfrm_source_length_used",// plugin name "MariaDB Corporation", // plugin author "Function STRNXFRM_SOURCE_LENGTH_USED()", // the plugin description PLUGIN_LICENSE_GPL, // the plugin license 0, // Pointer to plugin initialization function 0, // Pointer to plugin deinitialization function 0x0100, // Numeric version 0xAABB means AA.BB version NULL, // Status variables NULL, // System variables "1.0", // String version representation MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity }, { MariaDB_FUNCTION_PLUGIN, // the plugin type Item_func_strnxfrm_warnings::plugin_descriptor(), "strnxfrm_warnings",// plugin name "MariaDB Corporation", // plugin author "Function STRNXFRM_WARNINGS()", // the plugin description PLUGIN_LICENSE_GPL, // the plugin license 0, // Pointer to plugin initialization function 0, // Pointer to plugin deinitialization function 0x0100, // Numeric version 0xAABB means AA.BB version NULL, // Status variables NULL, // System variables "1.0", // String version representation MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity }, { MariaDB_FUNCTION_PLUGIN, // the plugin type Item_func_collation_tailoring::plugin_descriptor(), "collation_tailoring", // plugin name "MariaDB Corporation", // plugin author "Function COLLATION_TAILORING()", // the plugin description PLUGIN_LICENSE_GPL, // the plugin license 0, // Pointer to plugin initialization function 0, // Pointer to plugin deinitialization function 0x0100, // Numeric version 0xAABB means AA.BB version NULL, // Status variables NULL, // System variables "1.0", // String version representation MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity } maria_declare_plugin_end;