181 lines
7.5 KiB
C++
181 lines
7.5 KiB
C++
/* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
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, version 2.0, 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 */
|
|
|
|
#include "sql/dd/impl/tables/character_sets.h"
|
|
|
|
#include <stddef.h>
|
|
#include <new>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
#include "m_ctype.h"
|
|
#include "my_dbug.h"
|
|
#include "my_sys.h"
|
|
#include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_...
|
|
#include "sql/dd/dd.h" // dd::create_object
|
|
#include "sql/dd/impl/cache/storage_adapter.h" // Storage_adapter
|
|
#include "sql/dd/impl/raw/object_keys.h" // Global_name_key
|
|
#include "sql/dd/impl/raw/raw_record.h"
|
|
#include "sql/dd/impl/tables/dd_properties.h" // TARGET_DD_VERSION
|
|
#include "sql/dd/impl/types/charset_impl.h" // dd::Charset_impl
|
|
#include "sql/dd/impl/types/object_table_definition_impl.h"
|
|
#include "sql/dd/object_id.h"
|
|
#include "sql/dd/types/charset.h"
|
|
#include "sql/item_create.h"
|
|
#include "sql/sql_class.h" // THD
|
|
|
|
namespace dd {
|
|
namespace tables {
|
|
|
|
const Character_sets &Character_sets::instance() {
|
|
static Character_sets *s_instance = new Character_sets();
|
|
return *s_instance;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
const CHARSET_INFO *Character_sets::name_collation() {
|
|
return &my_charset_utf8_general_ci;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
Character_sets::Character_sets() {
|
|
m_target_def.set_table_name("character_sets");
|
|
|
|
m_target_def.add_field(FIELD_ID, "FIELD_ID",
|
|
"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT");
|
|
m_target_def.add_field(FIELD_NAME, "FIELD_NAME",
|
|
"name VARCHAR(64) NOT NULL COLLATE " +
|
|
String_type(name_collation()->name));
|
|
m_target_def.add_field(FIELD_DEFAULT_COLLATION_ID,
|
|
"FIELD_DEFAULT_COLLATION_ID",
|
|
"default_collation_id BIGINT UNSIGNED NOT NULL");
|
|
m_target_def.add_field(FIELD_COMMENT, "FIELD_COMMENT",
|
|
"comment VARCHAR(2048)"
|
|
" COLLATE utf8_general_ci NOT NULL");
|
|
m_target_def.add_field(FIELD_MB_MAX_LENGTH, "FIELD_MB_MAX_LENGTH",
|
|
"mb_max_length INT UNSIGNED NOT NULL");
|
|
m_target_def.add_field(FIELD_OPTIONS, "FIELD_OPTIONS", "options MEDIUMTEXT");
|
|
|
|
m_target_def.add_index(INDEX_PK_ID, "INDEX_PK_ID", "PRIMARY KEY(id)");
|
|
m_target_def.add_index(INDEX_UK_NAME, "INDEX_UK_NAME", "UNIQUE KEY(name)");
|
|
m_target_def.add_index(INDEX_UK_DEFAULT_COLLATION_ID,
|
|
"INDEX_UK_DEFAULT_COLLATION_ID",
|
|
"UNIQUE KEY(default_collation_id)");
|
|
|
|
m_target_def.add_foreign_key(FK_DEFAULT_COLLATION_ID,
|
|
"FK_DEFAULT_COLLATION_ID",
|
|
"FOREIGN KEY (default_collation_id) "
|
|
"REFERENCES collations(id)");
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// The table is populated when the server is started, unless it is
|
|
// started in read only mode.
|
|
|
|
bool Character_sets::populate(THD *thd) const {
|
|
// Obtain a list of the previously stored charsets.
|
|
cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
|
|
std::vector<const Charset *> prev_cset;
|
|
if (thd->dd_client()->fetch_global_components(&prev_cset)) return true;
|
|
|
|
std::set<Object_id> prev_cset_ids;
|
|
for (const Charset *cset : prev_cset) prev_cset_ids.insert(cset->id());
|
|
|
|
// We have an outer loop identifying the primary collations, i.e.,
|
|
// the collations which are default for some character set. Then,
|
|
// the character set of each primary collation is stored in an entry
|
|
// in the dd.character_sets table. This means that if there are
|
|
// collations referring to a character set which has no default
|
|
// collation, we will not have an entry for this character set in
|
|
// the dd.character_sets table. This also means that a given character
|
|
// set can have only one primary collation, since character set identity
|
|
// is given by the character set name, and we have a unique key on the
|
|
// character set name in the dd.character_sets table. Populating the
|
|
// dd.collations table follows a similar pattern, but has an additional
|
|
// inner loop adding the actual collations referring to the character
|
|
// sets. Each character set is stored with the id (primary key) of its
|
|
// corresponding primary collation as the id (primary key).
|
|
|
|
Charset_impl *new_charset = create_object<Charset_impl>();
|
|
bool error = false;
|
|
for (int internal_charset_id = 0;
|
|
internal_charset_id < MY_ALL_CHARSETS_SIZE && !error;
|
|
internal_charset_id++) {
|
|
CHARSET_INFO *cs = all_charsets[internal_charset_id];
|
|
if (cs && (cs->state & MY_CS_PRIMARY) && (cs->state & MY_CS_AVAILABLE) &&
|
|
!(cs->state & MY_CS_HIDDEN)) {
|
|
// Remove the id from the set of non-updated old ids.
|
|
prev_cset_ids.erase(cs->number);
|
|
|
|
// The character set is stored on the same id as its primary collation
|
|
new_charset->set_id(cs->number);
|
|
new_charset->set_name(cs->csname);
|
|
new_charset->set_default_collation_id(cs->number);
|
|
new_charset->set_mb_max_length(cs->mbmaxlen);
|
|
new_charset->set_comment(cs->comment ? cs->comment : "");
|
|
|
|
// If the charset exists, it will be updated; otherwise,
|
|
// it will be inserted.
|
|
error = cache::Storage_adapter::instance()->store(
|
|
thd, static_cast<Charset *>(new_charset));
|
|
}
|
|
}
|
|
delete new_charset;
|
|
|
|
// The remaining ids in the prev_cset_ids set were not updated, and must
|
|
// therefore be deleted from the DD since they are not supported anymore.
|
|
for (std::set<Object_id>::const_iterator del_it = prev_cset_ids.begin();
|
|
del_it != prev_cset_ids.end(); ++del_it) {
|
|
const Charset *del_cset = NULL;
|
|
if (thd->dd_client()->acquire(*del_it, &del_cset)) return true;
|
|
|
|
DBUG_ASSERT(del_cset);
|
|
if (thd->dd_client()->drop(del_cset)) return true;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/* purecov: begin deadcode */
|
|
Charset *Character_sets::create_entity_object(const Raw_record &) const {
|
|
return new (std::nothrow) Charset_impl();
|
|
}
|
|
/* purecov: end */
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
bool Character_sets::update_object_key(Global_name_key *key,
|
|
const String_type &charset_name) {
|
|
key->update(FIELD_NAME, charset_name, name_collation());
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
} // namespace tables
|
|
} // namespace dd
|